forked from mpusz/mp-units
fmt support for sign added
This commit is contained in:
@@ -547,7 +547,8 @@ The productions `fill-and-align`, `sign`, `width`, and `precision` are described
|
||||
`precision` specification in the `units-format-spec` is valid only for `units::quantity` types
|
||||
where the representation type `Rep` is a floating point type. For all other `Rep` types, an
|
||||
exception of type `format_error` is thrown if the `units-format-spec` contains a precision
|
||||
specification.
|
||||
specification. An `format_error` is also thrown if `sign` is provided with a `conversion-spec`
|
||||
to print quantity unit but not its value.
|
||||
|
||||
Each conversion specifier `conversion-spec` is replaced by appropriate characters as described
|
||||
in the following table:
|
||||
@@ -560,7 +561,6 @@ in the following table:
|
||||
| `%t` | A horizontal-tab character |
|
||||
| `%%` | A `%` character |
|
||||
|
||||
|
||||
If the `units-specs` is omitted, the `quantity` object is formatted as if by streaming it to
|
||||
`std::ostringstream os` and copying `os.str()` through the output iterator of the context with
|
||||
additional padding and adjustments as specified by the format specifiers.
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -763,17 +763,17 @@ TEST_CASE("sign specification", "[text][fmt]")
|
||||
|
||||
SECTION("value only format {:%Q} on a quantity")
|
||||
{
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", 1m) == "1 m,+1 m,1 m, 1 m");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", -1m) == "-1 m,-1 m,-1 m,-1 m");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", inf) == "inf m,+inf m,inf m, inf m");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", nan) == "nan m,+nan m,nan m, nan m");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", 1m) == "1,+1,1, 1");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", -1m) == "-1,-1,-1,-1");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", inf) == "inf,+inf,inf, inf");
|
||||
CHECK(fmt::format("{0:%Q},{0:+%Q},{0:-%Q},{0: %Q}", nan) == "nan,+nan,nan, nan");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("sign specification for unit only", "[text][fmt][exception]")
|
||||
{
|
||||
CHECK_THROWS_MATCHES(fmt::format("{:+%q}", 1m), fmt::format_error, Message("sign not allowed for quantity unit"));
|
||||
CHECK_THROWS_MATCHES(fmt::format("{:-%q}", 1m), fmt::format_error, Message("sign not allowed for quantity unit"));
|
||||
CHECK_THROWS_MATCHES(fmt::format("{:+%q}", 1m), fmt::format_error, Message("sign not allowed for a quantity unit"));
|
||||
CHECK_THROWS_MATCHES(fmt::format("{:-%q}", 1m), fmt::format_error, Message("sign not allowed for a quantity unit"));
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user