about summary refs log tree commit diff
path: root/absl/strings
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-04-23T22·50-0700
committerDerek Mauro <dmauro@google.com>2018-04-24T14·09-0400
commit19b3c95727316cef3b0b40eaf37f6645a876f8d2 (patch)
tree093012eb09e5d01e98c941607a884dd79d0db55b /absl/strings
parentaf7882601aad93ada881486eeaabc562f1733961 (diff)
- 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3 Fix the description of Span::subspan(). by Abseil Team <absl-team@google.com>
  - bae1a1c21924bd31fa7315eff05ea6158d9e7947 Port the symbolizer to Windows. by Derek Mauro <dmauro@google.com>
  - 2253c04c1a4f39d9581772f1dc4491878aa3831f Support absl::Hex() and absl::Dec() as arguments to absl:... by Jorg Brown <jorg@google.com>
  - 552c3ac259e9c254fda9244755487f3423d2fe4b Internal change by Jorg Brown <jorg@google.com>

GitOrigin-RevId: 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3
Change-Id: I448133c9bb6d837037c12b45a9a16a7945049453
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/substitute.cc55
-rw-r--r--absl/strings/substitute.h18
-rw-r--r--absl/strings/substitute_test.cc18
3 files changed, 83 insertions, 8 deletions
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index f739f8c20b2c..3b2005945095 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 5596a5dbf35a..5747d384d34e 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 7c9af6b22433..144df01ec184 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);