about summary refs log tree commit diff
path: root/absl/strings
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/BUILD.bazel4
-rw-r--r--absl/strings/CMakeLists.txt4
-rw-r--r--absl/strings/internal/str_format/extension_test.cc37
-rw-r--r--absl/strings/internal/str_format/output.h7
-rw-r--r--absl/strings/internal/str_format/output_test.cc8
-rw-r--r--absl/strings/str_format.h24
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.