summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2022-09-28 11:33:29 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2022-09-28 11:35:00 -0700
commitf7404cd33f2457bd561fdcfbb024e43852c94bcf (patch)
treedd71ed565fe81f220984ffd9a531266c06a05ec2
parent6d9ea2b46f470406e1f49acc30b272c6e9f6cc5e (diff)
Allows absl::StrFormat to accept types which implement AbslStringify()
PiperOrigin-RevId: 477507777 Change-Id: I5ecde3163ca560ac8774034e55654774e36ad230
-rw-r--r--absl/strings/internal/str_format/arg.h34
-rw-r--r--absl/strings/str_format_test.cc19
2 files changed, 42 insertions, 11 deletions
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 2dfbf728..3d616dba 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -45,6 +45,11 @@ class FormatConversionSpec;
namespace str_format_internal {
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+ bool value;
+};
+
template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {};
@@ -71,6 +76,20 @@ auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
return AbslFormatConvert(v, fcs, &fs);
}
+void AbslStringify(); // Stops the lexical name lookup
+template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl,
+ FormatSinkImpl* sink)
+ -> std::enable_if_t<std::is_void<decltype(AbslStringify(
+ std::declval<FormatSink&>(), v))>::value,
+ ArgConvertResult<FormatConversionCharSetInternal::v>> {
+ using FormatSinkT =
+ absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+ auto fs = sink->Wrap<FormatSinkT>();
+ AbslStringify(fs, v);
+ return {true};
+}
+
template <typename T>
class StreamedWrapper;
@@ -96,11 +115,6 @@ struct VoidPtr {
};
template <FormatConversionCharSet C>
-struct ArgConvertResult {
- bool value;
-};
-
-template <FormatConversionCharSet C>
constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
return C;
}
@@ -316,11 +330,11 @@ struct FormatArgImplFriend {
template <typename Arg>
constexpr FormatConversionCharSet ArgumentToConv() {
- return absl::str_format_internal::ExtractCharSet(
- decltype(str_format_internal::FormatConvertImpl(
- std::declval<const Arg&>(),
- std::declval<const FormatConversionSpecImpl&>(),
- std::declval<FormatSinkImpl*>())){});
+ using ConvResult = decltype(str_format_internal::FormatConvertImpl(
+ std::declval<const Arg&>(),
+ std::declval<const FormatConversionSpecImpl&>(),
+ std::declval<FormatSinkImpl*>()));
+ return absl::str_format_internal::ExtractCharSet(ConvResult{});
}
// A type-erased handle to a format argument.
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 4b778056..0c4f10c8 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -1074,7 +1074,8 @@ using FormatExtensionTest = ::testing::Test;
struct Point {
friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
- absl::FormatConversionCharSet::kIntegral>
+ absl::FormatConversionCharSet::kIntegral |
+ absl::FormatConversionCharSet::v>
AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
if (spec.conversion_char() == absl::FormatConversionChar::s) {
@@ -1093,6 +1094,7 @@ TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
Point p;
EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
+ EXPECT_EQ(absl::StrFormat("a %v z", p), "a 10,20 z");
// Typed formatting will fail to compile an invalid format.
// StrFormat("%f", p); // Does not compile.
@@ -1101,6 +1103,21 @@ TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
// FormatUntyped will return false for bad character.
EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
}
+
+struct PointStringify {
+ template <typename FormatSink>
+ friend void AbslStringify(FormatSink& sink, const PointStringify& p) {
+ sink.Append(absl::StrCat("(", p.x, ", ", p.y, ")"));
+ }
+
+ double x = 10.0;
+ double y = 20.0;
+};
+
+TEST_F(FormatExtensionTest, AbslStringifyExample) {
+ PointStringify p;
+ EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
+}
} // namespace
// Some codegen thunks that we can use to easily dump the generated assembly for