#pragma once #include "asl/integers.hpp" #include "asl/meta.hpp" #include "asl/io.hpp" #include "asl/span.hpp" #include "asl/string_view.hpp" namespace asl { class Formatter; template concept formattable = requires (Formatter& f, const T& value) { AslFormat(f, value); }; namespace format_internals { struct type_erased_arg { const void* data; void (*fn)(Formatter&, const void*); template static constexpr void erased_fn(Formatter& f, const void* data) { AslFormat(f, *reinterpret_cast(data)); } template explicit constexpr type_erased_arg(const T& arg) : data{&arg} , fn{erased_fn} {} }; void format(Writer*, string_view fmt, span args); } // namespace internals class Formatter { Writer* m_writer; public: explicit constexpr Formatter(Writer* writer) : m_writer{writer} {} constexpr void write(string_view s) { m_writer->write(as_bytes(s.as_span())); } }; template void format(Writer* w, string_view fmt, const Args&... args) { if constexpr (types_count > 0) { format_internals::type_erased_arg type_erased_args[] = { format_internals::type_erased_arg(args)... }; format_internals::format(w, fmt, type_erased_args); } else { format_internals::format(w, fmt, {}); } } template void AslFormat(Formatter& f, const char (&str)[N]) { f.write(str, N - 1); } void AslFormat(Formatter& f, const char* str); void AslFormat(Formatter& f, float); void AslFormat(Formatter& f, double); void AslFormat(Formatter& f, bool); void AslFormat(Formatter& f, uint8_t); void AslFormat(Formatter& f, uint16_t); void AslFormat(Formatter& f, uint32_t); void AslFormat(Formatter& f, uint64_t); void AslFormat(Formatter& f, int8_t); void AslFormat(Formatter& f, int16_t); void AslFormat(Formatter& f, int32_t); void AslFormat(Formatter& f, int64_t); } // namespace asl