diff options
author | Phoebe Liang <phoebeliang@google.com> | 2023-01-27 10:54:21 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-01-27 10:55:06 -0800 |
commit | 8a0693b2a75f21e508ffcd172efda3bbb638a275 (patch) | |
tree | 6cfae7297fcea3585ef6329f3e481a272e562b81 /absl/strings/str_cat.h | |
parent | 68a1de6f86b3e11ddf54841f11f63e60ed5bdc0a (diff) | |
download | abseil-8a0693b2a75f21e508ffcd172efda3bbb638a275.tar.gz abseil-8a0693b2a75f21e508ffcd172efda3bbb638a275.tar.bz2 abseil-8a0693b2a75f21e508ffcd172efda3bbb638a275.zip |
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
Diffstat (limited to 'absl/strings/str_cat.h')
-rw-r--r-- | absl/strings/str_cat.h | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index 8b68dac0..fcd48c4e 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -87,8 +87,10 @@ #ifndef ABSL_STRINGS_STR_CAT_H_ #define ABSL_STRINGS_STR_CAT_H_ +#include <algorithm> #include <array> #include <cstdint> +#include <cstring> #include <string> #include <type_traits> #include <utility> @@ -202,6 +204,27 @@ struct Hex { explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad) : 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: Hex(PadSpec spec, uint64_t v) : value(v), @@ -236,6 +259,38 @@ struct Dec { : spec - absl::kZeroPad2 + 2), fill(spec >= absl::kSpacePad2 ? ' ' : '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 { AlphaNum(double f) // NOLINT(runtime/explicit) : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} - AlphaNum(Hex hex); // NOLINT(runtime/explicit) - AlphaNum(Dec dec); // NOLINT(runtime/explicit) - template <size_t size> AlphaNum( // NOLINT(runtime/explicit) const strings_internal::AlphaNumBuffer<size>& buf |