diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index 74d3eaaf34f..2015a66bd82 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -223,6 +223,23 @@ namespace llvm { return Count; } + /// @} + /// @name Helpful Algorithms + /// @{ + + /// getAsInteger - Parse the current string as an integer of the specified + /// radix. If Radix is specified as zero, this does radix autosensing using + /// extended C rules: 0 is octal, 0x is hex, 0b is binary. + /// + /// 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. + /// + //bool getAsInteger(unsigned Radix, long long &Result) const; + bool getAsInteger(unsigned Radix, unsigned long long &Result) const; + + // TODO: Provide overloads for int/unsigned that check for overflow. + /// @} /// @name Substring Operations /// @{ diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index 4751f06645c..2e7d3c0c6e8 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -11,3 +11,66 @@ using namespace llvm; const size_t StringRef::npos; + +static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result) { + // Autosense radix if not specified. + if (Radix == 0) { + if (Str[0] != '0') { + Radix = 10; + } else { + if (Str.size() < 2) { + Radix = 8; + } else { + if (Str[1] == 'x') { + Str = Str.substr(2); + Radix = 16; + } else if (Str[1] == 'b') { + Str = Str.substr(2); + Radix = 2; + } else { + Radix = 8; + } + } + } + } + + // Empty strings (after the radix autosense) are invalid. + if (Str.empty()) return true; + + // Parse all the bytes of the string given this radix. Watch for overflow. + Result = 0; + while (!Str.empty()) { + unsigned CharVal; + if (Str[0] >= '0' && Str[0] <= '9') + CharVal = Str[0]-'0'; + else if (Str[0] >= 'a' && Str[0] <= 'z') + CharVal = Str[0]-'a'+10; + else if (Str[0] >= 'A' && Str[0] <= 'Z') + CharVal = Str[0]-'A'+10; + else + return true; + + // If the parsed value is larger than the integer radix, the string is + // invalid. + if (CharVal >= Radix) + return true; + + // Add in this character. + unsigned long long PrevResult = Result; + Result = Result*Radix+CharVal; + + // Check for overflow. + if (Result < PrevResult) + return true; + + Str = Str.substr(1); + } + + return false; +} + +bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const { + return GetAsUnsignedInteger(*this, Radix, Result); +} +