diff --git a/AK/Format.cpp b/AK/Format.cpp index 14ed0459dd8..0132807ed41 100644 --- a/AK/Format.cpp +++ b/AK/Format.cpp @@ -521,6 +521,11 @@ void Formatter::format(FormatBuilder& builder, StringView value) builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill); } +void Formatter::vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams params) +{ + return Formatter::format(builder, String::vformatted(fmtstr, params)); +} + template void Formatter::value>::Type>::format(FormatBuilder& builder, T value) { diff --git a/AK/Format.h b/AK/Format.h index 90030765eca..63b1d3fab2c 100644 --- a/AK/Format.h +++ b/AK/Format.h @@ -359,7 +359,7 @@ struct Formatter : Formatter { } }; -void vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams); +void vformat(StringBuilder&, StringView fmtstr, TypeErasedFormatParams); void vformat(const LogStream& stream, StringView fmtstr, TypeErasedFormatParams); #ifndef KERNEL @@ -435,6 +435,20 @@ template struct Formatter> : __FormatIfSupported::value> { }; +// This is a helper class, the idea is that if you want to implement a formatter you can inherit +// from this class to "break down" the formatting. +struct FormatString { +}; +template<> +struct Formatter : Formatter { + template + void format(FormatBuilder& builder, StringView fmtstr, const Parameters&... parameters) + { + vformat(builder, fmtstr, VariadicFormatParams { parameters... }); + } + void vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams params); +}; + } // namespace AK #ifndef KERNEL @@ -448,3 +462,4 @@ using AK::warnln; using AK::dbgln; using AK::FormatIfSupported; +using AK::FormatString; diff --git a/AK/Tests/TestFormat.cpp b/AK/Tests/TestFormat.cpp index cfe7fe29504..609582b6ae6 100644 --- a/AK/Tests/TestFormat.cpp +++ b/AK/Tests/TestFormat.cpp @@ -274,4 +274,20 @@ TEST_CASE(format_nullptr) EXPECT_EQ(String::formatted("{}", nullptr), String::formatted("{:p}", static_cast(0))); } +struct C { + int i; +}; +template<> +struct AK::Formatter : AK::Formatter { + void format(FormatBuilder& builder, C c) + { + return AK::Formatter::format(builder, "C(i={})", c.i); + } +}; + +TEST_CASE(use_format_string_formatter) +{ + EXPECT_EQ(String::formatted("{:*<10}", C { 42 }), "C(i=42)***"); +} + TEST_MAIN(Format) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 8a3bdcaf1e7..5b1c8b11f33 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -206,7 +206,6 @@ set(KERNEL_SOURCES VM/Region.cpp VM/SharedInodeVMObject.cpp VM/VMObject.cpp - VirtualAddress.cpp WaitQueue.cpp init.cpp kprintf.cpp diff --git a/Kernel/VirtualAddress.cpp b/Kernel/VirtualAddress.cpp deleted file mode 100644 index 945cc0e99c3..00000000000 --- a/Kernel/VirtualAddress.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -namespace AK { -void Formatter::format(FormatBuilder& builder, const VirtualAddress& value) -{ - Formatter::format(builder, String::formatted("V{:p}", value.get())); -} - -} diff --git a/Kernel/VirtualAddress.h b/Kernel/VirtualAddress.h index 3a0fa6691fb..78602aa8db7 100644 --- a/Kernel/VirtualAddress.h +++ b/Kernel/VirtualAddress.h @@ -76,11 +76,10 @@ inline const LogStream& operator<<(const LogStream& stream, VirtualAddress value return stream << 'V' << value.as_ptr(); } -namespace AK { - template<> -struct Formatter : Formatter { - void format(FormatBuilder&, const VirtualAddress&); +struct AK::Formatter : AK::Formatter { + void format(FormatBuilder& builder, const VirtualAddress& value) + { + return AK::Formatter::format(builder, "V{}", value.as_ptr()); + } }; - -} diff --git a/Libraries/LibCore/Object.cpp b/Libraries/LibCore/Object.cpp index 27d5985d006..cf16b4aadf0 100644 --- a/Libraries/LibCore/Object.cpp +++ b/Libraries/LibCore/Object.cpp @@ -268,12 +268,3 @@ const LogStream& operator<<(const LogStream& stream, const Object& object) } } - -namespace AK { - -void Formatter::format(FormatBuilder& builder, const Core::Object& value) -{ - Formatter::format(builder, String::formatted("{}({})", value.class_name(), &value)); -} - -} diff --git a/Libraries/LibCore/Object.h b/Libraries/LibCore/Object.h index f8e81743c63..ef568f84d55 100644 --- a/Libraries/LibCore/Object.h +++ b/Libraries/LibCore/Object.h @@ -173,12 +173,13 @@ private: } -namespace AK { template<> -struct Formatter : Formatter { - void format(FormatBuilder&, const Core::Object&); +struct AK::Formatter : AK::Formatter { + void format(FormatBuilder& builder, const Core::Object& value) + { + return AK::Formatter::format(builder, "{}({})", value.class_name(), &value); + } }; -} namespace Core { template diff --git a/Libraries/LibGUI/ModelIndex.cpp b/Libraries/LibGUI/ModelIndex.cpp index 6b87d4a70b7..ea6a97c28fd 100644 --- a/Libraries/LibGUI/ModelIndex.cpp +++ b/Libraries/LibGUI/ModelIndex.cpp @@ -47,17 +47,3 @@ const LogStream& operator<<(const LogStream& stream, const ModelIndex& value) } } - -namespace AK { - -void Formatter::format(FormatBuilder& builder, const GUI::ModelIndex& value) -{ - Formatter formatter { *this }; - - if (value.internal_data()) - formatter.format(builder, String::formatted("ModelIndex({},{},{:p})", value.row(), value.column(), value.internal_data())); - else - formatter.format(builder, String::formatted("ModelIndex({},{})", value.row(), value.column())); -} - -} diff --git a/Libraries/LibGUI/ModelIndex.h b/Libraries/LibGUI/ModelIndex.h index f0cf6a978cb..5f8e088798a 100644 --- a/Libraries/LibGUI/ModelIndex.h +++ b/Libraries/LibGUI/ModelIndex.h @@ -82,8 +82,14 @@ const LogStream& operator<<(const LogStream&, const ModelIndex&); namespace AK { template<> -struct Formatter : Formatter { - void format(FormatBuilder&, const GUI::ModelIndex&); +struct Formatter : Formatter { + void format(FormatBuilder& builder, const GUI::ModelIndex& value) + { + if (value.internal_data()) + return Formatter::format(builder, "ModelIndex({},{},{})", value.row(), value.column(), value.internal_data()); + else + return Formatter::format(builder, "ModelIndex({},{})", value.row(), value.column()); + } }; template<> diff --git a/Libraries/LibGUI/TextPosition.h b/Libraries/LibGUI/TextPosition.h index 8785341004e..47ccc71e47e 100644 --- a/Libraries/LibGUI/TextPosition.h +++ b/Libraries/LibGUI/TextPosition.h @@ -66,17 +66,13 @@ inline const LogStream& operator<<(const LogStream& stream, const TextPosition& } -namespace AK { - template<> -struct Formatter : Formatter { +struct AK::Formatter : AK::Formatter { void format(FormatBuilder& builder, const GUI::TextPosition& value) { if (value.is_valid()) - Formatter::format(builder, String::formatted("({},{})", value.line(), value.column())); + Formatter::format(builder, "({},{})", value.line(), value.column()); else - Formatter::format(builder, "GUI::TextPosition(Invalid)"); + Formatter::format(builder, "GUI::TextPosition(Invalid)"); } }; - -} diff --git a/Libraries/LibGUI/TextRange.h b/Libraries/LibGUI/TextRange.h index 4b10a4568f3..222edbca01f 100644 --- a/Libraries/LibGUI/TextRange.h +++ b/Libraries/LibGUI/TextRange.h @@ -94,17 +94,13 @@ inline const LogStream& operator<<(const LogStream& stream, const TextRange& val } -namespace AK { - template<> -struct Formatter : Formatter { +struct AK::Formatter : AK::Formatter { void format(FormatBuilder& builder, const GUI::TextRange& value) { if (value.is_valid()) - Formatter::format(builder, String::formatted("{}-{}", value.start(), value.end())); + return Formatter::format(builder, "{}-{}", value.start(), value.end()); else - Formatter::format(builder, "GUI::TextRange(Invalid)"); + return Formatter::format(builder, "GUI::TextRange(Invalid)"); } }; - -} diff --git a/Libraries/LibJS/Runtime/Cell.h b/Libraries/LibJS/Runtime/Cell.h index 0f1ff188603..df4a19f19a1 100644 --- a/Libraries/LibJS/Runtime/Cell.h +++ b/Libraries/LibJS/Runtime/Cell.h @@ -75,17 +75,13 @@ private: } -namespace AK { - template<> -struct Formatter : Formatter { +struct AK::Formatter : AK::Formatter { void format(FormatBuilder& builder, const JS::Cell* cell) { if (!cell) - Formatter::format(builder, "Cell{nullptr}"); + Formatter::format(builder, "Cell{nullptr}"); else - Formatter::format(builder, String::formatted("{}{{{}}}", cell->class_name(), static_cast(cell))); + Formatter::format(builder, "{}({})", cell->class_name(), cell); } }; - -}