mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-05 02:16:46 +00:00
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
This commit is contained in:
parent
4210b34e59
commit
9130b42a85
@ -10,16 +10,26 @@
|
|||||||
#ifndef LLVM_ADT_STRINGREF_H
|
#ifndef LLVM_ADT_STRINGREF_H
|
||||||
#define LLVM_ADT_STRINGREF_H
|
#define LLVM_ADT_STRINGREF_H
|
||||||
|
|
||||||
|
#include "llvm/Support/type_traits.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <utility>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SmallVectorImpl;
|
class SmallVectorImpl;
|
||||||
class APInt;
|
class APInt;
|
||||||
class hash_code;
|
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
|
/// StringRef - Represent a constant reference to a string, i.e. a character
|
||||||
/// array and a length, which need not be null terminated.
|
/// 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,
|
/// 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
|
/// 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;
|
template <typename T>
|
||||||
bool getAsInteger(unsigned Radix, unsigned long long &Result) const;
|
typename enable_if_c<std::numeric_limits<T>::is_signed, bool>::type
|
||||||
bool getAsInteger(unsigned Radix, int &Result) const;
|
getAsInteger(unsigned Radix, T &Result) const {
|
||||||
bool getAsInteger(unsigned Radix, unsigned &Result) const;
|
long long LLVal;
|
||||||
|
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
||||||
|
static_cast<T>(LLVal) != LLVal)
|
||||||
|
return true;
|
||||||
|
Result = LLVal;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Provide overloads for int/unsigned that check for overflow.
|
template <typename T>
|
||||||
|
typename enable_if_c<!std::numeric_limits<T>::is_signed, bool>::type
|
||||||
|
getAsInteger(unsigned Radix, T &Result) const {
|
||||||
|
unsigned long long ULLVal;
|
||||||
|
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
||||||
|
static_cast<T>(ULLVal) != ULLVal)
|
||||||
|
return true;
|
||||||
|
Result = ULLVal;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// getAsInteger - Parse the current string as an integer of the
|
/// getAsInteger - Parse the current string as an integer of the
|
||||||
/// specified radix, or of an autosensed radix if the radix given
|
/// specified radix, or of an autosensed radix if the radix given
|
||||||
|
@ -285,8 +285,8 @@ static unsigned GetAutoSenseRadix(StringRef &Str) {
|
|||||||
|
|
||||||
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
||||||
/// sequence of radix up to 36 to an unsigned long long value.
|
/// sequence of radix up to 36 to an unsigned long long value.
|
||||||
static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix,
|
bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||||
unsigned long long &Result) {
|
unsigned long long &Result) {
|
||||||
// Autosense radix if not specified.
|
// Autosense radix if not specified.
|
||||||
if (Radix == 0)
|
if (Radix == 0)
|
||||||
Radix = GetAutoSenseRadix(Str);
|
Radix = GetAutoSenseRadix(Str);
|
||||||
@ -326,17 +326,13 @@ static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const {
|
bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||||
return GetAsUnsignedInteger(*this, Radix, Result);
|
long long &Result) {
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool StringRef::getAsInteger(unsigned Radix, long long &Result) const {
|
|
||||||
unsigned long long ULLVal;
|
unsigned long long ULLVal;
|
||||||
|
|
||||||
// Handle positive strings first.
|
// Handle positive strings first.
|
||||||
if (empty() || front() != '-') {
|
if (Str.empty() || Str.front() != '-') {
|
||||||
if (GetAsUnsignedInteger(*this, Radix, ULLVal) ||
|
if (getAsUnsignedInteger(Str, Radix, ULLVal) ||
|
||||||
// Check for value so large it overflows a signed value.
|
// Check for value so large it overflows a signed value.
|
||||||
(long long)ULLVal < 0)
|
(long long)ULLVal < 0)
|
||||||
return true;
|
return true;
|
||||||
@ -345,7 +341,7 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the positive part of the value.
|
// 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
|
// Reject values so large they'd overflow as negative signed, but allow
|
||||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||||
// on signed overflow.
|
// on signed overflow.
|
||||||
@ -356,24 +352,6 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const {
|
|||||||
return false;
|
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 {
|
bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const {
|
||||||
StringRef Str = *this;
|
StringRef Str = *this;
|
||||||
|
|
||||||
|
@ -310,4 +310,122 @@ TEST(StringRefTest, Hashing) {
|
|||||||
hash_value(StringRef("hello world").slice(1, -1)));
|
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<uint8_t>(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<uint16_t>(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<uint32_t>(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<uint64_t>(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<int8_t>(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<int16_t>(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<int32_t>(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<int64_t>(Signed[i].Expected) == Signed[i].Expected) {
|
||||||
|
ASSERT_FALSE(S64Success);
|
||||||
|
EXPECT_EQ(S64, Signed[i].Expected);
|
||||||
|
} else {
|
||||||
|
ASSERT_TRUE(S64Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user