mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 20:54:28 +02:00
added ASCII-only format output support
This commit is contained in:
committed by
Mateusz Pusz
parent
99c309ef19
commit
e9272ac108
@@ -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
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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> {};
|
||||
|
@@ -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;
|
||||
|
99
src/include/units/symbol_text.h
Normal file
99
src/include/units/symbol_text.h
Normal 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
|
@@ -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;
|
||||
|
@@ -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")
|
||||
{
|
||||
|
Reference in New Issue
Block a user