added ASCII-only format output support

This commit is contained in:
Ramzi Sabra
2020-03-24 06:59:25 +02:00
committed by Mateusz Pusz
parent 99c309ef19
commit e9272ac108
8 changed files with 150 additions and 12 deletions

View File

@@ -25,6 +25,7 @@
#include <units/bits/external/fixed_string.h>
#include <units/bits/external/text_tools.h>
#include <units/derived_dimension.h>
#include <units/symbol_text.h>
namespace units::detail {
@@ -49,7 +50,7 @@ constexpr auto operator_text()
}
}
template<typename E, basic_fixed_string Symbol, std::size_t NegativeExpCount, std::size_t Idx>
template<typename E, basic_symbol_text Symbol, std::size_t NegativeExpCount, std::size_t Idx>
constexpr auto exp_text()
{
// get calculation operator + symbol

View File

@@ -131,6 +131,13 @@ namespace units {
if(ptr == end)
throw fmt::format_error("invalid format");
c = *ptr++;
switch(c)
{
case 'A':
handler.on_quantity_unit_ascii_only();
c = *ptr++;
break;
}
switch(c) {
// units-type
case '%':
@@ -212,13 +219,14 @@ namespace units {
global_format_specs<CharT> const & global_specs;
rep_format_specs const & rep_specs;
unit_format_specs const & unit_specs;
bool ascii_only;
explicit units_formatter(
OutputIt o, quantity<Dimension, Unit, Rep> q,
global_format_specs<CharT> const & gspecs,
rep_format_specs const & rspecs, unit_format_specs const & uspecs
):
out(o), val(q.count()), global_specs(gspecs), rep_specs(rspecs), unit_specs(uspecs)
out(o), val(q.count()), global_specs(gspecs), rep_specs(rspecs), unit_specs(uspecs), ascii_only(false)
{
}
@@ -235,12 +243,19 @@ namespace units {
void on_quantity_unit([[maybe_unused]] const CharT)
{
if (unit_specs.modifier != '\0') {
if (unit_specs.modifier != '\0' && unit_specs.modifier != 'A') {
throw fmt::format_error(
fmt::format("Unit modifier '{}' is not implemented", unit_specs.modifier)
); // TODO
}
format_to(out, "{}", unit_text<Dimension, Unit>().c_str());
auto txt = unit_text<Dimension, Unit>();
auto txt_c_str = ascii_only ? txt.ascii().c_str() : txt.standard().c_str();
format_to(out, "{}", txt_c_str);
}
void on_quantity_unit_ascii_only()
{
ascii_only = true;
}
};
@@ -260,6 +275,7 @@ private:
units::detail::unit_format_specs unit_specs;
bool quantity_value = false;
bool quantity_unit = false;
bool quantity_unit_ascii_only = false;
arg_ref_type width_ref;
arg_ref_type precision_ref;
fmt::basic_string_view<CharT> format_str;
@@ -342,6 +358,11 @@ private:
}
f.quantity_unit = true;
}
constexpr void on_quantity_unit_ascii_only()
{
f.quantity_unit_ascii_only = true;
}
};
struct parse_range {

View File

@@ -30,8 +30,8 @@ namespace units::natural {
struct unitless : named_unit<unitless, "", no_prefix> {};
struct electronvolt : named_unit<electronvolt, "eV", si::prefix> {};
struct gigaelectronvolt : prefixed_unit<gigaelectronvolt, si::giga, electronvolt> {};
struct inverted_gigaelectronvolt : named_unit<inverted_gigaelectronvolt, "GeV⁻¹", no_prefix> {};
struct square_gigaelectronvolt : named_unit<square_gigaelectronvolt, "GeV²", no_prefix> {};
struct inverted_gigaelectronvolt : named_unit<inverted_gigaelectronvolt, {"GeV⁻¹", "GeV^-1"}, no_prefix> {};
struct square_gigaelectronvolt : named_unit<square_gigaelectronvolt, {"GeV²", "GeV^2"}, no_prefix> {};
// NOTE: eV as a base unit with no relation to joule prevents us from going back
// from natural units to SI. Do we need such a support or should we treat

View File

@@ -30,7 +30,7 @@
namespace units::si {
struct ohm : named_unit<ohm, "Ω", prefix> {};
struct ohm : named_unit<ohm, {"Ω", "ohm"}, prefix> {};
struct milliohm : prefixed_unit<milliohm, milli, ohm> {};
struct kiloohm : prefixed_unit<kiloohm, kilo, ohm> {};
struct megaohm : prefixed_unit<megaohm, mega, ohm> {};

View File

@@ -23,8 +23,8 @@
#pragma once
#include <units/bits/external/downcasting.h>
#include <units/bits/external/fixed_string.h>
#include <units/ratio.h>
#include <units/symbol_text.h>
namespace units {
@@ -68,7 +68,7 @@ struct prefix_base : downcast_base<prefix_base<PT, R>> {
* @tparam Symbol a text representation of the prefix
* @tparam R factor to be used to scale a unit
*/
template<typename Child, PrefixFamily PT, basic_fixed_string Symbol, Ratio R>
template<typename Child, PrefixFamily PT, basic_symbol_text Symbol, Ratio R>
requires (!std::same_as<PT, no_prefix>)
struct prefix : downcast_child<Child, detail::prefix_base<PT, R>> {
static constexpr auto symbol = Symbol;

View File

@@ -0,0 +1,99 @@
#pragma once
#include <units/bits/external/fixed_string.h>
namespace units {
template<typename StandardCharT, typename ASCIICharT, std::size_t N, std::size_t M>
struct basic_symbol_text {
basic_fixed_string<StandardCharT, N> standard_;
basic_fixed_string<ASCIICharT, M> ascii_;
constexpr basic_symbol_text(StandardCharT s) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(StandardCharT s, ASCIICharT a) noexcept: standard_(s), ascii_(a) {}
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1]) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1], const ASCIICharT (&a)[M + 1]) noexcept: standard_(s), ascii_(a) {}
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s, const basic_fixed_string<ASCIICharT, M>& a) noexcept: standard_(s), ascii_(a) {}
[[nodiscard]] constexpr auto& standard() { return standard_; }
[[nodiscard]] constexpr const auto& standard() const { return standard_; }
[[nodiscard]] constexpr auto& ascii() { return ascii_; }
[[nodiscard]] constexpr const auto& ascii() const { return ascii_; }
[[nodiscard]] constexpr std::size_t size() const noexcept { return standard_.size(); }
[[nodiscard]] constexpr const StandardCharT* c_str() const noexcept { return standard_.c_str(); }
template<std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + M2> operator+(
const basic_symbol_text& lhs, const basic_symbol_text<StandardCharT, ASCIICharT, N2, M2>& rhs) noexcept
{
return basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + M2>(
lhs.standard_ + rhs.standard_, lhs.ascii_ + rhs.ascii_);
}
template<typename CharT, std::size_t N2>
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + N2> operator+(
const basic_symbol_text& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
{
return basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + N2>(
lhs.standard_ + rhs, lhs.ascii_ + rhs);
}
template<typename CharT, std::size_t N2>
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + N2> operator+(
const basic_fixed_string<CharT, N2>& lhs, const basic_symbol_text& rhs) noexcept
{
return basic_symbol_text<StandardCharT, ASCIICharT, N + N2, M + N2>(
lhs + rhs.standard_, lhs + rhs.ascii_);
}
template<typename StandardCharT2, typename ASCIICharT2, std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend bool operator<(const basic_symbol_text& lhs,
const basic_symbol_text<StandardCharT2, ASCIICharT2, N2, M2>& rhs) noexcept
{
return (lhs.standard_ < rhs.standard_);
}
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
const StandardCharT (&rhs)[N + 1]) noexcept
{
return (lhs.standard_ == basic_fixed_string(rhs));
}
template<typename StandardCharT2, std::size_t N2>
[[nodiscard]] constexpr friend bool operator==(const basic_symbol_text& lhs,
const StandardCharT2 (&rhs)[N2 + 1]) noexcept
{
return false;
}
template<class Traits>
friend std::basic_ostream<StandardCharT, Traits>& operator<<(std::basic_ostream<StandardCharT, Traits>& os,
const basic_symbol_text& symbol)
{
return os << symbol.standard_.c_str();
}
};
template<typename StandardCharT>
basic_symbol_text(StandardCharT) -> basic_symbol_text<StandardCharT, StandardCharT, 1, 1>;
template<typename StandardCharT, typename ASCIICharT>
basic_symbol_text(StandardCharT, ASCIICharT) -> basic_symbol_text<StandardCharT, ASCIICharT, 1, 1>;
template<typename StandardCharT, std::size_t N>
basic_symbol_text(const StandardCharT (&)[N]) -> basic_symbol_text<StandardCharT, StandardCharT, N - 1, N - 1>;
template<typename StandardCharT, std::size_t N>
basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s) -> basic_symbol_text<StandardCharT, StandardCharT, N - 1, N - 1>;
template<typename StandardCharT, typename ASCIICharT, std::size_t N, std::size_t M>
basic_symbol_text(const StandardCharT (&)[N], const ASCIICharT (&)[M]) -> basic_symbol_text<StandardCharT, ASCIICharT, N - 1, M - 1>;
template<typename StandardCharT, typename ASCIICharT, std::size_t N, std::size_t M>
basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s,
const basic_fixed_string<ASCIICharT, M>& a)
-> basic_symbol_text<StandardCharT, ASCIICharT, N - 1, M - 1>;
} // namespace units

View File

@@ -31,6 +31,7 @@
#include <units/derived_dimension.h>
#include <units/prefix.h>
#include <units/ratio.h>
#include <units/symbol_text.h>
namespace units {
@@ -94,7 +95,7 @@ struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
* @tparam Symbol a short text representation of the unit
* @tparam PT no_prefix or a type of prefix family
*/
template<typename Child, basic_fixed_string Symbol, PrefixFamily PT>
template<typename Child, basic_symbol_text Symbol, PrefixFamily PT>
struct named_unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
@@ -115,7 +116,7 @@ struct named_unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
* @tparam R a scale to apply to U
* @tparam U a reference unit to scale
*/
template<typename Child, basic_fixed_string Symbol, PrefixFamily PT, UnitRatio R, Unit U>
template<typename Child, basic_symbol_text Symbol, PrefixFamily PT, UnitRatio R, Unit U>
struct named_scaled_unit : downcast_child<Child, scaled_unit<ratio_multiply<R, typename U::ratio>, typename U::reference>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;

View File

@@ -29,6 +29,7 @@
#include "units/physical/si/velocity.h"
#include "units/physical/si/volume.h"
#include "units/physical/si/surface_tension.h"
#include "units/physical/si/resistance.h"
#include "units/format.h"
#include "units/math.h"
#include <catch2/catch.hpp>
@@ -706,7 +707,22 @@ TEST_CASE("format string with only %q should print quantity unit symbol only", "
CHECK(fmt::format("{:%q}", 123q_km_per_h) == "km/h");
}
TEST_CASE("%q an %Q can be put anywhere in a format string", "[text][fmt]")
TEST_CASE("format string with only %q for unit with ASCII quantity unit symbol should print Unicode quantity unit symbol only", "[text][fmt]")
{
CHECK(fmt::format("{:%Q%q}", 123q_kR) == "123kΩ");
}
TEST_CASE("format string with %Aq for unit with ASCII quantity unit symbol should print ASCII quantity unit symbol only", "[text][fmt]")
{
CHECK(fmt::format("{:%Q%Aq}", 123q_kR) == "123kohm");
}
TEST_CASE("format string with %Aq for unit with no ASCII quantity unit symbol should print Unicode quantity unit symbol only", "[text][fmt]")
{
CHECK(fmt::format("{:%Aq}", 123q_km_per_h) == "km/h");
}
TEST_CASE("%q and %Q can be put anywhere in a format string", "[text][fmt]")
{
SECTION("no space")
{