Commit 8a0693b2 by Phoebe Liang Committed by Copybara-Service

Adds `AbslStringify` support to `absl::Hex` and `absl::Dec`

`absl::Hex` and `absl::Dec` are now stringifiable through `AbslStringify`. This means that they can be passed to logging, `absl::StrFormat`, `absl::StrCat` and `absl::Substitute`. Note that this change will break unsupported usages of `absl::AlphaNum`. `absl::AlphaNum` is not intended to be instantiated as a stack variable due to lifetime issues. Unsupported usages include:

* constructing an `absl::AlphaNum` as a local variable.
  * For example, `absl::AlphaNum a = absl::Hex(...);`
* declaring an `absl::AlphaNum` as a member variable

Usage of `absl::AlphaNum` as a function parameter will continue to be supported.

PiperOrigin-RevId: 505158534
Change-Id: Idecdf0b3d137482e86b393c7480229343d68eb36
parent 68a1de6f
...@@ -30,55 +30,6 @@ ...@@ -30,55 +30,6 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
AlphaNum::AlphaNum(Hex hex) {
static_assert(numbers_internal::kFastToBufferSize >= 32,
"This function only works when output buffer >= 32 bytes long");
char* const end = &digits_[numbers_internal::kFastToBufferSize];
auto real_width =
absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
if (real_width >= hex.width) {
piece_ = absl::string_view(end - real_width, real_width);
} else {
// Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
// max pad width can be up to 20.
std::memset(end - 32, hex.fill, 16);
// Patch up everything else up to the real_width.
std::memset(end - real_width - 16, hex.fill, 16);
piece_ = absl::string_view(end - hex.width, hex.width);
}
}
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' + static_cast<char>(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, static_cast<size_t>(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
......
...@@ -87,8 +87,10 @@ ...@@ -87,8 +87,10 @@
#ifndef ABSL_STRINGS_STR_CAT_H_ #ifndef ABSL_STRINGS_STR_CAT_H_
#define ABSL_STRINGS_STR_CAT_H_ #define ABSL_STRINGS_STR_CAT_H_
#include <algorithm>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
...@@ -202,6 +204,27 @@ struct Hex { ...@@ -202,6 +204,27 @@ struct Hex {
explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad) explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
: Hex(spec, reinterpret_cast<uintptr_t>(v)) {} : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
template <typename S>
friend void AbslStringify(S& sink, Hex hex) {
static_assert(
numbers_internal::kFastToBufferSize >= 32,
"This function only works when output buffer >= 32 bytes long");
char buffer[numbers_internal::kFastToBufferSize];
char* const end = &buffer[numbers_internal::kFastToBufferSize];
auto real_width =
absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
if (real_width >= hex.width) {
sink.Append(absl::string_view(end - real_width, real_width));
} else {
// Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
// max pad width can be up to 20.
std::memset(end - 32, hex.fill, 16);
// Patch up everything else up to the real_width.
std::memset(end - real_width - 16, hex.fill, 16);
sink.Append(absl::string_view(end - hex.width, hex.width));
}
}
private: private:
Hex(PadSpec spec, uint64_t v) Hex(PadSpec spec, uint64_t v)
: value(v), : value(v),
...@@ -236,6 +259,38 @@ struct Dec { ...@@ -236,6 +259,38 @@ struct Dec {
: spec - absl::kZeroPad2 + 2), : spec - absl::kZeroPad2 + 2),
fill(spec >= absl::kSpacePad2 ? ' ' : '0'), fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
neg(v < 0) {} neg(v < 0) {}
template <typename S>
friend void AbslStringify(S& sink, Dec dec) {
assert(dec.width <= numbers_internal::kFastToBufferSize);
char buffer[numbers_internal::kFastToBufferSize];
char* const end = &buffer[numbers_internal::kFastToBufferSize];
char* const minfill = end - dec.width;
char* writer = end;
uint64_t val = dec.value;
while (val > 9) {
*--writer = '0' + (val % 10);
val /= 10;
}
*--writer = '0' + static_cast<char>(val);
if (dec.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 (dec.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 = '-';
}
sink.Append(absl::string_view(writer, static_cast<size_t>(end - writer)));
}
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -283,9 +338,6 @@ class AlphaNum { ...@@ -283,9 +338,6 @@ class AlphaNum {
AlphaNum(double f) // NOLINT(runtime/explicit) AlphaNum(double f) // NOLINT(runtime/explicit)
: piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
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)
const strings_internal::AlphaNumBuffer<size>& buf const strings_internal::AlphaNumBuffer<size>& buf
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment