diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 2f9df673..6981347a 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -17,16 +17,52 @@ #include #include +#include #include #include +#include #include "absl/strings/ascii.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/numbers.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN +namespace strings_internal { +void StringifySink::Append(size_t count, char ch) { buffer_.append(count, ch); } + +void StringifySink::Append(string_view v) { + buffer_.append(v.data(), v.size()); +} + +bool StringifySink::PutPaddedString(string_view v, int width, int precision, + bool left) { + size_t space_remaining = 0; + + if (width >= 0) space_remaining = static_cast(width); + + size_t n = v.size(); + + if (precision >= 0) n = (std::min)(n, static_cast(precision)); + + string_view shown(v.data(), n); + + if (shown.size() < space_remaining) { + space_remaining = space_remaining - shown.size(); + } else { + space_remaining = 0; + } + + if (!left) Append(space_remaining, ' '); + Append(shown); + if (left) Append(space_remaining, ' '); + return true; +} + +} // namespace strings_internal + AlphaNum::AlphaNum(Hex hex) { static_assert(numbers_internal::kFastToBufferSize >= 32, "This function only works when output buffer >= 32 bytes long"); diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index a94bc5df..05728ab5 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -57,6 +57,7 @@ #include #include #include +#include #include #include "absl/base/port.h" @@ -76,6 +77,27 @@ struct AlphaNumBuffer { size_t size; }; +class StringifySink { + public: + void Append(size_t count, char ch); + + void Append(string_view v); + + bool PutPaddedString(string_view v, int width, int precision, bool left); + + template + friend string_view ExtractStringification(StringifySink& sink, const T& v); + + private: + std::string buffer_; +}; + +template +string_view ExtractStringification(StringifySink& sink, const T& v) { + AbslStringify(sink, v); + return sink.buffer_; +} + } // namespace strings_internal // Enum that specifies the number of significant digits to return in a `Hex` or @@ -208,6 +230,15 @@ struct Dec { // `StrAppend()`, providing efficient conversion of numeric, boolean, and // hexadecimal values (through the `Hex` type) into strings. +template +struct HasAbslStringify : std::false_type {}; + +template +struct HasAbslStringify(), + std::declval()))>::value>> + : std::true_type {}; + class AlphaNum { public: // No bool ctor -- bools convert to an integral type. @@ -255,6 +286,13 @@ class AlphaNum { : piece_(NullSafeStringView(c_str)) {} // NOLINT(runtime/explicit) AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit) + template ::value>::type> + AlphaNum( // NOLINT(runtime/explicit) + const T& v, // NOLINT(runtime/explicit) + strings_internal::StringifySink&& sink = {}) // NOLINT(runtime/explicit) + : piece_(strings_internal::ExtractStringification(sink, v)) {} + template AlphaNum( // NOLINT(runtime/explicit) const std::basic_string, Allocator>& str) diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index 69df2502..868b9bce 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc @@ -612,4 +612,24 @@ TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) { TestFastPrints(); } +struct PointStringify { + template + friend void AbslStringify(FormatSink& sink, const PointStringify& p) { + sink.Append("("); + sink.Append(absl::StrCat(p.x)); + sink.Append(", "); + sink.Append(absl::StrCat(p.y)); + sink.Append(")"); + } + + double x = 10.0; + double y = 20.0; +}; + +TEST(StrCat, AbslStringifyExample) { + PointStringify p; + EXPECT_EQ(absl::StrCat(p), "(10, 20)"); + EXPECT_EQ(absl::StrCat("a ", p, " z"), "a (10, 20) z"); +} + } // namespace