diff options
| author | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-08 18:41:34 +0100 |
|---|---|---|
| committer | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-08 18:41:34 +0100 |
| commit | 2f12246a9807ba0d65bfcabc10539be24428d18f (patch) | |
| tree | 9721a424997c34faa09bb7a236ededbdd3a87793 /include | |
| parent | b1cd768aac3fcc686464c71fdc0582307c024cf0 (diff) | |
| download | cxxformat-2f12246a9807ba0d65bfcabc10539be24428d18f.tar.gz cxxformat-2f12246a9807ba0d65bfcabc10539be24428d18f.zip | |
Simplify runtime implementation
Diffstat (limited to 'include')
| -rw-r--r-- | include/cxxformat/runtime.hpp | 120 |
1 files changed, 66 insertions, 54 deletions
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<std::variant<std::string, format_specifier>> parts; std::size_t argCount; + template<typename Out> + struct argument_formatter { + virtual void format(const Out& out, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) = 0; + virtual void conversionSupported(format_specifier spec) = 0; + virtual ~argument_formatter() = default; + }; + + template<typename Out, typename Arg> + class argument_formatter_for : public argument_formatter<Out> { + Arg&& arg; + + using formatter = formatter_with_fallback<std::decay_t<Arg>>; + + public: + argument_formatter_for(Arg&& arg) : arg{std::forward<Arg>(arg)} {} + + void format(const Out& out, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) override + { + formatter::format(out, arg, spec, minWidth, precision); + } + + void conversionSupported(format_specifier spec) override + { + formatter::conversionSupported(spec); + } + }; + public: format_template(std::vector<std::variant<std::string, format_specifier>>&& parts, std::size_t argCount) noexcept : parts{std::move(parts)}, argCount{argCount} {} template<format_output_compatible Output, typename... Args> requires (has_some_formatter<std::decay_t<Args>> && ...) void operator()(Output&& output, Args&&... args) const { - checkArgCount(sizeof...(Args)); + constexpr auto passedArgCount = sizeof...(Args); + checkArgCount(passedArgCount); - std::array<optional_int<std::size_t>, sizeof...(Args)> indexArgs{[]<typename Arg>(Arg&& arg) constexpr -> optional_int<std::size_t> { + std::array<optional_int<std::size_t>, passedArgCount> indexArgs{[]<typename Arg>(Arg&& arg) constexpr -> optional_int<std::size_t> { if constexpr (std::unsigned_integral<Arg> && sizeof(Arg) <= sizeof(std::size_t)) { return static_cast<std::size_t>(arg); @@ -34,69 +62,53 @@ namespace format { } }(std::forward<Args>(args))...}; - const auto checkPart = [&args..., &indexArgs]<std::size_t... indices>(std::index_sequence<indices...>) - { - return [&args..., &indexArgs](format_specifier spec) - { - ([spec, &indexArgs]<typename Arg>(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<std::decay_t<Arg>>::conversionSupported(spec); - } - }(std::forward<Args>(args), indices), ...); - }; - }(std::make_index_sequence<sizeof...(Args)>()); + const auto out = make_output(std::forward<Output>(output)); + using Out = decltype(out); + + std::array<std::unique_ptr<argument_formatter<Out>>, passedArgCount> argFormatters{[]<typename Arg>(Arg&& arg) { + return std::unique_ptr<argument_formatter<Out>>{new argument_formatter_for<Out, Arg>{std::forward<Arg>(arg)}}; + }(std::forward<Args>(args))...}; for (const auto& part : parts) { if (std::holds_alternative<format_specifier>(part)) { - checkPart(std::get<format_specifier>(part)); + const auto spec = std::get<format_specifier>(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>(output)); const overloaded_callable visitor{ - [&args..., &out, &indexArgs]<std::size_t... indices>(std::index_sequence<indices...>) + [&out, &indexArgs, &argFormatters](format_specifier spec) { - return [&args..., &out, &indexArgs](format_specifier spec) + optional_int<std::size_t> minWidth = spec.minWidth; + if (spec.flags.widthAsArg) { - ([&out, spec, &indexArgs]<typename Arg>(Arg&& arg, std::size_t index) - { - if (index == spec.argIndex) - { - optional_int<std::size_t> minWidth = spec.minWidth; - if (spec.flags.widthAsArg) - { - minWidth = indexArgs[*minWidth]; - assert(minWidth); - } - optional_int<std::size_t> precision = spec.precision; - if (spec.flags.precisionAsArg) - { - precision = indexArgs[*precision]; - assert(precision); - } - return formatter_with_fallback<std::decay_t<Arg>>::format(out, std::forward<Arg>(arg), spec, minWidth, precision); - } - }(std::forward<Args>(args), indices), ...); - }; - }(std::make_index_sequence<sizeof...(Args)>()), + minWidth = indexArgs[*minWidth]; + assert(minWidth); + } + optional_int<std::size_t> 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) |
