From c8f7d6304f844b9c42dd2b154ff8d6f3de28abf8 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Wed, 12 Jan 2022 21:03:04 +0100 Subject: Add autopad_formatter and use it for the nullptr formatter --- include/cxxformat/formatters.hpp | 92 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/cxxformat/formatters.hpp b/include/cxxformat/formatters.hpp index 515d0ec..119f7ea 100644 --- a/include/cxxformat/formatters.hpp +++ b/include/cxxformat/formatters.hpp @@ -22,18 +22,31 @@ namespace format { } template - constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, optional_int minWidth) + constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, std::size_t minWidth) { - if(outputWidth < minWidth.value_or(0) && !leftJustified) + if (!leftJustified && outputWidth < minWidth) { - out(padding, *minWidth - outputWidth); + out(padding, minWidth - outputWidth); } outputter(out); - if(outputWidth < minWidth.value_or(0) && leftJustified) + if (leftJustified && outputWidth < minWidth) { - out(padding, *minWidth - outputWidth); + out(padding, minWidth - outputWidth); + } + } + + template + constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, optional_int minWidth) + { + if (minWidth) + { + formatPadded(out, outputter, outputWidth, padding, leftJustified, *minWidth); + } + else + { + outputter(out); } } @@ -159,6 +172,67 @@ namespace format { } } + template + class autopad_output : public FormatOutputBase> { + const Output& out; + std::size_t minWidth; + bool leftJustified; + char padding; +#ifndef _NDEBUG + mutable bool used{false}; +#endif + + public: + constexpr autopad_output(const Output& out, std::size_t minWidth, bool leftJustified, char padding) noexcept : out{out}, minWidth{minWidth}, leftJustified{leftJustified}, padding{padding} {} + + void output(std::string_view what) const + { +#ifndef _NDEBUG + assert(!used && "autopad_formatters must not call out() more than once for them to work correctly!"); + used = true; +#endif + + formatPadded(out, what, leftJustified, padding, minWidth); + } + }; + + // padding of '\0' means take from spec + template + struct autopad_formatter { + template + static constexpr void format(const format_output auto& out, U&& u, format_specifier spec, optional_int minWidth, optional_int precision) + { +#ifdef _NDEBUG + if (minWidth) + { + Derived::formatAutopad(autopad_output{out, *minWidth, spec.flags.leftJustified, padding_(spec)}, std::forward(u), spec, precision); + } + else + { + Derived::formatAutopad(out, std::forward(u), spec, precision); + } +#else + Derived::formatAutopad(autopad_output{out, minWidth.value_or(0), spec.flags.leftJustified, padding_(spec)}, std::forward(u), spec, precision); +#endif + } + + private: + static constexpr char padding_([[maybe_unused]] format_specifier spec) noexcept + { + static_assert(std::derived_from>, "autopad_formatter must be used with CRTP"); + static_assert(requires(T t, autopad_output o, optional_int p, format_specifier s) { Derived::formatAutopad(o, t, s, p); }, "The derived class must implement the static method formatAutopad(const format_output auto&, T-compatible, format_specifier, optional_int)"); + + if constexpr (padding == '\0') + { + return spec.padding; + } + else + { + return padding; + } + } + }; + using invalid_argument = std::invalid_argument; template @@ -629,10 +703,10 @@ namespace format { }; template<> - struct formatter { - static constexpr void format(const format_output auto& out, std::nullptr_t, format_specifier spec, optional_int minWidth, optional_int) + struct formatter : autopad_formatter, ' '> { + static constexpr void formatAutopad(const format_output auto& out, std::nullptr_t, format_specifier, optional_int) { - formatPadded(out, "(nil)", ' ', spec.flags.leftJustified, minWidth); + out("(nil)"); } static constexpr void conversionSupported(format_specifier spec) @@ -641,6 +715,8 @@ namespace format { } }; + static_assert(has_formatter); + template<> struct formatter { static constexpr void format(const format_output auto& out, const char* s, format_specifier spec, optional_int minWidth, optional_int precision) -- cgit v1.2.3-54-g00ecf