summaryrefslogtreecommitdiff
path: root/absl/strings/numbers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/numbers.cc')
-rw-r--r--absl/strings/numbers.cc152
1 files changed, 105 insertions, 47 deletions
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index 2bac4adc..68c26dd6 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -19,8 +19,8 @@
#include <algorithm>
#include <cassert>
-#include <cfloat> // for DBL_DIG and FLT_DIG
-#include <cmath> // for HUGE_VAL
+#include <cfloat> // for DBL_DIG and FLT_DIG
+#include <cmath> // for HUGE_VAL
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -30,16 +30,18 @@
#include <memory>
#include <utility>
+#include "absl/base/attributes.h"
#include "absl/base/internal/bits.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/ascii.h"
#include "absl/strings/charconv.h"
+#include "absl/strings/escaping.h"
#include "absl/strings/internal/memutil.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
namespace absl {
-inline namespace lts_2019_08_08 {
+ABSL_NAMESPACE_BEGIN
bool SimpleAtof(absl::string_view str, float* out) {
*out = 0.0;
@@ -93,43 +95,6 @@ bool SimpleAtod(absl::string_view str, double* out) {
return true;
}
-namespace {
-
-// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
-// range 0 <= i < 100, and buf must have space for two characters. Example:
-// char buf[2];
-// PutTwoDigits(42, buf);
-// // buf[0] == '4'
-// // buf[1] == '2'
-inline void PutTwoDigits(size_t i, char* buf) {
- static const char two_ASCII_digits[100][2] = {
- {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'},
- {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'},
- {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'},
- {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'},
- {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'},
- {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
- {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'},
- {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'},
- {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'},
- {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'},
- {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'},
- {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
- {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'},
- {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'},
- {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'},
- {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'},
- {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'},
- {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
- {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'},
- {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}
- };
- assert(i < 100);
- memcpy(buf, two_ASCII_digits[i], 2);
-}
-
-} // namespace
-
bool SimpleAtob(absl::string_view str, bool* out) {
ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
@@ -496,13 +461,13 @@ static ExpDigits SplitToSix(const double value) {
int two_digits = dddddd / 10000;
dddddd -= two_digits * 10000;
- PutTwoDigits(two_digits, &exp_dig.digits[0]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]);
two_digits = dddddd / 100;
dddddd -= two_digits * 100;
- PutTwoDigits(two_digits, &exp_dig.digits[2]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]);
- PutTwoDigits(dddddd, &exp_dig.digits[4]);
+ numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]);
return exp_dig;
}
@@ -755,8 +720,8 @@ inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/,
// commonly used bases.
template <typename IntType>
struct LookupTables {
- static const IntType kVmaxOverBase[];
- static const IntType kVminOverBase[];
+ ABSL_CONST_INIT static const IntType kVmaxOverBase[];
+ ABSL_CONST_INIT static const IntType kVminOverBase[];
};
// An array initializer macro for X/base where base in [0, 36].
@@ -771,6 +736,49 @@ struct LookupTables {
X / 35, X / 36, \
}
+// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
+// array to avoid a static initializer.
+template <>
+const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
+ 0,
+ 0,
+ MakeUint128(9223372036854775807u, 18446744073709551615u),
+ MakeUint128(6148914691236517205u, 6148914691236517205u),
+ MakeUint128(4611686018427387903u, 18446744073709551615u),
+ MakeUint128(3689348814741910323u, 3689348814741910323u),
+ MakeUint128(3074457345618258602u, 12297829382473034410u),
+ MakeUint128(2635249153387078802u, 5270498306774157604u),
+ MakeUint128(2305843009213693951u, 18446744073709551615u),
+ MakeUint128(2049638230412172401u, 14347467612885206812u),
+ MakeUint128(1844674407370955161u, 11068046444225730969u),
+ MakeUint128(1676976733973595601u, 8384883669867978007u),
+ MakeUint128(1537228672809129301u, 6148914691236517205u),
+ MakeUint128(1418980313362273201u, 4256940940086819603u),
+ MakeUint128(1317624576693539401u, 2635249153387078802u),
+ MakeUint128(1229782938247303441u, 1229782938247303441u),
+ MakeUint128(1152921504606846975u, 18446744073709551615u),
+ MakeUint128(1085102592571150095u, 1085102592571150095u),
+ MakeUint128(1024819115206086200u, 16397105843297379214u),
+ MakeUint128(970881267037344821u, 16504981539634861972u),
+ MakeUint128(922337203685477580u, 14757395258967641292u),
+ MakeUint128(878416384462359600u, 14054662151397753612u),
+ MakeUint128(838488366986797800u, 13415813871788764811u),
+ MakeUint128(802032351030850070u, 4812194106185100421u),
+ MakeUint128(768614336404564650u, 12297829382473034410u),
+ MakeUint128(737869762948382064u, 11805916207174113034u),
+ MakeUint128(709490156681136600u, 11351842506898185609u),
+ MakeUint128(683212743470724133u, 17080318586768103348u),
+ MakeUint128(658812288346769700u, 10540996613548315209u),
+ MakeUint128(636094623231363848u, 15266270957552732371u),
+ MakeUint128(614891469123651720u, 9838263505978427528u),
+ MakeUint128(595056260442243600u, 9520900167075897608u),
+ MakeUint128(576460752303423487u, 18446744073709551615u),
+ MakeUint128(558992244657865200u, 8943875914525843207u),
+ MakeUint128(542551296285575047u, 9765923333140350855u),
+ MakeUint128(527049830677415760u, 8432797290838652167u),
+ MakeUint128(512409557603043100u, 8198552921648689607u),
+};
+
template <typename IntType>
const IntType LookupTables<IntType>::kVmaxOverBase[] =
X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
@@ -790,6 +798,8 @@ inline bool safe_parse_positive_int(absl::string_view text, int base,
assert(base >= 0);
assert(vmax >= static_cast<IntType>(base));
const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base];
+ assert(base < 2 ||
+ std::numeric_limits<IntType>::max() / base == vmax_over_base);
const char* start = text.data();
const char* end = start + text.size();
// loop over digits
@@ -823,6 +833,8 @@ inline bool safe_parse_negative_int(absl::string_view text, int base,
assert(vmin < 0);
assert(vmin <= 0 - base);
IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base];
+ assert(base < 2 ||
+ std::numeric_limits<IntType>::min() / base == vmin_over_base);
// 2003 c++ standard [expr.mul]
// "... the sign of the remainder is implementation-defined."
// Although (vmin/base)*base + vmin%base is always vmin.
@@ -886,6 +898,48 @@ inline bool safe_uint_internal(absl::string_view text, IntType* value_p,
} // anonymous namespace
namespace numbers_internal {
+
+// Digit conversion.
+ABSL_CONST_INIT ABSL_DLL const char kHexChar[] =
+ "0123456789abcdef";
+
+ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] =
+ "000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ "505152535455565758595a5b5c5d5e5f"
+ "606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = {
+ {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
+ {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
+ {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
+ {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
+ {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
+ {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
+ {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
+ {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
+ {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
+ {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
+ {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
+ {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
+ {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
+ {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
+ {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
+ {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
+ {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
+
bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
return safe_int_internal<int32_t>(text, value, base);
}
@@ -901,7 +955,11 @@ bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
return safe_uint_internal<uint64_t>(text, value, base);
}
-} // namespace numbers_internal
-} // inline namespace lts_2019_08_08
+bool safe_strtou128_base(absl::string_view text, uint128* value, int base) {
+ return safe_uint_internal<absl::uint128>(text, value, base);
+}
+
+} // namespace numbers_internal
+ABSL_NAMESPACE_END
} // namespace absl