fmt support for sign added

This commit is contained in:
Mateusz Pusz
2019-11-12 19:46:15 +01:00
parent d763c75df2
commit ff656620e9
3 changed files with 71 additions and 31 deletions
+59 -19
View File
@@ -25,13 +25,14 @@
#include <units/bits/customization_points.h>
#include <units/quantity.h>
#include <fmt/format.h>
#include <string_view>
namespace units {
namespace detail {
// units-format-spec:
// fill-and-align[opt] width[opt] precision[opt] units-specs[opt]
// fill-and-align[opt] sign[opt] width[opt] precision[opt] units-specs[opt]
// units-specs:
// conversion-spec
// units-specs conversion-spec
@@ -94,11 +95,25 @@ namespace units {
}
template<typename Rep, typename OutputIt>
inline OutputIt format_units_quantity_value(OutputIt out, const Rep& val, int precision)
inline OutputIt format_units_quantity_value(OutputIt out, const Rep& val, fmt::sign_t sign, int precision)
{
std::string sign_text;
switch(sign) {
case fmt::sign::none:
break;
case fmt::sign::plus:
sign_text = "+";
break;
case fmt::sign::minus:
sign_text = "-";
break;
case fmt::sign::space:
sign_text = " ";
break;
}
if(precision >= 0)
return format_to(out, "{:.{}f}", val, precision);
return format_to(out, treat_as_floating_point<Rep> ? "{:g}" : "{}", val);
return format_to(out, "{:" + sign_text + ".{}f}", val, precision);
return format_to(out, treat_as_floating_point<Rep> ? "{:" + sign_text + "g}" : "{:" + sign_text + "}", val);
}
template<typename Unit, typename OutputIt>
@@ -111,10 +126,11 @@ namespace units {
struct units_formatter {
OutputIt out;
Rep val;
fmt::sign_t sign;
int precision;
explicit units_formatter(OutputIt o, quantity<Unit, Rep> q, int prec):
out(o), val(q.count()), precision(prec)
explicit units_formatter(OutputIt o, quantity<Unit, Rep> q, fmt::sign_t s, int prec):
out(o), val(q.count()), sign(s), precision(prec)
{
}
@@ -126,7 +142,7 @@ namespace units {
void on_quantity_value()
{
out = format_units_quantity_value(out, val, precision);
out = format_units_quantity_value(out, val, sign, precision);
}
void on_quantity_unit()
@@ -179,27 +195,30 @@ private:
}
void on_error(const char* msg) { throw fmt::format_error(msg); }
void on_fill(CharT fill) { f.specs.fill[0] = fill; }
void on_align(align_t align) { f.specs.align = align; }
void on_width(unsigned width) { f.specs.width = width; }
void on_precision(unsigned precision) { f.precision = precision; }
void end_precision() {}
constexpr void on_fill(CharT fill) { f.specs.fill[0] = fill; }
constexpr void on_plus() { f.specs.sign = fmt::sign::plus; }
constexpr void on_minus() { f.specs.sign = fmt::sign::minus; }
constexpr void on_space() { f.specs.sign = fmt::sign::space; }
constexpr void on_align(align_t align) { f.specs.align = align; }
constexpr void on_width(unsigned width) { f.specs.width = width; }
constexpr void on_precision(unsigned precision) { f.precision = precision; }
constexpr void end_precision() {}
template<typename Id>
void on_dynamic_width(Id arg_id)
constexpr void on_dynamic_width(Id arg_id)
{
f.width_ref = make_arg_ref(arg_id);
}
template<typename Id>
void on_dynamic_precision(Id arg_id)
constexpr void on_dynamic_precision(Id arg_id)
{
f.precision_ref = make_arg_ref(arg_id);
}
void on_text(const CharT*, const CharT*) {}
void on_quantity_value() { f.quantity_value = true; }
void on_quantity_unit() { f.quantity_unit = true; }
constexpr void on_text(const CharT*, const CharT*) {}
constexpr void on_quantity_value() { f.quantity_value = true; }
constexpr void on_quantity_unit() { f.quantity_unit = true; }
};
struct parse_range {
@@ -221,6 +240,24 @@ private:
if(begin == end)
return {begin, begin};
// parse sign
switch(static_cast<char>(*begin)) {
case '+':
handler.on_plus();
++begin;
break;
case '-':
handler.on_minus();
++begin;
break;
case ' ':
handler.on_space();
++begin;
break;
}
if(begin == end)
return {begin, begin};
// parse width
begin = fmt::internal::parse_width(begin, end, handler);
if(begin == end)
@@ -241,6 +278,9 @@ private:
// quantity values should behave like numbers (by default aligned to right)
specs.align = fmt::align_t::right;
if((quantity_unit && !quantity_value) && (specs.sign == fmt::sign::plus || specs.sign == fmt::sign::minus))
handler.on_error("sign not allowed for a quantity unit");
return {begin, end};
}
@@ -268,13 +308,13 @@ public:
// deal with quantity content
if(begin == end || *begin == '}') {
// default format should print value followed by the unit separeted with 1 space
out = units::detail::format_units_quantity_value(out, q.count(), precision);
out = units::detail::format_units_quantity_value(out, q.count(), specs.sign, precision);
*out++ = CharT(' ');
units::detail::format_units_quantity_unit<Unit>(out);
}
else {
// user provided format
units::detail::units_formatter f(out, q, precision);
units::detail::units_formatter f(out, q, specs.sign, precision);
parse_units_format(begin, end, f);
}