diff options
author | asynts <asynts@gmail.com> | 2020-10-07 14:01:59 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-10-08 09:59:55 +0200 |
commit | 2217d6b560d9030d66259f5b0feb292d5e515cff (patch) | |
tree | ad7ae097e5b06d0329c856c3d800ac63d1b9ee50 | |
parent | afef05ece2f878e95fd5dc678710c06b60c8c459 (diff) | |
download | serenity-2217d6b560d9030d66259f5b0feb292d5e515cff.zip |
AK+Format: Add SFINAE wrapper 'FormatIfSupported'.
-rw-r--r-- | AK/Format.h | 44 | ||||
-rw-r--r-- | AK/Tests/TestFormat.cpp | 18 |
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) |