AK+Format: Add SFINAE wrapper 'FormatIfSupported'.

This commit is contained in:
asynts 2020-10-07 14:01:59 +02:00 committed by Andreas Kling
parent afef05ece2
commit 2217d6b560
2 changed files with 61 additions and 1 deletions

View file

@ -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;

View file

@ -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)