diff options
Diffstat (limited to 'absl/strings')
-rw-r--r-- | absl/strings/substitute.cc | 55 | ||||
-rw-r--r-- | absl/strings/substitute.h | 18 | ||||
-rw-r--r-- | absl/strings/substitute_test.cc | 18 |
3 files changed, 83 insertions, 8 deletions
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index f739f8c2..3b200594 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc @@ -94,6 +94,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, assert(target == output->data() + output->size()); } +static const char kHexDigits[] = "0123456789abcdef"; Arg::Arg(const void* value) { static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, "fix sizeof(scratch_)"); @@ -102,7 +103,6 @@ Arg::Arg(const void* value) { } else { char* ptr = scratch_ + sizeof(scratch_); uintptr_t num = reinterpret_cast<uintptr_t>(value); - static const char kHexDigits[] = "0123456789abcdef"; do { *--ptr = kHexDigits[num & 0xf]; num >>= 4; @@ -113,5 +113,58 @@ Arg::Arg(const void* value) { } } +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Hex hex) { + char* const end = &scratch_[numbers_internal::kFastToBufferSize]; + char* writer = end; + uint64_t value = hex.value; + do { + *--writer = kHexDigits[value & 0xF]; + value >>= 4; + } while (value != 0); + + char* beg; + if (end - writer < hex.width) { + beg = end - hex.width; + std::fill_n(beg, writer - beg, hex.fill); + } else { + beg = writer; + } + + piece_ = absl::string_view(beg, end - beg); +} + +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Dec dec) { + assert(dec.width <= numbers_internal::kFastToBufferSize); + char* const end = &scratch_[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); +} + } // namespace substitute_internal } // namespace absl diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 5596a5db..5747d384 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -76,7 +76,7 @@ #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/numbers.h" -#include "absl/strings/str_join.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" @@ -113,10 +113,10 @@ class Arg { // what to do. Arg(char value) // NOLINT(runtime/explicit) : piece_(scratch_, 1) { scratch_[0] = value; } - Arg(short value) // NOLINT(runtime/explicit) + Arg(short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned short value) // NOLINT(runtime/explicit) + Arg(unsigned short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} Arg(int value) // NOLINT(runtime/explicit) @@ -125,16 +125,16 @@ class Arg { Arg(unsigned int value) // NOLINT(runtime/explicit) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long value) // NOLINT(runtime/explicit) + Arg(long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long value) // NOLINT(runtime/explicit) + Arg(unsigned long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long long value) // NOLINT(runtime/explicit) + Arg(long long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long long value) // NOLINT(runtime/explicit) + Arg(unsigned long long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} Arg(float value) // NOLINT(runtime/explicit) @@ -145,6 +145,10 @@ class Arg { } Arg(bool value) // NOLINT(runtime/explicit) : piece_(value ? "true" : "false") {} + + Arg(Hex hex); // NOLINT(runtime/explicit) + Arg(Dec dec); // NOLINT(runtime/explicit) + // `void*` values, with the exception of `char*`, are printed as // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed. Arg(const void* value); // NOLINT(runtime/explicit) diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc index 7c9af6b2..144df01e 100644 --- a/absl/strings/substitute_test.cc +++ b/absl/strings/substitute_test.cc @@ -43,6 +43,24 @@ TEST(SubstituteTest, Substitute) { -1234567890, 3234567890U, -1234567890L, 3234567890UL, -int64_t{1234567890123456789}, uint64_t{9234567890123456789u})); + // Hex format + EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef", + absl::Substitute("$0$1$2$3$4 $5", // + absl::Hex(0), absl::Hex(1, absl::kSpacePad2), + absl::Hex(0xf, absl::kSpacePad2), + absl::Hex(int16_t{-1}, absl::kSpacePad5), + absl::Hex(int16_t{-1}, absl::kZeroPad5), + absl::Hex(0x123456789abcdef, absl::kZeroPad16))); + + // Dec format + EXPECT_EQ("0 115 -1-0001 81985529216486895", + absl::Substitute("$0$1$2$3$4 $5", // + absl::Dec(0), absl::Dec(1, absl::kSpacePad2), + absl::Dec(0xf, absl::kSpacePad2), + absl::Dec(int16_t{-1}, absl::kSpacePad5), + absl::Dec(int16_t{-1}, absl::kZeroPad5), + absl::Dec(0x123456789abcdef, absl::kZeroPad16))); + // Pointer. const int* int_p = reinterpret_cast<const int*>(0x12345); std::string str = absl::Substitute("$0", int_p); |