From 50e3689e7bd71c8d69693b3ec78e68ef34ffec96 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Tue, 11 Jan 2022 20:17:34 +0100 Subject: Refactor out padded formatting in non-trivial cases --- include/cxxformat/formatters.hpp | 209 +++++++++++++++------------------------ 1 file changed, 82 insertions(+), 127 deletions(-) diff --git a/include/cxxformat/formatters.hpp b/include/cxxformat/formatters.hpp index 99f9f62..515d0ec 100644 --- a/include/cxxformat/formatters.hpp +++ b/include/cxxformat/formatters.hpp @@ -21,21 +21,27 @@ namespace format { return [](char c) constexpr noexcept { return std::string_view{what}.find(c) != std::string_view::npos; }; } - constexpr void formatPadded(const format_output auto& out, std::string_view subject, char padding, bool leftJustified, optional_int minWidth) + template + constexpr void formatPadded(const format_output auto& out, Outputter&& outputter, std::size_t outputWidth, char padding, bool leftJustified, optional_int minWidth) { - if(subject.length() < minWidth.value_or(0) && !leftJustified) + if(outputWidth < minWidth.value_or(0) && !leftJustified) { - out(padding, *minWidth - subject.length()); + out(padding, *minWidth - outputWidth); } - out(subject); + outputter(out); - if(subject.length() < minWidth.value_or(0) && leftJustified) + if(outputWidth < minWidth.value_or(0) && leftJustified) { - out(padding, *minWidth - subject.length()); + out(padding, *minWidth - outputWidth); } } + constexpr void formatPadded(const format_output auto& out, std::string_view subject, char padding, bool leftJustified, optional_int minWidth) + { + formatPadded(out, [subject](const auto& out){ out(subject); }, subject.size(), padding, leftJustified, minWidth); + } + constexpr void formatQuoteGrouped(const format_output auto& out, std::string_view subject, std::size_t leadingZeros, unsigned int grouping) { const auto quote = '\''; @@ -225,8 +231,9 @@ namespace format { prefix = {&signPrefix, 1}; } + const auto numSize = converted.size(); std::size_t precisionPadding{0}; - std::size_t normalPadding{0}; + const auto restSize = prefix.size(); if (precision) { if (*precision > converted.size()) @@ -236,8 +243,6 @@ namespace format { } else if (minWidth && spec.padding == '0') { - const auto numSize = converted.size(); - const auto restSize = prefix.size(); const auto totalLength = numSize + restSize + (quoteGrouping != 0 ? numSize / quoteGrouping : 0); if (*minWidth > totalLength) { @@ -254,40 +259,23 @@ namespace format { } } - if (minWidth) - { - const auto numSize = converted.size(); - const auto quoteSize = quoteGrouping != 0 ? ((numSize + precisionPadding - 1) / quoteGrouping) : 0; - const auto totalLength = numSize + precisionPadding + quoteSize + prefix.size(); - if (*minWidth > totalLength) - { - normalPadding = *minWidth - totalLength; - } - } - - const auto padding = precision ? ' ' : spec.padding; - if(!spec.flags.leftJustified) - { - out(padding, normalPadding); - } + const auto quoteSize = quoteGrouping != 0 ? ((numSize + precisionPadding - 1) / quoteGrouping) : 0; + const auto totalLength = numSize + precisionPadding + quoteSize + restSize; - out(prefix); - - if (quoteGrouping != 0) - { - formatQuoteGrouped(out, converted, precisionPadding, quoteGrouping); - } - else + formatPadded(out, [prefix, converted, precisionPadding, quoteGrouping](const auto& out) { - out('0', precisionPadding); - out(converted); - } + out(prefix); - if(spec.flags.leftJustified) - { - out(padding, normalPadding); - } - return; + if (quoteGrouping != 0) + { + formatQuoteGrouped(out, converted, precisionPadding, quoteGrouping); + } + else + { + out('0', precisionPadding); + out(converted); + } + }, totalLength, precision ? ' ' : spec.padding, spec.flags.leftJustified, minWidth); } static constexpr void conversionSupported(format_specifier spec) @@ -507,67 +495,55 @@ namespace format { } } - - std::size_t zeroPadding = 0; - std::size_t paddingLength{0}; - if (minWidth) + std::size_t zeroPadding{0}; + const auto prefixSize = (signPrefix != '\0' ? 1 : 0) + hexPrefix.size(); + const auto dotSize = (addDot ? 1 : 0); + const auto integralDigitCount = integralPart.size(); + const auto convertedSize = converted.size(); + std::size_t totalLength{prefixSize + convertedSize + dotSize + extraZeros + (quoteGrouping != 0 ? integralDigitCount / quoteGrouping : 0)}; + if (minWidth && *minWidth > totalLength) { - const auto prefixSize = (signPrefix != '\0' ? 1 : 0) + hexPrefix.size(); - const auto dotSize = (addDot ? 1 : 0); - const auto integralDigitCount = integralPart.size(); - const auto convertedSize = converted.size(); - const auto totalLength = prefixSize + convertedSize + dotSize + extraZeros + (quoteGrouping != 0 ? integralDigitCount / quoteGrouping : 0); - if (*minWidth > totalLength) + if (quoteGrouping != 0 && spec.padding == '0') { - if (quoteGrouping != 0 && spec.padding == '0') - { - zeroPadding = calculateNeededGroupedZeroPadding(*minWidth - prefixSize - dotSize - (convertedSize - integralDigitCount), integralDigitCount, quoteGrouping); - spec.padding = ' '; - paddingLength = *minWidth - (totalLength + zeroPadding + zeroPadding / quoteGrouping); - } - else + zeroPadding = calculateNeededGroupedZeroPadding(*minWidth - prefixSize - dotSize - (convertedSize - integralDigitCount), integralDigitCount, quoteGrouping); + spec.padding = ' '; + totalLength += zeroPadding + (zeroPadding / quoteGrouping); + } + else + { + if(spec.padding == '0') { - paddingLength = *minWidth - totalLength; - if(!spec.flags.leftJustified && spec.padding == '0') - { - zeroPadding = paddingLength; - } + zeroPadding = *minWidth - totalLength; + totalLength += zeroPadding; } } } - if(!spec.flags.leftJustified && spec.padding != '0') + formatPadded(out, [signPrefix, hexPrefix, quoteGrouping, mantissa, integralPart, fractionalPart, exponent, zeroPadding, extraZeros, addDot](const auto& out) { - out(spec.padding, paddingLength); - } - - if (signPrefix != '\0') - { - out(signPrefix); - } - out(hexPrefix); - - if (quoteGrouping != 0) - { - formatQuoteGrouped(out, integralPart, zeroPadding, quoteGrouping); - out(fractionalPart); - } - else - { - out('0', zeroPadding); - out(mantissa); - } - if (addDot) - { - out('.'); - } - out('0', extraZeros); - out(exponent); + if (signPrefix != '\0') + { + out(signPrefix); + } + out(hexPrefix); - if(spec.flags.leftJustified) - { - out(spec.padding, paddingLength); - } + if (quoteGrouping != 0) + { + formatQuoteGrouped(out, integralPart, zeroPadding, quoteGrouping); + out(fractionalPart); + } + else + { + out('0', zeroPadding); + out(mantissa); + } + if (addDot) + { + out('.'); + } + out('0', extraZeros); + out(exponent); + }, totalLength, ' ', spec.flags.leftJustified, minWidth); return; } @@ -584,47 +560,26 @@ namespace format { struct formatter { static constexpr void format(const format_output auto& out, const S& s, format_specifier spec, optional_int minWidth, optional_int precision) { - std::string_view val{s}; - if (precision) - { - val = val.substr(0, *precision); - } + const std::string_view val{precision ? std::string_view{s}.substr(0, *precision) : s}; if (spec.flags.quote) { const auto quoteExtra = std::count_if(val.begin(), val.end(), "\"\\"_contains) + 2; - std::size_t padding = 0; - if (minWidth) - { - const auto totalLength = val.size() + quoteExtra; - if (*minWidth > totalLength) + formatPadded(out, [val](const auto& out){ + out('"'); + for (std::size_t pos = 0, startPos = 0; pos < val.size(); ) { - padding = *minWidth - totalLength; - } - } - if (!spec.flags.leftJustified) - { - out(' ', padding); - } - - out('"'); - for (std::size_t pos = 0, startPos = 0; pos < val.size(); ) - { - pos = val.find_first_of("\"\\", pos); - out(val.substr(startPos, pos - startPos)); - if (pos != std::string_view::npos) - { - out('\\'); - startPos = pos; - ++pos; + pos = val.find_first_of("\"\\", pos); + out(val.substr(startPos, pos - startPos)); + if (pos != std::string_view::npos) + { + out('\\'); + startPos = pos; + ++pos; + } } - } - out('"'); - - if (spec.flags.leftJustified) - { - out(' ', padding); - } + out('"'); + }, val.size() + quoteExtra, ' ', spec.flags.leftJustified, minWidth); } else { -- cgit v1.2.3-54-g00ecf