diff options
| author | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-12 21:03:04 +0100 |
|---|---|---|
| committer | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-12 21:03:04 +0100 |
| commit | c8f7d6304f844b9c42dd2b154ff8d6f3de28abf8 (patch) | |
| tree | 16c51946790108e6d2e6a904b3a917b591b99de4 /include | |
| parent | 50e3689e7bd71c8d69693b3ec78e68ef34ffec96 (diff) | |
| download | cxxformat-c8f7d6304f844b9c42dd2b154ff8d6f3de28abf8.tar.gz cxxformat-c8f7d6304f844b9c42dd2b154ff8d6f3de28abf8.zip | |
Add autopad_formatter and use it for the nullptr formatter
Diffstat (limited to 'include')
| -rw-r--r-- | include/cxxformat/formatters.hpp | 92 |
1 files changed, 84 insertions, 8 deletions
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<typename Outputter> - constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, optional_int<std::size_t> 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<typename Outputter> + constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, optional_int<std::size_t> minWidth) + { + if (minWidth) + { + formatPadded(out, outputter, outputWidth, padding, leftJustified, *minWidth); + } + else + { + outputter(out); } } @@ -159,6 +172,67 @@ namespace format { } } + template<typename Output> + class autopad_output : public FormatOutputBase<autopad_output<Output>> { + 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<typename T, typename Derived, char padding = '\0'> + struct autopad_formatter { + template<typename U> + static constexpr void format(const format_output auto& out, U&& u, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) + { +#ifdef _NDEBUG + if (minWidth) + { + Derived::formatAutopad(autopad_output{out, *minWidth, spec.flags.leftJustified, padding_(spec)}, std::forward<U>(u), spec, precision); + } + else + { + Derived::formatAutopad(out, std::forward<U>(u), spec, precision); + } +#else + Derived::formatAutopad(autopad_output{out, minWidth.value_or(0), spec.flags.leftJustified, padding_(spec)}, std::forward<U>(u), spec, precision); +#endif + } + + private: + static constexpr char padding_([[maybe_unused]] format_specifier spec) noexcept + { + static_assert(std::derived_from<Derived, autopad_formatter<T, Derived, padding>>, "autopad_formatter must be used with CRTP"); + static_assert(requires(T t, autopad_output<NullOutput> o, optional_int<std::size_t> 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<std::size_t>)"); + + if constexpr (padding == '\0') + { + return spec.padding; + } + else + { + return padding; + } + } + }; + using invalid_argument = std::invalid_argument; template<std::integral T> @@ -629,10 +703,10 @@ namespace format { }; template<> - struct formatter<std::nullptr_t> { - static constexpr void format(const format_output auto& out, std::nullptr_t, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t>) + struct formatter<std::nullptr_t> : autopad_formatter<std::nullptr_t, formatter<std::nullptr_t>, ' '> { + static constexpr void formatAutopad(const format_output auto& out, std::nullptr_t, format_specifier, optional_int<std::size_t>) { - 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<std::nullptr_t>); + template<> struct formatter<const char*> { static constexpr void format(const format_output auto& out, const char* s, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) |
