summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorasynts <asynts@gmail.com>2020-10-07 14:01:59 +0200
committerAndreas Kling <kling@serenityos.org>2020-10-08 09:59:55 +0200
commit2217d6b560d9030d66259f5b0feb292d5e515cff (patch)
treead7ae097e5b06d0329c856c3d800ac63d1b9ee50
parentafef05ece2f878e95fd5dc678710c06b60c8c459 (diff)
downloadserenity-2217d6b560d9030d66259f5b0feb292d5e515cff.zip
AK+Format: Add SFINAE wrapper 'FormatIfSupported'.
-rw-r--r--AK/Format.h44
-rw-r--r--AK/Tests/TestFormat.cpp18
2 files changed, 61 insertions, 1 deletions
diff --git a/AK/Format.h b/AK/Format.h
index cb8d31c39e..d66e9b607c 100644
--- a/AK/Format.h
+++ b/AK/Format.h
@@ -41,7 +41,9 @@ class FormatParser;
class FormatBuilder;
template<typename T, typename = void>
-struct Formatter;
+struct Formatter {
+ using __no_formatter_defined = void;
+};
constexpr size_t max_format_arguments = 256;
@@ -346,6 +348,44 @@ template<typename... Parameters>
void dbgln(const char* fmtstr, const Parameters&... parameters) { dbgln(StringView { fmtstr }, parameters...); }
inline void dbgln() { raw_dbg("\n"); }
+template<typename T, typename = void>
+struct HasFormatter : TrueType {
+};
+template<typename T>
+struct HasFormatter<T, typename Formatter<T>::__no_formatter_defined> : FalseType {
+};
+
+template<typename T>
+class FormatIfSupported {
+public:
+ explicit FormatIfSupported(const T& value)
+ : m_value(value)
+ {
+ }
+
+ const T& value() const { return m_value; }
+
+private:
+ const T& m_value;
+};
+template<typename T, bool Supported = false>
+struct __FormatIfSupported : Formatter<StringView> {
+ void format(TypeErasedFormatParams& params, FormatBuilder& builder, const FormatIfSupported<T>&)
+ {
+ Formatter<StringView>::format(params, builder, "?");
+ }
+};
+template<typename T>
+struct __FormatIfSupported<T, true> : Formatter<T> {
+ void format(TypeErasedFormatParams& params, FormatBuilder& builder, const FormatIfSupported<T>& value)
+ {
+ Formatter<T>::format(params, builder, value.value());
+ }
+};
+template<typename T>
+struct Formatter<FormatIfSupported<T>> : __FormatIfSupported<T, HasFormatter<T>::value> {
+};
+
} // namespace AK
#ifndef KERNEL
@@ -361,3 +401,5 @@ using AK::warnln;
using AK::dbgln;
using AK::new_dbg;
using AK::raw_dbg;
+
+using AK::FormatIfSupported;
diff --git a/AK/Tests/TestFormat.cpp b/AK/Tests/TestFormat.cpp
index 0e7e9aae6a..7d426fb4e1 100644
--- a/AK/Tests/TestFormat.cpp
+++ b/AK/Tests/TestFormat.cpp
@@ -196,4 +196,22 @@ TEST_CASE(format_character)
EXPECT_EQ(String::formatted("{}", true ? a : 'b'), "a");
}
+struct A {
+};
+struct B {
+};
+template<>
+struct AK::Formatter<B> : Formatter<StringView> {
+ void format(TypeErasedFormatParams& params, FormatBuilder& builder, B)
+ {
+ Formatter<StringView>::format(params, builder, "B");
+ }
+};
+
+TEST_CASE(format_if_supported)
+{
+ EXPECT_EQ(String::formatted("{}", FormatIfSupported { A {} }), "?");
+ EXPECT_EQ(String::formatted("{}", FormatIfSupported { B {} }), "B");
+}
+
TEST_MAIN(Format)