From 2f12246a9807ba0d65bfcabc10539be24428d18f Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Sat, 8 Jan 2022 18:41:34 +0100 Subject: Simplify runtime implementation --- include/cxxformat/runtime.hpp | 120 +++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/include/cxxformat/runtime.hpp b/include/cxxformat/runtime.hpp index 23f2b96..3bfe7fe 100644 --- a/include/cxxformat/runtime.hpp +++ b/include/cxxformat/runtime.hpp @@ -15,15 +15,43 @@ namespace format { std::vector> parts; std::size_t argCount; + template + struct argument_formatter { + virtual void format(const Out& out, format_specifier spec, optional_int minWidth, optional_int precision) = 0; + virtual void conversionSupported(format_specifier spec) = 0; + virtual ~argument_formatter() = default; + }; + + template + class argument_formatter_for : public argument_formatter { + Arg&& arg; + + using formatter = formatter_with_fallback>; + + public: + argument_formatter_for(Arg&& arg) : arg{std::forward(arg)} {} + + void format(const Out& out, format_specifier spec, optional_int minWidth, optional_int precision) override + { + formatter::format(out, arg, spec, minWidth, precision); + } + + void conversionSupported(format_specifier spec) override + { + formatter::conversionSupported(spec); + } + }; + public: format_template(std::vector>&& parts, std::size_t argCount) noexcept : parts{std::move(parts)}, argCount{argCount} {} template requires (has_some_formatter> && ...) void operator()(Output&& output, Args&&... args) const { - checkArgCount(sizeof...(Args)); + constexpr auto passedArgCount = sizeof...(Args); + checkArgCount(passedArgCount); - std::array, sizeof...(Args)> indexArgs{[](Arg&& arg) constexpr -> optional_int { + std::array, passedArgCount> indexArgs{[](Arg&& arg) constexpr -> optional_int { if constexpr (std::unsigned_integral && sizeof(Arg) <= sizeof(std::size_t)) { return static_cast(arg); @@ -34,69 +62,53 @@ namespace format { } }(std::forward(args))...}; - const auto checkPart = [&args..., &indexArgs](std::index_sequence) - { - return [&args..., &indexArgs](format_specifier spec) - { - ([spec, &indexArgs](Arg&&, std::size_t index) - { - if (index == spec.argIndex) - { - if (spec.flags.widthAsArg) - { - if (!indexArgs[*spec.minWidth]) - { - throw std::invalid_argument{"Width argument must be an unsigned integral at most as big as std::size_t"}; - } - } - if (spec.flags.precisionAsArg) - { - if (!indexArgs[*spec.precision]) - { - throw std::invalid_argument{"Precision argument must be an unsigned integral at most as big as std::size_t"}; - } - } - formatter_with_fallback>::conversionSupported(spec); - } - }(std::forward(args), indices), ...); - }; - }(std::make_index_sequence()); + const auto out = make_output(std::forward(output)); + using Out = decltype(out); + + std::array>, passedArgCount> argFormatters{[](Arg&& arg) { + return std::unique_ptr>{new argument_formatter_for{std::forward(arg)}}; + }(std::forward(args))...}; for (const auto& part : parts) { if (std::holds_alternative(part)) { - checkPart(std::get(part)); + const auto spec = std::get(part); + if (spec.flags.widthAsArg) + { + if (!indexArgs[*spec.minWidth]) + { + throw std::invalid_argument{"Width argument must be an unsigned integral at most as big as std::size_t"}; + } + } + if (spec.flags.precisionAsArg) + { + if (!indexArgs[*spec.precision]) + { + throw std::invalid_argument{"Precision argument must be an unsigned integral at most as big as std::size_t"}; + } + } + argFormatters[spec.argIndex]->conversionSupported(spec); } } - const auto out = make_output(std::forward(output)); const overloaded_callable visitor{ - [&args..., &out, &indexArgs](std::index_sequence) + [&out, &indexArgs, &argFormatters](format_specifier spec) { - return [&args..., &out, &indexArgs](format_specifier spec) + optional_int minWidth = spec.minWidth; + if (spec.flags.widthAsArg) { - ([&out, spec, &indexArgs](Arg&& arg, std::size_t index) - { - if (index == spec.argIndex) - { - optional_int minWidth = spec.minWidth; - if (spec.flags.widthAsArg) - { - minWidth = indexArgs[*minWidth]; - assert(minWidth); - } - optional_int precision = spec.precision; - if (spec.flags.precisionAsArg) - { - precision = indexArgs[*precision]; - assert(precision); - } - return formatter_with_fallback>::format(out, std::forward(arg), spec, minWidth, precision); - } - }(std::forward(args), indices), ...); - }; - }(std::make_index_sequence()), + minWidth = indexArgs[*minWidth]; + assert(minWidth); + } + optional_int precision = spec.precision; + if (spec.flags.precisionAsArg) + { + precision = indexArgs[*precision]; + assert(precision); + } + return argFormatters[spec.argIndex]->format(out, spec, minWidth, precision); + }, [&out](std::string text) { out(text); } }; for (const auto& part : parts) -- cgit v1.2.3-54-g00ecf