diff options
Diffstat (limited to 'absl/strings')
-rw-r--r-- | absl/strings/BUILD.bazel | 4 | ||||
-rw-r--r-- | absl/strings/CMakeLists.txt | 4 | ||||
-rw-r--r-- | absl/strings/internal/str_format/extension_test.cc | 37 | ||||
-rw-r--r-- | absl/strings/internal/str_format/output.h | 7 | ||||
-rw-r--r-- | absl/strings/internal/str_format/output_test.cc | 8 | ||||
-rw-r--r-- | absl/strings/str_format.h | 24 |
6 files changed, 72 insertions, 12 deletions
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 404c707f001e..4ee5a2ca7d2d 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -651,6 +651,7 @@ cc_test( copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ + ":cord", ":str_format", ":strings", "//absl/base:core_headers", @@ -666,8 +667,10 @@ cc_test( copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ + ":cord", ":str_format", ":str_format_internal", + ":strings", "@com_google_googletest//:gtest_main", ], ) @@ -726,6 +729,7 @@ cc_test( copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ + ":cord", ":str_format_internal", "@com_google_googletest//:gtest_main", ], diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 2106148c91c1..10213022a7bb 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -409,6 +409,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::str_format + absl::cord absl::strings absl::core_headers gmock_main @@ -424,6 +425,8 @@ absl_cc_test( DEPS absl::str_format absl::str_format_internal + absl::cord + absl::strings gmock_main ) @@ -487,6 +490,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::str_format_internal + absl::cord gmock_main ) diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc index 4e23fefbd5b0..dc5576b6337e 100644 --- a/absl/strings/internal/str_format/extension_test.cc +++ b/absl/strings/internal/str_format/extension_test.cc @@ -19,9 +19,27 @@ #include <random> #include <string> +#include "absl/strings/cord.h" +#include "gtest/gtest.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" -#include "gtest/gtest.h" +namespace my_namespace { +class UserDefinedType { + public: + UserDefinedType() = default; + + void Append(absl::string_view str) { value_.append(str.data(), str.size()); } + const std::string& Value() const { return value_; } + + friend void AbslFormatFlush(UserDefinedType* x, absl::string_view str) { + x->Append(str); + } + + private: + std::string value_; +}; +} // namespace my_namespace namespace { @@ -63,4 +81,21 @@ TEST(FormatExtensionTest, SinkAppendChars) { EXPECT_EQ(actual, expected); } } + +TEST(FormatExtensionTest, CordSink) { + absl::Cord c; + absl::Format(&c, "There were %04d little %s.", 3, "pigs"); + EXPECT_EQ(c, "There were 0003 little pigs."); + absl::Format(&c, "And %-3llx bad wolf!", 1); + EXPECT_EQ(c, "There were 0003 little pigs.And 1 bad wolf!"); +} + +TEST(FormatExtensionTest, CustomSink) { + my_namespace::UserDefinedType sink; + absl::Format(&sink, "There were %04d little %s.", 3, "pigs"); + EXPECT_EQ("There were 0003 little pigs.", sink.Value()); + absl::Format(&sink, "And %-3llx bad wolf!", 1); + EXPECT_EQ("There were 0003 little pigs.And 1 bad wolf!", sink.Value()); +} + } // namespace diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h index 28b288b7dde3..c3168d208590 100644 --- a/absl/strings/internal/str_format/output.h +++ b/absl/strings/internal/str_format/output.h @@ -91,10 +91,11 @@ inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { sink->Write(v); } +// This is a SFINAE to get a better compiler error message when the type +// is not supported. template <typename T> -auto InvokeFlush(T* out, string_view s) - -> decltype(str_format_internal::AbslFormatFlush(out, s)) { - str_format_internal::AbslFormatFlush(out, s); +auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) { + AbslFormatFlush(out, s); } } // namespace str_format_internal diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc index e54e6f70a511..ce2e91a0bbe8 100644 --- a/absl/strings/internal/str_format/output_test.cc +++ b/absl/strings/internal/str_format/output_test.cc @@ -19,6 +19,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/cord.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -37,6 +38,12 @@ TEST(InvokeFlush, Stream) { EXPECT_EQ(str.str(), "ABCDEF"); } +TEST(InvokeFlush, Cord) { + absl::Cord str("ABC"); + str_format_internal::InvokeFlush(&str, "DEF"); + EXPECT_EQ(str, "ABCDEF"); +} + TEST(BufferRawSink, Limits) { char buf[16]; { @@ -70,4 +77,3 @@ TEST(BufferRawSink, Limits) { } // namespace ABSL_NAMESPACE_END } // namespace absl - diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index d40fca114be3..2e0b33f7e558 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -57,8 +57,7 @@ // arbitrary sink types: // // * A generic `Format()` function to write outputs to arbitrary sink types, -// which must implement a `RawSinkFormat` interface. (See -// `str_format_sink.h` for more information.) +// which must implement a `FormatRawSink` interface. // // * A `FormatUntyped()` function that is similar to `Format()` except it is // loosely typed. `FormatUntyped()` is not a template and does not perform @@ -432,6 +431,16 @@ int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, // // FormatRawSink is a type erased wrapper around arbitrary sink objects // specifically used as an argument to `Format()`. +// +// All the object has to do define an overload of `AbslFormatFlush()` for the +// sink, usually by adding a ADL-based free function in the same namespace as +// the sink: +// +// void AbslFormatFlush(MySink* dest, absl::string_view part); +// +// where `dest` is the pointer passed to `absl::Format()`. The function should +// append `part` to `dest`. +// // FormatRawSink does not own the passed sink object. The passed object must // outlive the FormatRawSink. class FormatRawSink { @@ -455,12 +464,13 @@ class FormatRawSink { // `absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // -// By default, `std::string` and `std::ostream` are supported as destination -// objects. If a `std::string` is used the formatted string is appended to it. +// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as +// destination objects. If a `std::string` is used the formatted string is +// appended to it. // -// `absl::Format()` is a generic version of `absl::StrFormat(), for custom -// sinks. The format string, like format strings for `StrFormat()`, is checked -// at compile-time. +// `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for +// custom sinks. The format string, like format strings for `StrFormat()`, is +// checked at compile-time. // // On failure, this function returns `false` and the state of the sink is // unspecified. |