| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef ABSL_STRINGS_NUMBERS_H_ |
| #define ABSL_STRINGS_NUMBERS_H_ |
|
|
| #ifdef __SSSE3__ |
| #include <tmmintrin.h> |
| #endif |
|
|
| #ifdef _MSC_VER |
| #include <intrin.h> |
| #endif |
|
|
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <cstring> |
| #include <ctime> |
| #include <limits> |
| #include <string> |
| #include <type_traits> |
|
|
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" |
| #include "absl/numeric/bits.h" |
| #include "absl/numeric/int128.h" |
| #include "absl/strings/string_view.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename int_type> |
| ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, |
| absl::Nonnull<int_type*> out); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, |
| absl::Nonnull<float*> out); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, |
| absl::Nonnull<double*> out); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, |
| absl::Nonnull<bool*> out); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename int_type> |
| ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, |
| absl::Nonnull<int_type*> out); |
|
|
| |
| ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( |
| absl::string_view str, absl::Nonnull<absl::int128*> out); |
| ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( |
| absl::string_view str, absl::Nonnull<absl::uint128*> out); |
|
|
| ABSL_NAMESPACE_END |
| } |
|
|
| |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace numbers_internal { |
|
|
| |
| ABSL_DLL extern const char kHexChar[17]; |
| ABSL_DLL extern const char |
| kHexTable[513]; |
|
|
| |
| |
| |
| |
| |
| |
| void PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf); |
|
|
| |
|
|
| bool safe_strto32_base(absl::string_view text, absl::Nonnull<int32_t*> value, |
| int base); |
| bool safe_strto64_base(absl::string_view text, absl::Nonnull<int64_t*> value, |
| int base); |
| bool safe_strto128_base(absl::string_view text, |
| absl::Nonnull<absl::int128*> value, int base); |
| bool safe_strtou32_base(absl::string_view text, absl::Nonnull<uint32_t*> value, |
| int base); |
| bool safe_strtou64_base(absl::string_view text, absl::Nonnull<uint64_t*> value, |
| int base); |
| bool safe_strtou128_base(absl::string_view text, |
| absl::Nonnull<absl::uint128*> value, int base); |
|
|
| static const int kFastToBufferSize = 32; |
| static const int kSixDigitsToBufferSize = 16; |
|
|
| template <class T> |
| std::enable_if_t<!std::is_unsigned<T>::value, bool> IsNegative(const T& v) { |
| return v < T(); |
| } |
|
|
| template <class T> |
| std::enable_if_t<std::is_unsigned<T>::value, std::false_type> IsNegative( |
| const T&) { |
| |
| |
| return std::false_type(); |
| } |
|
|
| template <class T> |
| std::enable_if_t<std::is_unsigned<std::decay_t<T>>::value, T&&> |
| UnsignedAbsoluteValue(T&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) { |
| |
| return std::forward<T>(v); |
| } |
|
|
| template <class T> |
| ABSL_ATTRIBUTE_CONST_FUNCTION |
| std::enable_if_t<!std::is_unsigned<T>::value, std::make_unsigned_t<T>> |
| UnsignedAbsoluteValue(T v) { |
| using U = std::make_unsigned_t<T>; |
| return IsNegative(v) ? U() - static_cast<U>(v) : static_cast<U>(v); |
| } |
|
|
| |
| |
| |
| |
| |
| template <typename T> |
| std::enable_if_t<std::is_unsigned<T>::value, uint32_t> Base10Digits( |
| T v, const uint32_t initial_digits = 1) { |
| uint32_t r = initial_digits; |
| |
| |
| for (;;) { |
| if (ABSL_PREDICT_TRUE(v < 10 * 10)) { |
| r += (v >= 10); |
| break; |
| } |
| if (ABSL_PREDICT_TRUE(v < 1000 * 10)) { |
| r += (v >= 1000) + 2; |
| break; |
| } |
| if (ABSL_PREDICT_TRUE(v < 100000 * 10)) { |
| r += (v >= 100000) + 4; |
| break; |
| } |
| r += 6; |
| v = static_cast<T>(v / 1000000); |
| } |
| return r; |
| } |
|
|
| template <typename T> |
| std::enable_if_t<std::is_signed<T>::value, uint32_t> Base10Digits( |
| T v, uint32_t r = 1) { |
| |
| r += static_cast<uint32_t>(IsNegative(v)); |
| return Base10Digits(UnsignedAbsoluteValue(v), r); |
| } |
|
|
| |
| |
| |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| signed char v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| unsigned char v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| short v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| unsigned short v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(int v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| unsigned int v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| long v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| unsigned long v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| long long v); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( |
| unsigned long long v); |
|
|
| |
| |
| |
| |
| |
| |
| size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer); |
|
|
| |
| |
| |
| absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer); |
| absl::Nonnull<char*> FastIntToBuffer(uint32_t i, absl::Nonnull<char*> buffer); |
| absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer); |
| absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer); |
|
|
| |
| |
| template <typename int_type> |
| absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) { |
| static_assert(sizeof(i) <= 64 / 8, |
| "FastIntToBuffer works only with 64-bit-or-less integers."); |
| |
| |
| |
| |
| constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0; |
| constexpr bool kUse64Bit = sizeof(i) > 32 / 8; |
| if (kIsSigned) { |
| if (kUse64Bit) { |
| return FastIntToBuffer(static_cast<int64_t>(i), buffer); |
| } else { |
| return FastIntToBuffer(static_cast<int32_t>(i), buffer); |
| } |
| } else { |
| if (kUse64Bit) { |
| return FastIntToBuffer(static_cast<uint64_t>(i), buffer); |
| } else { |
| return FastIntToBuffer(static_cast<uint32_t>(i), buffer); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| absl::Nonnull<char*> FastIntToBufferBackward(int32_t i, |
| absl::Nonnull<char*> buffer_end, |
| uint32_t exact_digit_count); |
| absl::Nonnull<char*> FastIntToBufferBackward(uint32_t i, |
| absl::Nonnull<char*> buffer_end, |
| uint32_t exact_digit_count); |
| absl::Nonnull<char*> FastIntToBufferBackward(int64_t i, |
| absl::Nonnull<char*> buffer_end, |
| uint32_t exact_digit_count); |
| absl::Nonnull<char*> FastIntToBufferBackward(uint64_t i, |
| absl::Nonnull<char*> buffer_end, |
| uint32_t exact_digit_count); |
|
|
| |
| |
| template <typename int_type> |
| absl::Nonnull<char*> FastIntToBufferBackward(int_type i, |
| absl::Nonnull<char*> buffer_end, |
| uint32_t exact_digit_count) { |
| static_assert( |
| sizeof(i) <= 64 / 8, |
| "FastIntToBufferBackward works only with 64-bit-or-less integers."); |
| |
| |
| |
| |
| constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0; |
| constexpr bool kUse64Bit = sizeof(i) > 32 / 8; |
| if (kIsSigned) { |
| if (kUse64Bit) { |
| return FastIntToBufferBackward(static_cast<int64_t>(i), buffer_end, |
| exact_digit_count); |
| } else { |
| return FastIntToBufferBackward(static_cast<int32_t>(i), buffer_end, |
| exact_digit_count); |
| } |
| } else { |
| if (kUse64Bit) { |
| return FastIntToBufferBackward(static_cast<uint64_t>(i), buffer_end, |
| exact_digit_count); |
| } else { |
| return FastIntToBufferBackward(static_cast<uint32_t>(i), buffer_end, |
| exact_digit_count); |
| } |
| } |
| } |
|
|
| |
| |
| template <typename int_type> |
| ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, |
| absl::Nonnull<int_type*> out, |
| int base) { |
| static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, |
| "SimpleAtoi works only with 32-bit or 64-bit integers."); |
| static_assert(!std::is_floating_point<int_type>::value, |
| "Use SimpleAtof or SimpleAtod instead."); |
| bool parsed; |
| |
| |
| |
| |
| constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0; |
| constexpr bool kUse64Bit = sizeof(*out) == 64 / 8; |
| if (kIsSigned) { |
| if (kUse64Bit) { |
| int64_t val; |
| parsed = numbers_internal::safe_strto64_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else { |
| int32_t val; |
| parsed = numbers_internal::safe_strto32_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } |
| } else { |
| if (kUse64Bit) { |
| uint64_t val; |
| parsed = numbers_internal::safe_strtou64_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else { |
| uint32_t val; |
| parsed = numbers_internal::safe_strtou32_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } |
| } |
| return parsed; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| inline size_t FastHexToBufferZeroPad16(uint64_t val, absl::Nonnull<char*> out) { |
| #ifdef ABSL_INTERNAL_HAVE_SSSE3 |
| uint64_t be = absl::big_endian::FromHost64(val); |
| const auto kNibbleMask = _mm_set1_epi8(0xf); |
| const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); |
| auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); |
| auto v4 = _mm_srli_epi64(v, 4); |
| auto il = _mm_unpacklo_epi8(v4, v); |
| auto m = _mm_and_si128(il, kNibbleMask); |
| auto hexchars = _mm_shuffle_epi8(kHexDigits, m); |
| _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars); |
| #else |
| for (int i = 0; i < 8; ++i) { |
| auto byte = (val >> (56 - 8 * i)) & 0xFF; |
| auto* hex = &absl::numbers_internal::kHexTable[byte * 2]; |
| std::memcpy(out + 2 * i, hex, 2); |
| } |
| #endif |
| |
| return 16 - static_cast<size_t>(countl_zero(val | 0x1) / 4); |
| } |
|
|
| } |
|
|
| template <typename int_type> |
| ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, |
| absl::Nonnull<int_type*> out) { |
| return numbers_internal::safe_strtoi_base(str, out, 10); |
| } |
|
|
| ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, |
| absl::Nonnull<absl::int128*> out) { |
| return numbers_internal::safe_strto128_base(str, out, 10); |
| } |
|
|
| ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, |
| absl::Nonnull<absl::uint128*> out) { |
| return numbers_internal::safe_strtou128_base(str, out, 10); |
| } |
|
|
| template <typename int_type> |
| ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, |
| absl::Nonnull<int_type*> out) { |
| return numbers_internal::safe_strtoi_base(str, out, 16); |
| } |
|
|
| ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( |
| absl::string_view str, absl::Nonnull<absl::int128*> out) { |
| return numbers_internal::safe_strto128_base(str, out, 16); |
| } |
|
|
| ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( |
| absl::string_view str, absl::Nonnull<absl::uint128*> out) { |
| return numbers_internal::safe_strtou128_base(str, out, 16); |
| } |
|
|
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|