diff options
Diffstat (limited to 'absl/strings/numbers.h')
-rw-r--r-- | absl/strings/numbers.h | 163 |
1 files changed, 12 insertions, 151 deletions
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index ad4e66b6..739dbb28 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -32,7 +32,6 @@ #endif #include <cstddef> -#include <cstdint> #include <cstdlib> #include <cstring> #include <ctime> @@ -40,12 +39,10 @@ #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" @@ -161,96 +158,6 @@ bool safe_strtou128_base(absl::string_view text, 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&) { - // The integer is unsigned, so return a compile-time constant. - // This can help the optimizer avoid having to prove bool to be false later. - 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) { - // The value is unsigned; just return the original. - 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); -} - -// Returns the number of base-10 digits in the given number. -// Note that this strictly counts digits. It does not count the sign. -// The `initial_digits` parameter is the starting point, which is normally equal -// to 1 because the number of digits in 0 is 1 (a special case). -// However, callers may e.g. wish to change it to 2 to account for the sign. -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; - // If code size becomes an issue, the 'if' stage can be removed for a minor - // performance loss. - 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) { - // Branchlessly add 1 to account for a minus sign. - r += static_cast<uint32_t>(IsNegative(v)); - return Base10Digits(UnsignedAbsoluteValue(v), r); -} - -// These functions return the number of base-10 digits, but multiplied by -1 if -// the input itself is negative. This is handy and efficient for later usage, -// since the bitwise complement of the result becomes equal to the number of -// characters required. -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); // NOLINT -ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( - unsigned short v); // NOLINT -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); // NOLINT -ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( - unsigned long v); // NOLINT -ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( - long long v); // NOLINT -ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( - unsigned long long v); // NOLINT - // Helper function for fast formatting of floating-point values. // The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six // significant digits are returned, trailing zeros are removed, and numbers @@ -259,18 +166,24 @@ ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative( // Required buffer size is `kSixDigitsToBufferSize`. size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer); -// All of these functions take an output buffer +// WARNING: These functions may write more characters than necessary, because +// they are intended for speed. All functions take an output buffer // as an argument and return a pointer to the last byte they wrote, which is the // terminating '\0'. At most `kFastToBufferSize` bytes are written. -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); +absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(uint32_t n, absl::Nonnull<char*> out_str) + ABSL_INTERNAL_NEED_MIN_SIZE(out_str, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); // For enums and integer types that are not an exact match for the types above, // use templates to call the appropriate one of the four overloads above. template <typename int_type> -absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) { +absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) { static_assert(sizeof(i) <= 64 / 8, "FastIntToBuffer works only with 64-bit-or-less integers."); // TODO(jorg): This signed-ness check is used because it works correctly @@ -294,58 +207,6 @@ absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) { } } -// These functions do NOT add any null-terminator. -// They return a pointer to the beginning of the written string. -// The digit counts provided must *exactly* match the number of base-10 digits -// in the number, or the behavior is undefined. -// (i.e. do NOT count the minus sign, or over- or under-count the digits.) -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); - -// For enums and integer types that are not an exact match for the types above, -// use templates to call the appropriate one of the four overloads above. -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."); - // This signed-ness check is used because it works correctly - // with enums, and it also serves to check that int_type is not a pointer. - // If one day something like std::is_signed<enum E> works, switch to it. - // These conditions are constexpr bools to suppress MSVC warning C4127. - 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); - } - } -} - // Implementation of SimpleAtoi, generalized to support arbitrary base (used // with base different from 10 elsewhere in Abseil implementation). template <typename int_type> |