Changes imported from Abseil "staging" branch:

- a0405e7870a80a9dbc6784b06795e7df5a8c90f5 Internal change by Daniel Katz <katzdm@google.com>
  - 2888fe17796d7afa45f4b6ca7eb8e88f52739c39 StrCat: Support zero-padding and space-padding for decima... by Jorg Brown <jorg@google.com>
  - feebc521195241783730df9700394f6585550ff2 Merge GitHub PR #91. by Derek Mauro <dmauro@google.com>
  - e8164335efefb7335f407c17a16fce2ba4f24e3e This changes the value base_internal::kOnceDone from 32-b... by Abseil Team <absl-team@google.com>
  - 0f6085f3f0ee1d6baf9a558d07a25c2fcde93273 Remove `compliant` field from some type trait structs. by Matt Armstrong <marmstrong@google.com>

GitOrigin-RevId: a0405e7870a80a9dbc6784b06795e7df5a8c90f5
Change-Id: Ic2efd40f6ec35f79a8aa12d4475cbea3150756d7
This commit is contained in:
Abseil Team 2018-02-09 11:56:54 -08:00 committed by Daniel Katz
parent 4791df7d1a
commit 0dc82b9d55
6 changed files with 151 additions and 18 deletions

View file

@ -1,4 +1,15 @@
workspace(name = "com_google_absl") 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. # GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive( http_archive(
name = "com_google_googletest", name = "com_google_googletest",

View file

@ -134,7 +134,10 @@ enum {
kOnceInit = 0, kOnceInit = 0,
kOnceRunning = 0x65C2937B, kOnceRunning = 0x65C2937B,
kOnceWaiter = 0x05A308D2, 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 <typename Callable, typename... Args> template <typename Callable, typename... Args>

View file

@ -150,6 +150,7 @@ struct is_trivially_destructible
: std::integral_constant<bool, __has_trivial_destructor(T) && : std::integral_constant<bool, __has_trivial_destructor(T) &&
std::is_destructible<T>::value> { std::is_destructible<T>::value> {
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
private:
static constexpr bool compliant = std::is_trivially_destructible<T>::value == static constexpr bool compliant = std::is_trivially_destructible<T>::value ==
is_trivially_destructible::value; is_trivially_destructible::value;
static_assert(compliant || std::is_trivially_destructible<T>::value, static_assert(compliant || std::is_trivially_destructible<T>::value,
@ -199,6 +200,7 @@ struct is_trivially_default_constructible
std::is_default_constructible<T>::value && std::is_default_constructible<T>::value &&
is_trivially_destructible<T>::value> { is_trivially_destructible<T>::value> {
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
private:
static constexpr bool compliant = static constexpr bool compliant =
std::is_trivially_default_constructible<T>::value == std::is_trivially_default_constructible<T>::value ==
is_trivially_default_constructible::value; is_trivially_default_constructible::value;
@ -230,6 +232,7 @@ struct is_trivially_copy_constructible
std::is_copy_constructible<T>::value && std::is_copy_constructible<T>::value &&
is_trivially_destructible<T>::value> { is_trivially_destructible<T>::value> {
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
private:
static constexpr bool compliant = static constexpr bool compliant =
std::is_trivially_copy_constructible<T>::value == std::is_trivially_copy_constructible<T>::value ==
is_trivially_copy_constructible::value; is_trivially_copy_constructible::value;
@ -262,6 +265,7 @@ struct is_trivially_copy_assignable
: std::integral_constant<bool, __has_trivial_assign(T) && : std::integral_constant<bool, __has_trivial_assign(T) &&
std::is_copy_assignable<T>::value> { std::is_copy_assignable<T>::value> {
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
private:
static constexpr bool compliant = static constexpr bool compliant =
std::is_trivially_copy_assignable<T>::value == std::is_trivially_copy_assignable<T>::value ==
is_trivially_copy_assignable::value; is_trivially_copy_assignable::value;

View file

@ -45,6 +45,37 @@ AlphaNum::AlphaNum(Hex hex) {
piece_ = absl::string_view(beg, end - beg); 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 <fill><+/-><digits>
// But...: if the fill character is '0', then it's <+/-><fill><digits>
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() // StrCat()
// This merges the given strings or integers, with no delimiter. This // This merges the given strings or integers, with no delimiter. This

View file

@ -76,10 +76,10 @@ struct AlphaNumBuffer {
} // namespace strings_internal } // namespace strings_internal
// Enum that specifies the number of significant digits to return in a `Hex` // Enum that specifies the number of significant digits to return in a `Hex` or
// conversion and fill character to use. A `kZeroPad2` value, for example, would // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
// produce hexadecimal strings such as "0A","0F" and 'kSpacePad5' value would // would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
// produce hexadecimal strings such as " A"," F". // would produce hexadecimal strings such as " A"," F".
enum PadSpec { enum PadSpec {
kNoPad = 1, kNoPad = 1,
kZeroPad2, kZeroPad2,
@ -153,6 +153,32 @@ struct Hex {
fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} 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 <typename Int>
explicit Dec(Int v, PadSpec spec = absl::kNoPad,
typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
: value(v >= 0 ? static_cast<uint64_t>(v)
: uint64_t{0} - static_cast<uint64_t>(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 // AlphaNum
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -191,6 +217,7 @@ class AlphaNum {
: piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
AlphaNum(Hex hex); // NOLINT(runtime/explicit) AlphaNum(Hex hex); // NOLINT(runtime/explicit)
AlphaNum(Dec dec); // NOLINT(runtime/explicit)
template <size_t size> template <size_t size>
AlphaNum( // NOLINT(runtime/explicit) AlphaNum( // NOLINT(runtime/explicit)

View file

@ -431,28 +431,85 @@ void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format,
} }
} }
void CheckHex64(uint64_t v) { template <typename IntType>
unsigned long long llv = v; // NOLINT(runtime/int) void CheckDec(IntType v, const char* nopad_format, const char* zeropad_format,
const char* spacepad_format) {
char expected[256];
CheckHex(llv, "%llx", "%0*llx", "%*llx"); 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<absl::PadSpec>(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<absl::PadSpec>(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);
}
} }
template <typename Int32Type> void CheckHexDec64(uint64_t v) {
void CheckHex32(Int32Type v) { unsigned long long ullv = v; // NOLINT(runtime/int)
CheckHex(v, "%x", "%0*x", "%*x");
CheckHex(ullv, "%llx", "%0*llx", "%*llx");
CheckDec(ullv, "%llu", "%0*llu", "%*llu");
long long llv = static_cast<long long>(ullv); // NOLINT(runtime/int)
CheckDec(llv, "%lld", "%0*lld", "%*lld");
}
void CheckHexDec32(uint32_t uv) {
CheckHex(uv, "%x", "%0*x", "%*x");
CheckDec(uv, "%u", "%0*u", "%*u");
int32_t v = static_cast<int32_t>(uv);
CheckDec(v, "%d", "%0*d", "%*d");
}
void CheckAll(uint64_t v) {
CheckHexDec64(v);
CheckHexDec32(static_cast<uint32_t>(v));
} }
void TestFastPrints() { 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++) { for (int i = 0; i < 10000; i++) {
CheckHex64(i); CheckAll(i);
CheckHex32(static_cast<uint32_t>(i));
CheckHex32(i);
CheckHex32(-i);
} }
CheckHex64(uint64_t{0x123456789abcdef0}); CheckAll(std::numeric_limits<uint64_t>::max());
CheckHex32(0x12345678U); CheckAll(std::numeric_limits<uint64_t>::max() - 1);
CheckAll(std::numeric_limits<int64_t>::min());
CheckAll(std::numeric_limits<int64_t>::min() + 1);
CheckAll(std::numeric_limits<uint32_t>::max());
CheckAll(std::numeric_limits<uint32_t>::max() - 1);
CheckAll(std::numeric_limits<int32_t>::min());
CheckAll(std::numeric_limits<int32_t>::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; int8_t minus_one_8bit = -1;
EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit))); EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit)));