123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*
- * Copyright (c) 2020, the SerenityOS developers.
- * 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.
- */
- #pragma once
- #include <AK/Array.h>
- #include <AK/GenericLexer.h>
- #include <AK/StringView.h>
- // FIXME: I would really love to merge the format_value and make_type_erased_parameters functions,
- // but the compiler creates weird error messages when I do that. Here is a small snippet that
- // reproduces the issue: https://godbolt.org/z/o55crs
- namespace AK {
- class TypeErasedFormatParams;
- class FormatParser;
- class FormatBuilder;
- template<typename T, typename = void>
- struct Formatter;
- constexpr size_t max_format_arguments = 256;
- struct TypeErasedParameter {
- enum class Type {
- UInt8,
- UInt16,
- UInt32,
- UInt64,
- Int8,
- Int16,
- Int32,
- Int64,
- Custom
- };
- template<typename T>
- static Type get_type()
- {
- if (IsSame<T, u8>::value)
- return Type::UInt8;
- if (IsSame<T, u16>::value)
- return Type::UInt16;
- if (IsSame<T, u32>::value)
- return Type::UInt32;
- if (IsSame<T, u64>::value)
- return Type::UInt64;
- if (IsSame<T, i8>::value)
- return Type::Int8;
- if (IsSame<T, i16>::value)
- return Type::Int16;
- if (IsSame<T, i32>::value)
- return Type::Int32;
- if (IsSame<T, i64>::value)
- return Type::Int64;
- return Type::Custom;
- }
- const void* value;
- Type type;
- void (*formatter)(TypeErasedFormatParams&, FormatBuilder&, FormatParser&, const void* value);
- };
- class FormatParser : public GenericLexer {
- public:
- struct FormatSpecifier {
- StringView flags;
- size_t index;
- };
- explicit FormatParser(StringView input);
- StringView consume_literal();
- bool consume_number(size_t& value);
- bool consume_specifier(FormatSpecifier& specifier);
- bool consume_replacement_field(size_t& index);
- };
- class FormatBuilder {
- public:
- enum class Align {
- Default,
- Left,
- Center,
- Right,
- };
- enum class SignMode {
- OnlyIfNeeded,
- Always,
- Reserved,
- Default = OnlyIfNeeded,
- };
- explicit FormatBuilder(StringBuilder& builder)
- : m_builder(builder)
- {
- }
- void put_padding(char fill, size_t amount);
- void put_literal(StringView value);
- void put_string(
- StringView value,
- Align align = Align::Left,
- size_t min_width = 0,
- size_t max_width = NumericLimits<size_t>::max(),
- char fill = ' ');
- void put_u64(
- u64 value,
- u8 base = 10,
- bool prefix = false,
- bool upper_case = false,
- bool zero_pad = false,
- Align align = Align::Right,
- size_t min_width = 0,
- char fill = ' ',
- SignMode sign_mode = SignMode::OnlyIfNeeded,
- bool is_negative = false);
- void put_i64(
- i64 value,
- u8 base = 10,
- bool prefix = false,
- bool upper_case = false,
- bool zero_pad = false,
- Align align = Align::Right,
- size_t min_width = 0,
- char fill = ' ',
- SignMode sign_mode = SignMode::OnlyIfNeeded);
- const StringBuilder& builder() const { return m_builder; }
- StringBuilder& builder() { return m_builder; }
- private:
- StringBuilder& m_builder;
- };
- class TypeErasedFormatParams {
- public:
- explicit TypeErasedFormatParams(Span<const TypeErasedParameter> parameters)
- : m_parameters(parameters)
- {
- }
- Span<const TypeErasedParameter> parameters() const { return m_parameters; }
- size_t take_next_index() { return m_next_index++; }
- size_t decode(size_t value, size_t default_value = 0);
- private:
- Span<const TypeErasedParameter> m_parameters;
- size_t m_next_index { 0 };
- };
- template<typename T>
- void __format_value(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser, const void* value)
- {
- Formatter<T> formatter;
- formatter.parse(params, parser);
- formatter.format(params, builder, *static_cast<const T*>(value));
- }
- template<typename... Parameters>
- class VariadicFormatParams : public TypeErasedFormatParams {
- public:
- static_assert(sizeof...(Parameters) <= max_format_arguments);
- explicit VariadicFormatParams(const Parameters&... parameters)
- : TypeErasedFormatParams(m_data)
- , m_data({ TypeErasedParameter { ¶meters, TypeErasedParameter::get_type<Parameters>(), __format_value<Parameters> }... })
- {
- }
- private:
- Array<TypeErasedParameter, sizeof...(Parameters)> m_data;
- };
- // We use the same format for most types for consistency. This is taken directly from std::format.
- // Not all valid options do anything yet.
- // https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
- struct StandardFormatter {
- enum class Mode {
- Default,
- Binary,
- BinaryUppercase,
- Decimal,
- Octal,
- Hexadecimal,
- HexadecimalUppercase,
- Character,
- String,
- Pointer,
- };
- static constexpr size_t value_not_set = NumericLimits<size_t>::max();
- static constexpr size_t value_from_next_arg = NumericLimits<size_t>::max() - 1;
- static constexpr size_t value_from_arg = NumericLimits<size_t>::max() - max_format_arguments - 2;
- FormatBuilder::Align m_align = FormatBuilder::Align::Default;
- FormatBuilder::SignMode m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
- Mode m_mode = Mode::Default;
- bool m_alternative_form = false;
- char m_fill = ' ';
- bool m_zero_pad = false;
- size_t m_width = value_not_set;
- size_t m_precision = value_not_set;
- void parse(TypeErasedFormatParams&, FormatParser&);
- };
- template<>
- struct Formatter<StringView> : StandardFormatter {
- Formatter() { }
- explicit Formatter(StandardFormatter formatter)
- : StandardFormatter(formatter)
- {
- }
- void format(TypeErasedFormatParams&, FormatBuilder&, StringView value);
- };
- template<>
- struct Formatter<const char*> : Formatter<StringView> {
- };
- template<>
- struct Formatter<char*> : Formatter<StringView> {
- };
- template<size_t Size>
- struct Formatter<char[Size]> : Formatter<StringView> {
- };
- template<>
- struct Formatter<String> : Formatter<StringView> {
- };
- template<>
- struct Formatter<FlyString> : Formatter<StringView> {
- };
- template<typename T>
- struct Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type> : StandardFormatter {
- Formatter() { }
- explicit Formatter(StandardFormatter formatter)
- : StandardFormatter(formatter)
- {
- }
- void format(TypeErasedFormatParams&, FormatBuilder&, T value);
- };
- template<typename T>
- struct Formatter<T*> : StandardFormatter {
- void format(TypeErasedFormatParams& params, FormatBuilder& builder, T* value)
- {
- Formatter<FlatPtr> formatter { *this };
- formatter.format(params, builder, reinterpret_cast<FlatPtr>(value));
- }
- };
- template<>
- struct Formatter<char> : Formatter<StringView> {
- void format(TypeErasedFormatParams& params, FormatBuilder& builder, char value)
- {
- Formatter<StringView>::format(params, builder, { &value, 1 });
- }
- };
- template<>
- struct Formatter<bool> : StandardFormatter {
- void format(TypeErasedFormatParams&, FormatBuilder&, bool value);
- };
- void vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams);
- void vformat(const LogStream& stream, StringView fmtstr, TypeErasedFormatParams);
- #ifndef KERNEL
- void vout(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
- void raw_out(StringView string);
- // FIXME: Rename this function to 'out' when that name becomes avaliable.
- template<typename... Parameters>
- void new_out(StringView fmtstr, const Parameters&... parameters) { vout(fmtstr, VariadicFormatParams { parameters... }); }
- template<typename... Parameters>
- void outln(StringView fmtstr, const Parameters&... parameters) { vout(fmtstr, VariadicFormatParams { parameters... }, true); }
- void vwarn(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
- void raw_warn(StringView string);
- // FIXME: Rename this function to 'warn' when that name becomes avaliable.
- template<typename... Parameters>
- void new_warn(StringView fmtstr, const Parameters&... parameters) { vwarn(fmtstr, VariadicFormatParams { parameters... }); }
- template<typename... Parameters>
- void warnln(StringView fmtstr, const Parameters&... parameters) { vwarn(fmtstr, VariadicFormatParams { parameters... }, true); }
- #endif
- void vdbg(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
- void raw_dbg(StringView string);
- // FIXME: Rename this function to 'dbg' when that name becomes avaliable.
- template<typename... Parameters>
- void new_dbg(StringView fmtstr, const Parameters&... parameters) { vdbg(fmtstr, VariadicFormatParams { parameters... }); }
- template<typename... Parameters>
- void dbgln(StringView fmtstr, const Parameters&... parameters) { vdbg(fmtstr, VariadicFormatParams { parameters... }, true); }
- } // namespace AK
- #ifndef KERNEL
- using AK::new_out;
- using AK::outln;
- using AK::raw_out;
- using AK::new_warn;
- using AK::raw_warn;
- using AK::warnln;
- #endif
- using AK::dbgln;
- using AK::new_dbg;
- using AK::raw_dbg;
|