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
|
`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
|
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
|
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
|
Each conversion specifier `conversion-spec` is replaced by appropriate characters as described
|
||||||
in the following table:
|
in the following table:
|
||||||
@@ -560,7 +561,6 @@ in the following table:
|
|||||||
| `%t` | A horizontal-tab character |
|
| `%t` | A horizontal-tab character |
|
||||||
| `%%` | A `%` character |
|
| `%%` | A `%` character |
|
||||||
|
|
||||||
|
|
||||||
If the `units-specs` is omitted, the `quantity` object is formatted as if by streaming it to
|
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
|
`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.
|
additional padding and adjustments as specified by the format specifiers.
|
||||||
|
@@ -25,13 +25,14 @@
|
|||||||
#include <units/bits/customization_points.h>
|
#include <units/bits/customization_points.h>
|
||||||
#include <units/quantity.h>
|
#include <units/quantity.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// units-format-spec:
|
// 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:
|
// units-specs:
|
||||||
// conversion-spec
|
// conversion-spec
|
||||||
// units-specs conversion-spec
|
// units-specs conversion-spec
|
||||||
@@ -94,11 +95,25 @@ namespace units {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Rep, typename OutputIt>
|
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)
|
if(precision >= 0)
|
||||||
return format_to(out, "{:.{}f}", val, precision);
|
return format_to(out, "{:" + sign_text + ".{}f}", val, precision);
|
||||||
return format_to(out, treat_as_floating_point<Rep> ? "{:g}" : "{}", val);
|
return format_to(out, treat_as_floating_point<Rep> ? "{:" + sign_text + "g}" : "{:" + sign_text + "}", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Unit, typename OutputIt>
|
template<typename Unit, typename OutputIt>
|
||||||
@@ -111,10 +126,11 @@ namespace units {
|
|||||||
struct units_formatter {
|
struct units_formatter {
|
||||||
OutputIt out;
|
OutputIt out;
|
||||||
Rep val;
|
Rep val;
|
||||||
|
fmt::sign_t sign;
|
||||||
int precision;
|
int precision;
|
||||||
|
|
||||||
explicit units_formatter(OutputIt o, quantity<Unit, Rep> q, int prec):
|
explicit units_formatter(OutputIt o, quantity<Unit, Rep> q, fmt::sign_t s, int prec):
|
||||||
out(o), val(q.count()), precision(prec)
|
out(o), val(q.count()), sign(s), precision(prec)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +142,7 @@ namespace units {
|
|||||||
|
|
||||||
void on_quantity_value()
|
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()
|
void on_quantity_unit()
|
||||||
@@ -179,27 +195,30 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* msg) { throw fmt::format_error(msg); }
|
void on_error(const char* msg) { throw fmt::format_error(msg); }
|
||||||
void on_fill(CharT fill) { f.specs.fill[0] = fill; }
|
constexpr void on_fill(CharT fill) { f.specs.fill[0] = fill; }
|
||||||
void on_align(align_t align) { f.specs.align = align; }
|
constexpr void on_plus() { f.specs.sign = fmt::sign::plus; }
|
||||||
void on_width(unsigned width) { f.specs.width = width; }
|
constexpr void on_minus() { f.specs.sign = fmt::sign::minus; }
|
||||||
void on_precision(unsigned precision) { f.precision = precision; }
|
constexpr void on_space() { f.specs.sign = fmt::sign::space; }
|
||||||
void end_precision() {}
|
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>
|
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);
|
f.width_ref = make_arg_ref(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename 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);
|
f.precision_ref = make_arg_ref(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_text(const CharT*, const CharT*) {}
|
constexpr void on_text(const CharT*, const CharT*) {}
|
||||||
void on_quantity_value() { f.quantity_value = true; }
|
constexpr void on_quantity_value() { f.quantity_value = true; }
|
||||||
void on_quantity_unit() { f.quantity_unit = true; }
|
constexpr void on_quantity_unit() { f.quantity_unit = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct parse_range {
|
struct parse_range {
|
||||||
@@ -221,6 +240,24 @@ private:
|
|||||||
if(begin == end)
|
if(begin == end)
|
||||||
return {begin, begin};
|
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
|
// parse width
|
||||||
begin = fmt::internal::parse_width(begin, end, handler);
|
begin = fmt::internal::parse_width(begin, end, handler);
|
||||||
if(begin == end)
|
if(begin == end)
|
||||||
@@ -241,6 +278,9 @@ private:
|
|||||||
// quantity values should behave like numbers (by default aligned to right)
|
// quantity values should behave like numbers (by default aligned to right)
|
||||||
specs.align = fmt::align_t::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};
|
return {begin, end};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,13 +308,13 @@ public:
|
|||||||
// deal with quantity content
|
// deal with quantity content
|
||||||
if(begin == end || *begin == '}') {
|
if(begin == end || *begin == '}') {
|
||||||
// default format should print value followed by the unit separeted with 1 space
|
// 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(' ');
|
*out++ = CharT(' ');
|
||||||
units::detail::format_units_quantity_unit<Unit>(out);
|
units::detail::format_units_quantity_unit<Unit>(out);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// user provided format
|
// 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);
|
parse_units_format(begin, end, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -763,17 +763,17 @@ TEST_CASE("sign specification", "[text][fmt]")
|
|||||||
|
|
||||||
SECTION("value only format {:%Q} on a quantity")
|
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,+1,1, 1");
|
||||||
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,-1,-1,-1");
|
||||||
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}", inf) == "inf,+inf,inf, inf");
|
||||||
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}", nan) == "nan,+nan,nan, nan");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("sign specification for unit only", "[text][fmt][exception]")
|
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 a 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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user