From 0dc82b9d55e1616c1745d05973d40c9901903cc9 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Feb 2018 11:56:54 -0800 Subject: Changes imported from Abseil "staging" branch: - a0405e7870a80a9dbc6784b06795e7df5a8c90f5 Internal change by Daniel Katz - 2888fe17796d7afa45f4b6ca7eb8e88f52739c39 StrCat: Support zero-padding and space-padding for decima... by Jorg Brown - feebc521195241783730df9700394f6585550ff2 Merge GitHub PR #91. by Derek Mauro - e8164335efefb7335f407c17a16fce2ba4f24e3e This changes the value base_internal::kOnceDone from 32-b... by Abseil Team - 0f6085f3f0ee1d6baf9a558d07a25c2fcde93273 Remove `compliant` field from some type trait structs. by Matt Armstrong GitOrigin-RevId: a0405e7870a80a9dbc6784b06795e7df5a8c90f5 Change-Id: Ic2efd40f6ec35f79a8aa12d4475cbea3150756d7 --- WORKSPACE | 11 ++++++ absl/base/call_once.h | 5 ++- absl/meta/type_traits.h | 4 +++ absl/strings/str_cat.cc | 31 +++++++++++++++++ absl/strings/str_cat.h | 35 ++++++++++++++++--- absl/strings/str_cat_test.cc | 83 +++++++++++++++++++++++++++++++++++++------- 6 files changed, 151 insertions(+), 18 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 485f504..3b8b88a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,15 @@ workspace(name = "com_google_absl") +# Bazel toolchains +http_archive( + name = "bazel_toolchains", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f3b09700fae5d7b6e659d7cefe0dcc6e8498504c.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/archive/f3b09700fae5d7b6e659d7cefe0dcc6e8498504c.tar.gz", + ], + strip_prefix = "bazel-toolchains-f3b09700fae5d7b6e659d7cefe0dcc6e8498504c", + sha256 = "ed829b5eea8af1f405f4cc3d6ecfc3b1365bb7843171036030a31b5127002311", +) + # GoogleTest/GoogleMock framework. Used by most unit-tests. http_archive( name = "com_google_googletest", diff --git a/absl/base/call_once.h b/absl/base/call_once.h index 5d823a1..25c783e 100644 --- a/absl/base/call_once.h +++ b/absl/base/call_once.h @@ -134,7 +134,10 @@ enum { kOnceInit = 0, kOnceRunning = 0x65C2937B, kOnceWaiter = 0x05A308D2, - kOnceDone = 0x3F2D8AB0, + // A very small constant is chosen for kOnceDone so that it fit in a single + // compare with immediate instruction for most common ISAs. This is verified + // for x86, POWER and ARM. + kOnceDone = 221, // Random Number }; template diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index f36a59a..ac5d8e1 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -150,6 +150,7 @@ struct is_trivially_destructible : std::integral_constant::value> { #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE + private: static constexpr bool compliant = std::is_trivially_destructible::value == is_trivially_destructible::value; static_assert(compliant || std::is_trivially_destructible::value, @@ -199,6 +200,7 @@ struct is_trivially_default_constructible std::is_default_constructible::value && is_trivially_destructible::value> { #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE + private: static constexpr bool compliant = std::is_trivially_default_constructible::value == is_trivially_default_constructible::value; @@ -230,6 +232,7 @@ struct is_trivially_copy_constructible std::is_copy_constructible::value && is_trivially_destructible::value> { #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE + private: static constexpr bool compliant = std::is_trivially_copy_constructible::value == is_trivially_copy_constructible::value; @@ -262,6 +265,7 @@ struct is_trivially_copy_assignable : std::integral_constant::value> { #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE + private: static constexpr bool compliant = std::is_trivially_copy_assignable::value == is_trivially_copy_assignable::value; diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 99eb289..3fe8c95 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -45,6 +45,37 @@ AlphaNum::AlphaNum(Hex hex) { piece_ = absl::string_view(beg, end - beg); } +AlphaNum::AlphaNum(Dec dec) { + assert(dec.width <= numbers_internal::kFastToBufferSize); + char* const end = &digits_[numbers_internal::kFastToBufferSize]; + char* const minfill = end - dec.width; + char* writer = end; + uint64_t value = dec.value; + bool neg = dec.neg; + while (value > 9) { + *--writer = '0' + (value % 10); + value /= 10; + } + *--writer = '0' + value; + if (neg) *--writer = '-'; + + ptrdiff_t fillers = writer - minfill; + if (fillers > 0) { + // Tricky: if the fill character is ' ', then it's <+/-> + // But...: if the fill character is '0', then it's <+/-> + bool add_sign_again = false; + if (neg && dec.fill == '0') { // If filling with '0', + ++writer; // ignore the sign we just added + add_sign_again = true; // and re-add the sign later. + } + writer -= fillers; + std::fill_n(writer, fillers, dec.fill); + if (add_sign_again) *--writer = '-'; + } + + piece_ = absl::string_view(writer, end - writer); +} + // ---------------------------------------------------------------------- // StrCat() // This merges the given strings or integers, with no delimiter. This diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index 1cf7b11..0c33b6c 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -76,10 +76,10 @@ struct AlphaNumBuffer { } // namespace strings_internal -// Enum that specifies the number of significant digits to return in a `Hex` -// conversion and fill character to use. A `kZeroPad2` value, for example, would -// produce hexadecimal strings such as "0A","0F" and 'kSpacePad5' value would -// produce hexadecimal strings such as " A"," F". +// Enum that specifies the number of significant digits to return in a `Hex` or +// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, +// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value +// would produce hexadecimal strings such as " A"," F". enum PadSpec { kNoPad = 1, kZeroPad2, @@ -153,6 +153,32 @@ struct Hex { fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} }; +// ----------------------------------------------------------------------------- +// Dec +// ----------------------------------------------------------------------------- +// +// `Dec` stores a set of decimal std::string conversion parameters for use +// within `AlphaNum` std::string conversions. Dec is slower than the default +// integer conversion, so use it only if you need padding. +struct Dec { + uint64_t value; + uint8_t width; + char fill; + bool neg; + + template + explicit Dec(Int v, PadSpec spec = absl::kNoPad, + typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) + : value(v >= 0 ? static_cast(v) + : uint64_t{0} - static_cast(v)), + width(spec == absl::kNoPad + ? 1 + : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 + : spec - absl::kZeroPad2 + 2), + fill(spec >= absl::kSpacePad2 ? ' ' : '0'), + neg(v < 0) {} +}; + // ----------------------------------------------------------------------------- // AlphaNum // ----------------------------------------------------------------------------- @@ -191,6 +217,7 @@ class AlphaNum { : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} AlphaNum(Hex hex); // NOLINT(runtime/explicit) + AlphaNum(Dec dec); // NOLINT(runtime/explicit) template AlphaNum( // NOLINT(runtime/explicit) diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index dd063b0..710113f 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc @@ -431,28 +431,85 @@ void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format, } } -void CheckHex64(uint64_t v) { - unsigned long long llv = v; // NOLINT(runtime/int) +template +void CheckDec(IntType v, const char* nopad_format, const char* zeropad_format, + const char* spacepad_format) { + char expected[256]; + + std::string actual = absl::StrCat(absl::Dec(v, absl::kNoPad)); + snprintf(expected, sizeof(expected), nopad_format, v); + EXPECT_EQ(expected, actual) << " decimal value " << v; + + for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) { + std::string actual = + absl::StrCat(absl::Dec(v, static_cast(spec))); + snprintf(expected, sizeof(expected), zeropad_format, + spec - absl::kZeroPad2 + 2, v); + EXPECT_EQ(expected, actual) + << " decimal value " << v << " format '" << zeropad_format + << "' digits " << (spec - absl::kZeroPad2 + 2); + } + + for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) { + std::string actual = + absl::StrCat(absl::Dec(v, static_cast(spec))); + snprintf(expected, sizeof(expected), spacepad_format, + spec - absl::kSpacePad2 + 2, v); + EXPECT_EQ(expected, actual) + << " decimal value " << v << " format '" << spacepad_format + << "' digits " << (spec - absl::kSpacePad2 + 2); + } +} + +void CheckHexDec64(uint64_t v) { + unsigned long long ullv = v; // NOLINT(runtime/int) + + CheckHex(ullv, "%llx", "%0*llx", "%*llx"); + CheckDec(ullv, "%llu", "%0*llu", "%*llu"); + + long long llv = static_cast(ullv); // NOLINT(runtime/int) + CheckDec(llv, "%lld", "%0*lld", "%*lld"); +} - CheckHex(llv, "%llx", "%0*llx", "%*llx"); +void CheckHexDec32(uint32_t uv) { + CheckHex(uv, "%x", "%0*x", "%*x"); + CheckDec(uv, "%u", "%0*u", "%*u"); + int32_t v = static_cast(uv); + CheckDec(v, "%d", "%0*d", "%*d"); } -template -void CheckHex32(Int32Type v) { - CheckHex(v, "%x", "%0*x", "%*x"); +void CheckAll(uint64_t v) { + CheckHexDec64(v); + CheckHexDec32(static_cast(v)); } void TestFastPrints() { - // Test min int to make sure that works + // Test all small ints; there aren't many and they're common. for (int i = 0; i < 10000; i++) { - CheckHex64(i); - CheckHex32(static_cast(i)); - CheckHex32(i); - CheckHex32(-i); + CheckAll(i); } - CheckHex64(uint64_t{0x123456789abcdef0}); - CheckHex32(0x12345678U); + CheckAll(std::numeric_limits::max()); + CheckAll(std::numeric_limits::max() - 1); + CheckAll(std::numeric_limits::min()); + CheckAll(std::numeric_limits::min() + 1); + CheckAll(std::numeric_limits::max()); + CheckAll(std::numeric_limits::max() - 1); + CheckAll(std::numeric_limits::min()); + CheckAll(std::numeric_limits::min() + 1); + CheckAll(999999999); // fits in 32 bits + CheckAll(1000000000); // fits in 32 bits + CheckAll(9999999999); // doesn't fit in 32 bits + CheckAll(10000000000); // doesn't fit in 32 bits + CheckAll(999999999999999999); // fits in signed 64-bit + CheckAll(9999999999999999999u); // fits in unsigned 64-bit, but not signed. + CheckAll(1000000000000000000); // fits in signed 64-bit + CheckAll(10000000000000000000u); // fits in unsigned 64-bit, but not signed. + + CheckAll(999999999876543210); // check all decimal digits, signed + CheckAll(9999999999876543210u); // check all decimal digits, unsigned. + CheckAll(0x123456789abcdef0); // check all hex digits + CheckAll(0x12345678); int8_t minus_one_8bit = -1; EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit))); -- cgit v1.2.3