From e9bb35cea3d3b18bdaaa273f6e1746d9334aa324 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 1 Jun 2023 13:51:36 -0700 Subject: Adding support for int128 and uint128 flag types PiperOrigin-RevId: 537120102 Change-Id: I7952e53aca10319eb433e4c4d60cf3d7fe74d19a --- absl/flags/BUILD.bazel | 1 + absl/flags/CMakeLists.txt | 1 + absl/flags/marshalling.cc | 27 ++++++++ absl/flags/marshalling.h | 3 + absl/flags/marshalling_test.cc | 137 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+) diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 627f453a..583e6d94 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -99,6 +99,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:log_severity", + "//absl/numeric:int128", "//absl/strings", "//absl/strings:str_format", "//absl/types:optional", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index b9d3b97b..6525eb2a 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -87,6 +87,7 @@ absl_cc_library( absl::config absl::core_headers absl::log_severity + absl::int128 absl::optional absl::strings absl::str_format diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index 81f9cebd..cf6312b1 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc @@ -26,6 +26,7 @@ #include "absl/base/config.h" #include "absl/base/log_severity.h" #include "absl/base/macros.h" +#include "absl/numeric/int128.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" @@ -125,6 +126,32 @@ bool AbslParseFlag(absl::string_view text, unsigned long long* dst, return ParseFlagImpl(text, *dst); } +bool AbslParseFlag(absl::string_view text, absl::int128* dst, std::string*) { + text = absl::StripAsciiWhitespace(text); + + // check hex + int base = NumericBase(text); + if (!absl::numbers_internal::safe_strto128_base(text, dst, base)) { + return false; + } + + return base == 16 ? absl::SimpleHexAtoi(text, dst) + : absl::SimpleAtoi(text, dst); +} + +bool AbslParseFlag(absl::string_view text, absl::uint128* dst, std::string*) { + text = absl::StripAsciiWhitespace(text); + + // check hex + int base = NumericBase(text); + if (!absl::numbers_internal::safe_strtou128_base(text, dst, base)) { + return false; + } + + return base == 16 ? absl::SimpleHexAtoi(text, dst) + : absl::SimpleAtoi(text, dst); +} + // -------------------------------------------------------------------- // AbslParseFlag for floating point types. diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h index 325e75e5..21d955d5 100644 --- a/absl/flags/marshalling.h +++ b/absl/flags/marshalling.h @@ -200,6 +200,7 @@ #define ABSL_FLAGS_MARSHALLING_H_ #include "absl/base/config.h" +#include "absl/numeric/int128.h" #if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) #include @@ -233,6 +234,8 @@ bool AbslParseFlag(absl::string_view, unsigned long*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, long long*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, unsigned long long*, // NOLINT std::string*); +bool AbslParseFlag(absl::string_view, absl::int128*, std::string*); // NOLINT +bool AbslParseFlag(absl::string_view, absl::uint128*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, float*, std::string*); bool AbslParseFlag(absl::string_view, double*, std::string*); bool AbslParseFlag(absl::string_view, std::string*, std::string*); diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index 7b6d2ad5..d996ca7f 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc @@ -455,6 +455,143 @@ TEST(MarshallingTest, TestUInt64Parsing) { // -------------------------------------------------------------------- +TEST(MarshallingTest, TestInt128Parsing) { + std::string err; + absl::int128 value; + + absl::int128 zero = 0; + absl::int128 one = 1; + absl::int128 neg_one = -1; + absl::int128 hundred = 100; + absl::int128 hundreds_val = 123; + absl::int128 neg_thousands_val = -98765; + absl::int128 pos_three = 3; + + // Decimal values. + EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); + EXPECT_EQ(value, zero); + EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("-1", &value, &err)); + EXPECT_EQ(value, neg_one); + EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); + EXPECT_EQ(value, hundreds_val); + EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err)); + EXPECT_EQ(value, neg_thousands_val); + EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); + EXPECT_EQ(value, pos_three); + + // Leading zero values. + EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); + EXPECT_EQ(value, hundred); + + absl::int128 sixteen = 16; + absl::int128 quintillion_val = 1152827684197027293; + absl::int128 quintillion_val2 = + absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + + // Hex values. + EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); + EXPECT_EQ(value, quintillion_val); + EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); + EXPECT_EQ(value, quintillion_val2); + + // TODO(b/285183223): Add support for parsing negative hex representation + + // Whitespace handling + EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); + EXPECT_EQ(value, hundred); + EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); + EXPECT_EQ(value, hundreds_val); // =123 + + // Invalid values. + EXPECT_FALSE(absl::ParseFlag("", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("--1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\n", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\t", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("2U", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err)); +} + +// -------------------------------------------------------------------- + +TEST(MarshallingTest, TestUint128Parsing) { + std::string err; + absl::uint128 value; + + absl::uint128 zero = 0; + absl::uint128 one = 1; + absl::uint128 hundred = 100; + absl::uint128 hundreds_val = 123; + absl::uint128 pos_three = 3; + + // Decimal values. + EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); + EXPECT_EQ(value, zero); + EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); + EXPECT_EQ(value, hundreds_val); + EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); + EXPECT_EQ(value, pos_three); + + // Leading zero values. + EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); + EXPECT_EQ(value, hundred); + + absl::uint128 sixteen = 16; + absl::uint128 quintillion_val = 1152827684197027293; + absl::uint128 quintillion_val2 = + absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + + // Hex values. + EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); + EXPECT_EQ(value, quintillion_val); + EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); + EXPECT_EQ(value, quintillion_val2); + + // Whitespace handling + EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); + EXPECT_EQ(value, hundred); + EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); + EXPECT_EQ(value, hundreds_val); // =123 + + // Invalid values. + EXPECT_FALSE(absl::ParseFlag("", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("-1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("--1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\n", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\t", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("2U", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err)); +} + +// -------------------------------------------------------------------- + TEST(MarshallingTest, TestFloatParsing) { std::string err; float value; -- cgit v1.2.3