From 9130b42a85998238b7bbe25ed2989e0605f636f0 Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Sat, 10 Mar 2012 23:02:54 +0000 Subject: [PATCH] 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 --- include/llvm/ADT/StringRef.h | 39 +++++++++-- lib/Support/StringRef.cpp | 36 ++-------- unittests/ADT/StringRefTest.cpp | 118 ++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 36 deletions(-) diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index a2bb7fe5fb9..76ba66e746c 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -10,16 +10,26 @@ #ifndef LLVM_ADT_STRINGREF_H #define LLVM_ADT_STRINGREF_H +#include "llvm/Support/type_traits.h" + #include #include -#include +#include #include +#include namespace llvm { template class SmallVectorImpl; class APInt; class hash_code; + class StringRef; + + /// Helper functions for StringRef::getAsInteger. + bool getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result); + + bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result); /// StringRef - Represent a constant reference to a string, i.e. a character /// array and a length, which need not be null terminated. @@ -305,14 +315,29 @@ namespace llvm { /// /// If the string is invalid or if only a subset of the string is valid, /// this returns true to signify the error. The string is considered - /// erroneous if empty. + /// erroneous if empty or if it overflows T. /// - bool getAsInteger(unsigned Radix, long long &Result) const; - bool getAsInteger(unsigned Radix, unsigned long long &Result) const; - bool getAsInteger(unsigned Radix, int &Result) const; - bool getAsInteger(unsigned Radix, unsigned &Result) const; + template + typename enable_if_c::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + long long LLVal; + if (getAsSignedInteger(*this, Radix, LLVal) || + static_cast(LLVal) != LLVal) + return true; + Result = LLVal; + return false; + } - // TODO: Provide overloads for int/unsigned that check for overflow. + template + typename enable_if_c::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + unsigned long long ULLVal; + if (getAsUnsignedInteger(*this, Radix, ULLVal) || + static_cast(ULLVal) != ULLVal) + return true; + Result = ULLVal; + return false; + } /// getAsInteger - Parse the current string as an integer of the /// specified radix, or of an autosensed radix if the radix given diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index 1c28bf879e0..abe570f6df4 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -285,8 +285,8 @@ static unsigned GetAutoSenseRadix(StringRef &Str) { /// GetAsUnsignedInteger - Workhorse method that converts a integer character /// sequence of radix up to 36 to an unsigned long long value. -static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, - unsigned long long &Result) { +bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result) { // Autosense radix if not specified. if (Radix == 0) Radix = GetAutoSenseRadix(Str); @@ -326,17 +326,13 @@ static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, return false; } -bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const { - return GetAsUnsignedInteger(*this, Radix, Result); -} - - -bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { +bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix, + long long &Result) { unsigned long long ULLVal; // Handle positive strings first. - if (empty() || front() != '-') { - if (GetAsUnsignedInteger(*this, Radix, ULLVal) || + if (Str.empty() || Str.front() != '-') { + if (getAsUnsignedInteger(Str, Radix, ULLVal) || // Check for value so large it overflows a signed value. (long long)ULLVal < 0) return true; @@ -345,7 +341,7 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { } // Get the positive part of the value. - if (GetAsUnsignedInteger(substr(1), Radix, ULLVal) || + if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) || // Reject values so large they'd overflow as negative signed, but allow // "-0". This negates the unsigned so that the negative isn't undefined // on signed overflow. @@ -356,24 +352,6 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { return false; } -bool StringRef::getAsInteger(unsigned Radix, int &Result) const { - long long Val; - if (getAsInteger(Radix, Val) || - (int)Val != Val) - return true; - Result = Val; - return false; -} - -bool StringRef::getAsInteger(unsigned Radix, unsigned &Result) const { - unsigned long long Val; - if (getAsInteger(Radix, Val) || - (unsigned)Val != Val) - return true; - Result = Val; - return false; -} - bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { StringRef Str = *this; diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp index b2f6fdcce03..ac6582936a7 100644 --- a/unittests/ADT/StringRefTest.cpp +++ b/unittests/ADT/StringRefTest.cpp @@ -310,4 +310,122 @@ TEST(StringRefTest, Hashing) { hash_value(StringRef("hello world").slice(1, -1))); } +struct UnsignedPair { + const char *Str; + uint64_t Expected; +} Unsigned[] = + { {"0", 0} + , {"255", 255} + , {"256", 256} + , {"65535", 65535} + , {"65536", 65536} + , {"4294967295", 4294967295} + , {"4294967296", 4294967296} + , {"18446744073709551615", 18446744073709551615ULL} + , {"042", 34} + , {"0x42", 66} + , {"0b101010", 42} + }; + +struct SignedPair { + const char *Str; + int64_t Expected; +} Signed[] = + { {"0", 0} + , {"-0", 0} + , {"127", 127} + , {"128", 128} + , {"-128", -128} + , {"-129", -129} + , {"32767", 32767} + , {"32768", 32768} + , {"-32768", -32768} + , {"-32769", -32769} + , {"2147483647", 2147483647} + , {"2147483648", 2147483648} + , {"-2147483648", -2147483648LL} + , {"-2147483649", -2147483649LL} + , {"-9223372036854775808", -(9223372036854775807LL) - 1} + , {"042", 34} + , {"0x42", 66} + , {"0b101010", 42} + , {"-042", -34} + , {"-0x42", -66} + , {"-0b101010", -42} + }; + +TEST(StringRefTest, getAsInteger) { + uint8_t U8; + uint16_t U16; + uint32_t U32; + uint64_t U64; + + for (size_t i = 0; i < array_lengthof(Unsigned); ++i) { + bool U8Success = StringRef(Unsigned[i].Str).getAsInteger(0, U8); + if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) { + ASSERT_FALSE(U8Success); + EXPECT_EQ(U8, Unsigned[i].Expected); + } else { + ASSERT_TRUE(U8Success); + } + bool U16Success = StringRef(Unsigned[i].Str).getAsInteger(0, U16); + if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) { + ASSERT_FALSE(U16Success); + EXPECT_EQ(U16, Unsigned[i].Expected); + } else { + ASSERT_TRUE(U16Success); + } + bool U32Success = StringRef(Unsigned[i].Str).getAsInteger(0, U32); + if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) { + ASSERT_FALSE(U32Success); + EXPECT_EQ(U32, Unsigned[i].Expected); + } else { + ASSERT_TRUE(U32Success); + } + bool U64Success = StringRef(Unsigned[i].Str).getAsInteger(0, U64); + if (static_cast(Unsigned[i].Expected) == Unsigned[i].Expected) { + ASSERT_FALSE(U64Success); + EXPECT_EQ(U64, Unsigned[i].Expected); + } else { + ASSERT_TRUE(U64Success); + } + } + + int8_t S8; + int16_t S16; + int32_t S32; + int64_t S64; + + for (size_t i = 0; i < array_lengthof(Signed); ++i) { + bool S8Success = StringRef(Signed[i].Str).getAsInteger(0, S8); + if (static_cast(Signed[i].Expected) == Signed[i].Expected) { + ASSERT_FALSE(S8Success); + EXPECT_EQ(S8, Signed[i].Expected); + } else { + ASSERT_TRUE(S8Success); + } + bool S16Success = StringRef(Signed[i].Str).getAsInteger(0, S16); + if (static_cast(Signed[i].Expected) == Signed[i].Expected) { + ASSERT_FALSE(S16Success); + EXPECT_EQ(S16, Signed[i].Expected); + } else { + ASSERT_TRUE(S16Success); + } + bool S32Success = StringRef(Signed[i].Str).getAsInteger(0, S32); + if (static_cast(Signed[i].Expected) == Signed[i].Expected) { + ASSERT_FALSE(S32Success); + EXPECT_EQ(S32, Signed[i].Expected); + } else { + ASSERT_TRUE(S32Success); + } + bool S64Success = StringRef(Signed[i].Str).getAsInteger(0, S64); + if (static_cast(Signed[i].Expected) == Signed[i].Expected) { + ASSERT_FALSE(S64Success); + EXPECT_EQ(S64, Signed[i].Expected); + } else { + ASSERT_TRUE(S64Success); + } + } +} + } // end anonymous namespace