#pragma once #include "asl/integers.hpp" #include "asl/meta.hpp" #include "asl/io.hpp" #include "asl/span.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*, const char* fmt, span args); } // namespace internals class formatter { writer* m_writer; public: explicit constexpr formatter(writer* writer) : m_writer{writer} {} // @Todo Use string_view constexpr void write(const char* s, isize_t len) { m_writer->write(as_bytes(span(s, len))); } }; // @Todo Use string_view template void format(writer* w, const char* 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