llvm.org GIT mirror llvm / 9130b42
Make StringRef::getAsInteger work with all integer types. Before this change it would fail with {,u}int64_t on x86-64 Linux. This also removes code duplication. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152517 91177308-0d34-0410-b5e6-96231b3b80d8 Michael J. Spencer 8 years ago
3 changed file(s) with 159 addition(s) and 38 deletion(s). Raw diff Collapse all Expand all
99 #ifndef LLVM_ADT_STRINGREF_H
1010 #define LLVM_ADT_STRINGREF_H
1111
12 #include "llvm/Support/type_traits.h"
13
1214 #include
1315 #include
16 #include
17 #include
1418 #include
15 #include
1619
1720 namespace llvm {
1821 template
1922 class SmallVectorImpl;
2023 class APInt;
2124 class hash_code;
25 class StringRef;
26
27 /// Helper functions for StringRef::getAsInteger.
28 bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
29 unsigned long long &Result);
30
31 bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
2232
2333 /// StringRef - Represent a constant reference to a string, i.e. a character
2434 /// array and a length, which need not be null terminated.
304314 ///
305315 /// If the string is invalid or if only a subset of the string is valid,
306316 /// this returns true to signify the error. The string is considered
307 /// erroneous if empty.
308 ///
309 bool getAsInteger(unsigned Radix, long long &Result) const;
310 bool getAsInteger(unsigned Radix, unsigned long long &Result) const;
311 bool getAsInteger(unsigned Radix, int &Result) const;
312 bool getAsInteger(unsigned Radix, unsigned &Result) const;
313
314 // TODO: Provide overloads for int/unsigned that check for overflow.
317 /// erroneous if empty or if it overflows T.
318 ///
319 template
320 typename enable_if_c::is_signed, bool>::type
321 getAsInteger(unsigned Radix, T &Result) const {
322 long long LLVal;
323 if (getAsSignedInteger(*this, Radix, LLVal) ||
324 static_cast(LLVal) != LLVal)
325 return true;
326 Result = LLVal;
327 return false;
328 }
329
330 template
331 typename enable_if_c::is_signed, bool>::type
332 getAsInteger(unsigned Radix, T &Result) const {
333 unsigned long long ULLVal;
334 if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
335 static_cast(ULLVal) != ULLVal)
336 return true;
337 Result = ULLVal;
338 return false;
339 }
315340
316341 /// getAsInteger - Parse the current string as an integer of the
317342 /// specified radix, or of an autosensed radix if the radix given
284284
285285 /// GetAsUnsignedInteger - Workhorse method that converts a integer character
286286 /// sequence of radix up to 36 to an unsigned long long value.
287 static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix,
288 unsigned long long &Result) {
287 bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix,
288 unsigned long long &Result) {
289289 // Autosense radix if not specified.
290290 if (Radix == 0)
291291 Radix = GetAutoSenseRadix(Str);
325325 return false;
326326 }
327327
328 bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const {
329 return GetAsUnsignedInteger(*this, Radix, Result);
330 }
331
332
333 bool StringRef::getAsInteger(unsigned Radix, long long &Result) const {
328 bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix,
329 long long &Result) {
334330 unsigned long long ULLVal;
335331
336332 // Handle positive strings first.
337 if (empty() || front() != '-') {
338 if (GetAsUnsignedInteger(*this, Radix, ULLVal) ||
333 if (Str.empty() || Str.front() != '-') {
334 if (getAsUnsignedInteger(Str, Radix, ULLVal) ||
339335 // Check for value so large it overflows a signed value.
340336 (long long)ULLVal < 0)
341337 return true;
344340 }
345341
346342 // Get the positive part of the value.
347 if (GetAsUnsignedInteger(substr(1), Radix, ULLVal) ||
343 if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) ||
348344 // Reject values so large they'd overflow as negative signed, but allow
349345 // "-0". This negates the unsigned so that the negative isn't undefined
350346 // on signed overflow.
352348 return true;
353349
354350 Result = -ULLVal;
355 return false;
356 }
357
358 bool StringRef::getAsInteger(unsigned Radix, int &Result) const {
359 long long Val;
360 if (getAsInteger(Radix, Val) ||
361 (int)Val != Val)
362 return true;
363 Result = Val;
364 return false;
365 }
366
367 bool StringRef::getAsInteger(unsigned Radix, unsigned &Result) const {
368 unsigned long long Val;
369 if (getAsInteger(Radix, Val) ||
370 (unsigned)Val != Val)
371 return true;
372 Result = Val;
373351 return false;
374352 }
375353
309309 hash_value(StringRef("hello world").slice(1, -1)));
310310 }
311311
312 struct UnsignedPair {
313 const char *Str;
314 uint64_t Expected;
315 } Unsigned[] =
316 { {"0", 0}
317 , {"255", 255}
318 , {"256", 256}
319 , {"65535", 65535}
320 , {"65536", 65536}
321 , {"4294967295", 4294967295}
322 , {"4294967296", 4294967296}
323 , {"18446744073709551615", 18446744073709551615ULL}
324 , {"042", 34}
325 , {"0x42", 66}
326 , {"0b101010", 42}
327 };
328
329 struct SignedPair {
330 const char *Str;
331 int64_t Expected;
332 } Signed[] =
333 { {"0", 0}
334 , {"-0", 0}
335 , {"127", 127}
336 , {"128", 128}
337 , {"-128", -128}
338 , {"-129", -129}
339 , {"32767", 32767}
340 , {"32768", 32768}
341 , {"-32768", -32768}
342 , {"-32769", -32769}
343 , {"2147483647", 2147483647}
344 , {"2147483648", 2147483648}
345 , {"-2147483648", -2147483648LL}
346 , {"-2147483649", -2147483649LL}
347 , {"-9223372036854775808", -(9223372036854775807LL) - 1}
348 , {"042", 34}
349 , {"0x42", 66}
350 , {"0b101010", 42}
351 , {"-042", -34}
352 , {"-0x42", -66}
353 , {"-0b101010", -42}
354 };
355
356 TEST(StringRefTest, getAsInteger) {
357 uint8_t U8;
358 uint16_t U16;
359 uint32_t U32;
360 uint64_t U64;
361
362 for (size_t i = 0; i < array_lengthof(Unsigned); ++i) {
363 bool U8Success = StringRef(Unsigned[i].Str).getAsInteger(0, U8);
364 if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) {
365 ASSERT_FALSE(U8Success);
366 EXPECT_EQ(U8, Unsigned[i].Expected);
367 } else {
368 ASSERT_TRUE(U8Success);
369 }
370 bool U16Success = StringRef(Unsigned[i].Str).getAsInteger(0, U16);
371 if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) {
372 ASSERT_FALSE(U16Success);
373 EXPECT_EQ(U16, Unsigned[i].Expected);
374 } else {
375 ASSERT_TRUE(U16Success);
376 }
377 bool U32Success = StringRef(Unsigned[i].Str).getAsInteger(0, U32);
378 if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) {
379 ASSERT_FALSE(U32Success);
380 EXPECT_EQ(U32, Unsigned[i].Expected);
381 } else {
382 ASSERT_TRUE(U32Success);
383 }
384 bool U64Success = StringRef(Unsigned[i].Str).getAsInteger(0, U64);
385 if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) {
386 ASSERT_FALSE(U64Success);
387 EXPECT_EQ(U64, Unsigned[i].Expected);
388 } else {
389 ASSERT_TRUE(U64Success);
390 }
391 }
392
393 int8_t S8;
394 int16_t S16;
395 int32_t S32;
396 int64_t S64;
397
398 for (size_t i = 0; i < array_lengthof(Signed); ++i) {
399 bool S8Success = StringRef(Signed[i].Str).getAsInteger(0, S8);
400 if (static_cast(Signed[i].Expected) == Signed[i].Expected) {
401 ASSERT_FALSE(S8Success);
402 EXPECT_EQ(S8, Signed[i].Expected);
403 } else {
404 ASSERT_TRUE(S8Success);
405 }
406 bool S16Success = StringRef(Signed[i].Str).getAsInteger(0, S16);
407 if (static_cast(Signed[i].Expected) == Signed[i].Expected) {
408 ASSERT_FALSE(S16Success);
409 EXPECT_EQ(S16, Signed[i].Expected);
410 } else {
411 ASSERT_TRUE(S16Success);
412 }
413 bool S32Success = StringRef(Signed[i].Str).getAsInteger(0, S32);
414 if (static_cast(Signed[i].Expected) == Signed[i].Expected) {
415 ASSERT_FALSE(S32Success);
416 EXPECT_EQ(S32, Signed[i].Expected);
417 } else {
418 ASSERT_TRUE(S32Success);
419 }
420 bool S64Success = StringRef(Signed[i].Str).getAsInteger(0, S64);
421 if (static_cast(Signed[i].Expected) == Signed[i].Expected) {
422 ASSERT_FALSE(S64Success);
423 EXPECT_EQ(S64, Signed[i].Expected);
424 } else {
425 ASSERT_TRUE(S64Success);
426 }
427 }
428 }
429
312430 } // end anonymous namespace