AK: Add Formatter<FormatString> as helper class.

This commit is contained in:
asynts 2021-01-09 01:00:22 +01:00 committed by Andreas Kling
parent 9a842ec419
commit 1160817a9e
13 changed files with 64 additions and 94 deletions

View file

@ -521,6 +521,11 @@ void Formatter<StringView>::format(FormatBuilder& builder, StringView value)
builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill);
}
void Formatter<FormatString>::vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams params)
{
return Formatter<String>::format(builder, String::vformatted(fmtstr, params));
}
template<typename T>
void Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type>::format(FormatBuilder& builder, T value)
{

View file

@ -359,7 +359,7 @@ struct Formatter<std::nullptr_t> : Formatter<FlatPtr> {
}
};
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<typename T>
struct Formatter<FormatIfSupported<T>> : __FormatIfSupported<T, HasFormatter<T>::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<FormatString> : Formatter<String> {
template<typename... Parameters>
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;

View file

@ -274,4 +274,20 @@ TEST_CASE(format_nullptr)
EXPECT_EQ(String::formatted("{}", nullptr), String::formatted("{:p}", static_cast<FlatPtr>(0)));
}
struct C {
int i;
};
template<>
struct AK::Formatter<C> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, C c)
{
return AK::Formatter<FormatString>::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)

View file

@ -206,7 +206,6 @@ set(KERNEL_SOURCES
VM/Region.cpp
VM/SharedInodeVMObject.cpp
VM/VMObject.cpp
VirtualAddress.cpp
WaitQueue.cpp
init.cpp
kprintf.cpp

View file

@ -1,36 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/String.h>
#include <Kernel/VirtualAddress.h>
namespace AK {
void Formatter<VirtualAddress>::format(FormatBuilder& builder, const VirtualAddress& value)
{
Formatter<StringView>::format(builder, String::formatted("V{:p}", value.get()));
}
}

View file

@ -76,11 +76,10 @@ inline const LogStream& operator<<(const LogStream& stream, VirtualAddress value
return stream << 'V' << value.as_ptr();
}
namespace AK {
template<>
struct Formatter<VirtualAddress> : Formatter<StringView> {
void format(FormatBuilder&, const VirtualAddress&);
struct AK::Formatter<VirtualAddress> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const VirtualAddress& value)
{
return AK::Formatter<FormatString>::format(builder, "V{}", value.as_ptr());
}
};
}

View file

@ -268,12 +268,3 @@ const LogStream& operator<<(const LogStream& stream, const Object& object)
}
}
namespace AK {
void Formatter<Core::Object>::format(FormatBuilder& builder, const Core::Object& value)
{
Formatter<StringView>::format(builder, String::formatted("{}({})", value.class_name(), &value));
}
}

View file

@ -173,12 +173,13 @@ private:
}
namespace AK {
template<>
struct Formatter<Core::Object> : Formatter<StringView> {
void format(FormatBuilder&, const Core::Object&);
struct AK::Formatter<Core::Object> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const Core::Object& value)
{
return AK::Formatter<FormatString>::format(builder, "{}({})", value.class_name(), &value);
}
};
}
namespace Core {
template<typename T, typename Callback>

View file

@ -47,17 +47,3 @@ const LogStream& operator<<(const LogStream& stream, const ModelIndex& value)
}
}
namespace AK {
void Formatter<GUI::ModelIndex>::format(FormatBuilder& builder, const GUI::ModelIndex& value)
{
Formatter<StringView> 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()));
}
}

View file

@ -82,8 +82,14 @@ const LogStream& operator<<(const LogStream&, const ModelIndex&);
namespace AK {
template<>
struct Formatter<GUI::ModelIndex> : Formatter<StringView> {
void format(FormatBuilder&, const GUI::ModelIndex&);
struct Formatter<GUI::ModelIndex> : Formatter<FormatString> {
void format(FormatBuilder& builder, const GUI::ModelIndex& value)
{
if (value.internal_data())
return Formatter<FormatString>::format(builder, "ModelIndex({},{},{})", value.row(), value.column(), value.internal_data());
else
return Formatter<FormatString>::format(builder, "ModelIndex({},{})", value.row(), value.column());
}
};
template<>

View file

@ -66,17 +66,13 @@ inline const LogStream& operator<<(const LogStream& stream, const TextPosition&
}
namespace AK {
template<>
struct Formatter<GUI::TextPosition> : Formatter<StringView> {
struct AK::Formatter<GUI::TextPosition> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const GUI::TextPosition& value)
{
if (value.is_valid())
Formatter<StringView>::format(builder, String::formatted("({},{})", value.line(), value.column()));
Formatter<FormatString>::format(builder, "({},{})", value.line(), value.column());
else
Formatter<StringView>::format(builder, "GUI::TextPosition(Invalid)");
Formatter<FormatString>::format(builder, "GUI::TextPosition(Invalid)");
}
};
}

View file

@ -94,17 +94,13 @@ inline const LogStream& operator<<(const LogStream& stream, const TextRange& val
}
namespace AK {
template<>
struct Formatter<GUI::TextRange> : Formatter<StringView> {
struct AK::Formatter<GUI::TextRange> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const GUI::TextRange& value)
{
if (value.is_valid())
Formatter<StringView>::format(builder, String::formatted("{}-{}", value.start(), value.end()));
return Formatter<FormatString>::format(builder, "{}-{}", value.start(), value.end());
else
Formatter<StringView>::format(builder, "GUI::TextRange(Invalid)");
return Formatter<FormatString>::format(builder, "GUI::TextRange(Invalid)");
}
};
}

View file

@ -75,17 +75,13 @@ private:
}
namespace AK {
template<>
struct Formatter<JS::Cell> : Formatter<StringView> {
struct AK::Formatter<JS::Cell> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const JS::Cell* cell)
{
if (!cell)
Formatter<StringView>::format(builder, "Cell{nullptr}");
Formatter<FormatString>::format(builder, "Cell{nullptr}");
else
Formatter<StringView>::format(builder, String::formatted("{}{{{}}}", cell->class_name(), static_cast<const void*>(cell)));
Formatter<FormatString>::format(builder, "{}({})", cell->class_name(), cell);
}
};
}