From b864461636057cb3da72b09e6ab0068cfa883f57 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 18 Oct 2019 15:34:46 +0200 Subject: [PATCH] Prefixed units support redesigned --- README.md | 1 + doc/DESIGN.md | 161 +++++++++++------- src/include/units/bits/fixed_string.h | 37 ++-- src/include/units/dimensions/acceleration.h | 2 +- src/include/units/dimensions/area.h | 10 +- src/include/units/dimensions/capacitance.h | 4 +- src/include/units/dimensions/current.h | 4 +- .../units/dimensions/electric_charge.h | 4 +- src/include/units/dimensions/energy.h | 13 +- src/include/units/dimensions/force.h | 4 +- src/include/units/dimensions/frequency.h | 15 +- src/include/units/dimensions/length.h | 19 ++- .../units/dimensions/luminous_intensity.h | 4 +- src/include/units/dimensions/mass.h | 6 +- src/include/units/dimensions/power.h | 13 +- src/include/units/dimensions/pressure.h | 4 +- ...base_dimensions.h => si_base_dimensions.h} | 0 .../{prefix.h => dimensions/si_prefixes.h} | 35 ++-- src/include/units/dimensions/substance.h | 4 +- src/include/units/dimensions/temperature.h | 4 +- src/include/units/dimensions/time.h | 15 +- src/include/units/dimensions/velocity.h | 6 +- src/include/units/dimensions/voltage.h | 4 +- src/include/units/dimensions/volume.h | 10 +- src/include/units/format.h | 18 +- src/include/units/quantity.h | 9 +- src/include/units/unit.h | 79 +++++---- .../runtime/digital_information_test.cpp | 8 +- test/unit_test/runtime/text_test.cpp | 17 +- test/unit_test/static/custom_unit_test.cpp | 10 +- 30 files changed, 284 insertions(+), 236 deletions(-) rename src/include/units/dimensions/{base_dimensions.h => si_base_dimensions.h} (100%) rename src/include/units/{prefix.h => dimensions/si_prefixes.h} (60%) diff --git a/README.md b/README.md index 27e5cbf4..77396d3f 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer. - Added unit symbols definitions to `base_dimension` and `derived_unit` - Added `coherent_derived_unit` helper - Added support for `operator<<` on `quantity` + - Refactored the way prefixed units are defined - 0.3.1 Sep 18, 2019 - cmcstl2 dependency changed to range-v3 0.9.1 diff --git a/doc/DESIGN.md b/doc/DESIGN.md index 66c6a4d5..02019e0a 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -157,7 +157,7 @@ helper: ```cpp template -struct derived_dimension; +struct derived_dimension : downcast_helper::type> {}; ``` `Child` class template parameter is a part of a CRTP idiom and is used to provide a downcasting facility @@ -229,68 +229,6 @@ struct unit : downcast_base> { }; ``` -Coherent derived units (units with `ratio<1>`) are created with a `coherent_derived_unit` helper: - -```cpp -template -struct coherent_derived_unit; -``` - -The above type exposes public `symbol` and `prefix` member types used to print unit symbol names. - -For example to define the base unit of `length`: - -```cpp -struct metre : coherent_derived_unit {}; -``` - -Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used -to provide downcasting facility (described below). - -All other units are created with a `derived_unit` helper: - -```cpp -template -struct derived_unit; -``` - -The above type exposes public `symbol` member type used to print unit symbol names. - -`derived_unit` has a few useful partial specializations: -- helper to create non-coherent units for a specified dimension - -```cpp -template -struct derived_unit; -``` - -```cpp -struct yard : derived_unit> {}; -``` - -- helper to create a named unit with a SI prefix - -```cpp -template -struct derived_unit; -``` - -```cpp -struct kilometre : derived_unit> {}; -``` - -- helper that automatically calculates ratio based on info in desired dimension and provided list - of units of base dimensions - -```cpp -template -struct derived_unit; -``` - -```cpp -struct kilometre_per_hour : derived_unit {}; -``` - `units::Unit` is a concept that is satisfied by a type that is empty and publicly derived from `units::unit` class template: @@ -301,6 +239,96 @@ concept Unit = detail::is_unit>; // exposition only ``` +Coherent derived units (units with `ratio<1>`) are created with a `coherent_derived_unit` class +template: + +```cpp +template +struct coherent_derived_unit : downcast_helper>> { + static constexpr auto symbol = Symbol; + using prefix_type = PrefixType; +}; +``` + +The above exposes public `prefix_type` member type and `symbol` used to print unit symbol +names. `prefix_type` is a tag type used to identify the type of prefixes to be used (i.e. SI, +data). + +For example to define the coherent unit of `length`: + +```cpp +struct metre : coherent_derived_unit {}; +``` + +Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used +to provide downcasting facility (described below). + +To create the rest of derived units the following class template can be used: + +```cpp +template +struct derived_unit : downcast_helper> { + static constexpr auto symbol = Symbol; +}; +``` + +User has to provide a symbol name, dimension, and a ratio relative to a coherent derived unit. +For example to define `minute`: + +```cpp +struct minute : derived_unit> {}; +``` + +The `mp-units` library provides also a few helper class templates to simplify the above process. + +For example to create a prefixed unit the following may be used: + +```cpp +template + requires requires { U::symbol; } && std::same_as +struct prefixed_derived_unit : downcast_helper>> { + static constexpr auto symbol = P::symbol + U::symbol; + using prefix_type = P::prefix_type; +}; +``` + +where `Prefix` is a concept requiring the instantiation of the following class template: + +```cpp +template +struct prefix { + using prefix_type = PrefixType; + using ratio = R; + static constexpr auto symbol = Symbol; +}; +``` + +With this to create prefixed units user does not have to specify numeric value of the prefix ratio +or its symbol and just has to do the following: + +```cpp +struct kilometre : prefixed_derived_unit {}; +``` + +For the cases where determining the exact ratio is not trivial another helper can be used: + +```cpp +template +struct deduced_derived_unit : downcast_helper> { + static constexpr auto symbol = Symbol; +}; +``` + +This will deduce the ratio based on the ingredient units and their relation defined in the +dimension: + +```cpp +struct mile_per_hour : deduced_derived_unit {}; +``` + + ### `Quantities` `units::quantity` is a class template that expresses the quantity/amount of a specific dimension @@ -416,6 +444,13 @@ of checks: 3. If a quantity has an unknown dimension, the symbols of base dimensions will be used to construct a unit symbol (i.e. `2 m/kg^2`). In this case no prefix symbols are added. +#### Text Formatting + +| Specifier | Replacement | +|-----------|--------------------------------------------------------------| +| `%q` | The quantity’s unit symbol | +| `%Q` | The quantity’s numeric value (as if extracted via `.count()` | + ## Strong types instead of aliases, and type downcasting facility diff --git a/src/include/units/bits/fixed_string.h b/src/include/units/bits/fixed_string.h index b49a51a5..3e2b3379 100644 --- a/src/include/units/bits/fixed_string.h +++ b/src/include/units/bits/fixed_string.h @@ -35,7 +35,7 @@ namespace units { data_[i] = txt[i]; } - [[nodiscard]] constexpr bool size() const noexcept { return N; } + [[nodiscard]] constexpr std::size_t size() const noexcept { return N; } [[nodiscard]] constexpr const CharT* c_str() const noexcept { return data_; } // auto operator==(const basic_fixed_string &) = default; @@ -75,6 +75,20 @@ namespace units { { return os << txt.c_str(); } + + template + [[nodiscard]] constexpr friend basic_fixed_string operator+(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept + { + CharT txt[lhs.size() + rhs.size() + 1] = {}; + + size_t i = 0; + for(; i != lhs.size(); ++i) + txt[i] = lhs.c_str()[i]; + for(size_t j = 0; j != rhs.size(); ++j) + txt[i + j] = rhs.c_str()[j]; + + return basic_fixed_string(txt); + } }; template @@ -83,25 +97,4 @@ namespace units { template using fixed_string = basic_fixed_string; - // TODO gcc:92101 - // hacked version to work with derived_unit - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92101 - - template - struct basic_fixed_string_hack { - static constexpr CharT txt[] = { Chars..., '\0' }; - - static constexpr const CharT* c_str() noexcept - { - return txt; - } - }; - - inline namespace hacks { - - template - constexpr basic_fixed_string_hack operator""_fs() { return {}; } - - } - } diff --git a/src/include/units/dimensions/acceleration.h b/src/include/units/dimensions/acceleration.h index 29074bb7..8a0f3510 100644 --- a/src/include/units/dimensions/acceleration.h +++ b/src/include/units/dimensions/acceleration.h @@ -31,7 +31,7 @@ namespace units { template concept Acceleration = QuantityOf; - struct metre_per_second_sq : coherent_derived_unit {}; + struct metre_per_second_sq : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/area.h b/src/include/units/dimensions/area.h index 59121ed6..89ce34ff 100644 --- a/src/include/units/dimensions/area.h +++ b/src/include/units/dimensions/area.h @@ -31,11 +31,11 @@ namespace units { template concept Area = QuantityOf; - struct square_metre : coherent_derived_unit {}; - struct square_millimetre : derived_unit {}; - struct square_centimetre : derived_unit {}; - struct square_kilometre : derived_unit {}; - struct square_foot : derived_unit {}; + struct square_metre : coherent_derived_unit {}; + struct square_millimetre : deduced_derived_unit {}; + struct square_centimetre : deduced_derived_unit {}; + struct square_kilometre : deduced_derived_unit {}; + struct square_foot : deduced_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/capacitance.h b/src/include/units/dimensions/capacitance.h index 79a3432e..683af249 100644 --- a/src/include/units/dimensions/capacitance.h +++ b/src/include/units/dimensions/capacitance.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include @@ -33,7 +33,7 @@ namespace units { template concept Capacitance = QuantityOf; - struct farad : coherent_derived_unit {}; + struct farad : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/current.h b/src/include/units/dimensions/current.h index 5fb5fda7..101eb62a 100644 --- a/src/include/units/dimensions/current.h +++ b/src/include/units/dimensions/current.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include namespace units { @@ -32,7 +32,7 @@ namespace units { template concept Current = QuantityOf; - struct ampere : coherent_derived_unit {}; + struct ampere : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/electric_charge.h b/src/include/units/dimensions/electric_charge.h index 4181e936..c9eb3c27 100644 --- a/src/include/units/dimensions/electric_charge.h +++ b/src/include/units/dimensions/electric_charge.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include @@ -33,7 +33,7 @@ namespace units { template concept ElectricCharge = QuantityOf; - struct coulomb : coherent_derived_unit {}; + struct coulomb : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/energy.h b/src/include/units/dimensions/energy.h index 8468fb27..8a893383 100644 --- a/src/include/units/dimensions/energy.h +++ b/src/include/units/dimensions/energy.h @@ -22,7 +22,8 @@ #pragma once -#include +#include +#include #include #include @@ -33,11 +34,11 @@ namespace units { template concept Energy = QuantityOf; - struct joule : coherent_derived_unit {}; - struct millijoule : derived_unit> {}; - struct kilojoule : derived_unit> {}; - struct megajoule : derived_unit> {}; - struct gigajoule : derived_unit> {}; + struct joule : coherent_derived_unit {}; + struct millijoule : prefixed_derived_unit {}; + struct kilojoule : prefixed_derived_unit {}; + struct megajoule : prefixed_derived_unit {}; + struct gigajoule : prefixed_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/force.h b/src/include/units/dimensions/force.h index 52fcb3ab..ac0b0fc2 100644 --- a/src/include/units/dimensions/force.h +++ b/src/include/units/dimensions/force.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include @@ -33,7 +33,7 @@ namespace units { template concept Force = QuantityOf; - struct newton : coherent_derived_unit {}; + struct newton : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/frequency.h b/src/include/units/dimensions/frequency.h index 38c9b971..3250ed43 100644 --- a/src/include/units/dimensions/frequency.h +++ b/src/include/units/dimensions/frequency.h @@ -22,7 +22,8 @@ #pragma once -#include +#include +#include #include namespace units { @@ -32,12 +33,12 @@ namespace units { template concept Frequency = QuantityOf; - struct hertz : coherent_derived_unit {}; - struct millihertz : derived_unit> {}; - struct kilohertz : derived_unit> {}; - struct megahertz : derived_unit> {}; - struct gigahertz : derived_unit> {}; - struct terahertz : derived_unit> {}; + struct hertz : coherent_derived_unit {}; + struct millihertz : prefixed_derived_unit {}; + struct kilohertz : prefixed_derived_unit {}; + struct megahertz : prefixed_derived_unit {}; + struct gigahertz : prefixed_derived_unit {}; + struct terahertz : prefixed_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/length.h b/src/include/units/dimensions/length.h index 7aebd258..6f8cd454 100644 --- a/src/include/units/dimensions/length.h +++ b/src/include/units/dimensions/length.h @@ -22,7 +22,8 @@ #pragma once -#include +#include +#include #include namespace units { @@ -33,10 +34,10 @@ namespace units { concept Length = QuantityOf; // SI units - struct metre : coherent_derived_unit {}; - struct millimetre : derived_unit> {}; - struct centimetre : derived_unit> {}; - struct kilometre : derived_unit> {}; + struct metre : coherent_derived_unit {}; + struct millimetre : prefixed_derived_unit {}; + struct centimetre : prefixed_derived_unit {}; + struct kilometre : prefixed_derived_unit {}; inline namespace literals { @@ -59,10 +60,10 @@ namespace units { } // namespace literals // US customary units - struct yard : derived_unit> {}; - struct foot : derived_unit, yard::ratio>> {}; - struct inch : derived_unit, foot::ratio>> {}; - struct mile : derived_unit, yard::ratio>> {}; + struct yard : derived_unit> {}; + struct foot : derived_unit, yard::ratio>> {}; + struct inch : derived_unit, foot::ratio>> {}; + struct mile : derived_unit, yard::ratio>> {}; inline namespace literals { diff --git a/src/include/units/dimensions/luminous_intensity.h b/src/include/units/dimensions/luminous_intensity.h index 14df26ac..4fd354a8 100644 --- a/src/include/units/dimensions/luminous_intensity.h +++ b/src/include/units/dimensions/luminous_intensity.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include namespace units { @@ -32,7 +32,7 @@ namespace units { template concept LuminousIntensity = QuantityOf; - struct candela : coherent_derived_unit {}; + struct candela : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/mass.h b/src/include/units/dimensions/mass.h index 36c34826..f48e3c43 100644 --- a/src/include/units/dimensions/mass.h +++ b/src/include/units/dimensions/mass.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include namespace units { @@ -32,8 +32,8 @@ namespace units { template concept Mass = QuantityOf; - struct kilogram : coherent_derived_unit {}; - struct gram : derived_unit> {}; + struct kilogram : coherent_derived_unit {}; + struct gram : derived_unit> {}; inline namespace literals { diff --git a/src/include/units/dimensions/power.h b/src/include/units/dimensions/power.h index a415a740..76a67760 100644 --- a/src/include/units/dimensions/power.h +++ b/src/include/units/dimensions/power.h @@ -22,7 +22,8 @@ #pragma once -#include +#include +#include #include namespace units { @@ -32,11 +33,11 @@ namespace units { template concept Power = QuantityOf; - struct watt : coherent_derived_unit {}; - struct milliwatt : derived_unit> {}; - struct kilowatt : derived_unit> {}; - struct megawatt : derived_unit> {}; - struct gigawatt : derived_unit> {}; + struct watt : coherent_derived_unit {}; + struct milliwatt : prefixed_derived_unit {}; + struct kilowatt : prefixed_derived_unit {}; + struct megawatt : prefixed_derived_unit {}; + struct gigawatt : prefixed_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/pressure.h b/src/include/units/dimensions/pressure.h index 11fdd086..1d1b11de 100644 --- a/src/include/units/dimensions/pressure.h +++ b/src/include/units/dimensions/pressure.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include @@ -33,7 +33,7 @@ namespace units { template concept Pressure = QuantityOf; - struct pascal : coherent_derived_unit {}; + struct pascal : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/base_dimensions.h b/src/include/units/dimensions/si_base_dimensions.h similarity index 100% rename from src/include/units/dimensions/base_dimensions.h rename to src/include/units/dimensions/si_base_dimensions.h diff --git a/src/include/units/prefix.h b/src/include/units/dimensions/si_prefixes.h similarity index 60% rename from src/include/units/prefix.h rename to src/include/units/dimensions/si_prefixes.h index a7d488e1..ecf4997a 100644 --- a/src/include/units/prefix.h +++ b/src/include/units/dimensions/si_prefixes.h @@ -29,30 +29,31 @@ namespace units { // prefix tags struct si_prefix; - + // SI prefixes - template using atto = unit>>; - template using femto = unit>>; - template using pico = unit>>; - template using nano = unit>>; - template using micro = unit>>; - template using milli = unit>>; - template using centi = unit>>; - template using deca = unit>>; - template using hecto = unit>>; - template using kilo = unit>>; - template using mega = unit>>; - template using giga = unit>>; - template using tera = unit>>; - template using peta = unit>>; - template using exa = unit>>; + using atto = prefix, "a">; + using femto = prefix, "f">; + using pico = prefix, "p">; + using nano = prefix, "n">; + using micro = prefix, "µ">; + using milli = prefix, "m">; + using centi = prefix, "c">; + using deci = prefix, "d">; + using deca = prefix, "da">; + using hecto = prefix, "h">; + using kilo = prefix, "k">; + using mega = prefix, "M">; + using giga = prefix, "G">; + using tera = prefix, "T">; + using peta = prefix, "P">; + using exa = prefix, "E">; template<> inline constexpr std::string_view prefix_symbol> = "a"; template<> inline constexpr std::string_view prefix_symbol> = "f"; template<> inline constexpr std::string_view prefix_symbol> = "p"; template<> inline constexpr std::string_view prefix_symbol> = "n"; - template<> inline constexpr std::string_view prefix_symbol> = "\u00b5\u0073"; // µ + template<> inline constexpr std::string_view prefix_symbol> = "µ"; template<> inline constexpr std::string_view prefix_symbol> = "m"; template<> inline constexpr std::string_view prefix_symbol> = "c"; template<> inline constexpr std::string_view prefix_symbol> = "d"; diff --git a/src/include/units/dimensions/substance.h b/src/include/units/dimensions/substance.h index 47a4d077..11e62d1f 100644 --- a/src/include/units/dimensions/substance.h +++ b/src/include/units/dimensions/substance.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include namespace units { @@ -32,7 +32,7 @@ namespace units { template concept Substance = QuantityOf; - struct mole : coherent_derived_unit {}; + struct mole : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/temperature.h b/src/include/units/dimensions/temperature.h index e59b2e83..a5f30494 100644 --- a/src/include/units/dimensions/temperature.h +++ b/src/include/units/dimensions/temperature.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include namespace units { @@ -32,7 +32,7 @@ namespace units { template concept ThermodynamicTemperature = QuantityOf; - struct kelvin : coherent_derived_unit {}; + struct kelvin : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/time.h b/src/include/units/dimensions/time.h index 46fd2e4c..4aa0bbf3 100644 --- a/src/include/units/dimensions/time.h +++ b/src/include/units/dimensions/time.h @@ -22,7 +22,8 @@ #pragma once -#include +#include +#include #include namespace units { @@ -32,12 +33,12 @@ namespace units { template concept Time = QuantityOf; - struct second : coherent_derived_unit {}; - struct nanosecond : derived_unit> {}; - struct microsecond : derived_unit> {}; - struct millisecond : derived_unit> {}; - struct minute : derived_unit> {}; - struct hour : derived_unit> {}; + struct second : coherent_derived_unit {}; + struct nanosecond : prefixed_derived_unit {}; + struct microsecond : prefixed_derived_unit {}; + struct millisecond : prefixed_derived_unit {}; + struct minute : derived_unit> {}; + struct hour : derived_unit> {}; inline namespace literals { diff --git a/src/include/units/dimensions/velocity.h b/src/include/units/dimensions/velocity.h index e3458686..3dc04ed7 100644 --- a/src/include/units/dimensions/velocity.h +++ b/src/include/units/dimensions/velocity.h @@ -32,9 +32,9 @@ namespace units { template concept Velocity = QuantityOf; - struct metre_per_second : coherent_derived_unit {}; - struct kilometre_per_hour : derived_unit {}; - struct mile_per_hour : derived_unit {}; + struct metre_per_second : coherent_derived_unit {}; + struct kilometre_per_hour : deduced_derived_unit {}; + struct mile_per_hour : deduced_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/voltage.h b/src/include/units/dimensions/voltage.h index 47886166..28db4cb7 100644 --- a/src/include/units/dimensions/voltage.h +++ b/src/include/units/dimensions/voltage.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include #include @@ -35,7 +35,7 @@ namespace units { template concept Voltage = QuantityOf; - struct volt : coherent_derived_unit {}; + struct volt : coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/volume.h b/src/include/units/dimensions/volume.h index a0007a39..786aa471 100644 --- a/src/include/units/dimensions/volume.h +++ b/src/include/units/dimensions/volume.h @@ -31,11 +31,11 @@ namespace units { template concept Volume = QuantityOf; - struct cubic_metre : coherent_derived_unit {}; - struct cubic_millimetre : derived_unit {}; - struct cubic_centimetre : derived_unit {}; - struct cubic_kilometre : derived_unit {}; - struct cubic_foot : derived_unit {}; + struct cubic_metre : coherent_derived_unit {}; + struct cubic_millimetre : deduced_derived_unit {}; + struct cubic_centimetre : deduced_derived_unit {}; + struct cubic_kilometre : deduced_derived_unit {}; + struct cubic_foot : deduced_derived_unit {}; inline namespace literals { diff --git a/src/include/units/format.h b/src/include/units/format.h index 00816e38..cb030b6f 100644 --- a/src/include/units/format.h +++ b/src/include/units/format.h @@ -22,12 +22,13 @@ #pragma once -#include +#include +#include namespace units { - template - inline constexpr std::string_view prefix_symbol = ""; + template + inline constexpr std::string_view prefix_symbol; namespace detail { @@ -44,13 +45,13 @@ namespace units { } } - template + template void print_prefix_or_ratio(std::basic_ostream& os) { if constexpr(Ratio::num != 1 || Ratio::den != 1) { - constexpr auto prefix = prefix_symbol; + constexpr auto prefix = prefix_symbol; - if constexpr(prefix != "") { + if constexpr(!prefix.empty()) { // print as a prefixed unit os << prefix; } @@ -77,7 +78,10 @@ namespace units { os << "^(" << abs(E::num) << "/" << E::den << ")"; } else if constexpr(abs(E::num) != 1) { - os << "^" << abs(E::num); + // if constexpr(is_unicode) + // os << superscript; + // else + os << "^" << abs(E::num); } first = false; }; diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 380bd911..ff7b55ac 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -23,7 +23,8 @@ #pragma once #include -#include +#include +#include #include #include @@ -283,7 +284,7 @@ namespace units { os << q.count() << " "; if constexpr(!detail::is_unit) { // print user-defined unit - os << unit::symbol::c_str(); + os << unit::symbol; } else { using ratio = quantity::unit::ratio; @@ -291,8 +292,8 @@ namespace units { if constexpr(!detail::is_dimension) { // print as a prefix or ratio of a coherent unit symbol defined by the user using coherent_unit = downcast_target>>; - detail::print_prefix_or_ratio(os); - os << coherent_unit::symbol::c_str(); + detail::print_prefix_or_ratio(os); + os << coherent_unit::symbol; } else { // print as a ratio of a coherent unit diff --git a/src/include/units/unit.h b/src/include/units/unit.h index 596bc439..9b9efaa7 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -52,6 +52,30 @@ namespace units { std::is_empty_v && detail::is_unit>; + template + struct prefix { + using prefix_type = PrefixType; + using ratio = R; + static constexpr auto symbol = Symbol; + }; + + + // TODO gcc:92150 + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150 + // namespace detail { + + // template + // inline constexpr bool is_prefix = false; + + // template + // inline constexpr bool is_prefix> = true; + + // } // namespace detail + + template +// concept Prefix = detail::is_prefix; + concept Prefix = true; + // make_derived_unit namespace detail { @@ -115,56 +139,29 @@ namespace units { // derived_unit - // TODO gcc:92101 - // Gated by the following gcc bug - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92101 - // template - // struct derived_unit; - - // template - // struct derived_unit : downcast_helper>> { - // static constexpr auto symbol = Symbol; - // }; - - // template - // struct derived_unit : downcast_helper> { - // static constexpr auto symbol = Symbol; - // }; - - // template - // struct derived_unit : downcast_helper { - // static constexpr auto symbol = Symbol; - // }; - - // template - // struct derived_unit : downcast_helper> { - // static constexpr auto symbol = Symbol; - // }; - struct no_prefix; - template + template struct coherent_derived_unit : downcast_helper>> { - using symbol = Symbol; - using prefix = Prefix; + static constexpr auto symbol = Symbol; + using prefix_type = PrefixType; }; - template - struct derived_unit; - - template - struct derived_unit : downcast_helper> { - using symbol = Symbol; + template + struct derived_unit : downcast_helper> { + static constexpr auto symbol = Symbol; }; - template - struct derived_unit : downcast_helper { - using symbol = Symbol; + template + requires requires { U::symbol; } && std::same_as + struct prefixed_derived_unit : downcast_helper>> { + static constexpr auto symbol = P::symbol + U::symbol; + using prefix_type = P::prefix_type; }; - template - struct derived_unit : downcast_helper> { - using symbol = Symbol; + template + struct deduced_derived_unit : downcast_helper> { + static constexpr auto symbol = Symbol; }; } // namespace units diff --git a/test/unit_test/runtime/digital_information_test.cpp b/test/unit_test/runtime/digital_information_test.cpp index 82315c68..1f0da6a6 100644 --- a/test/unit_test/runtime/digital_information_test.cpp +++ b/test/unit_test/runtime/digital_information_test.cpp @@ -33,13 +33,11 @@ namespace data { template concept DigitalInformation = units::QuantityOf; - using namespace units::hacks; - struct data_prefix; - struct bit : units::coherent_derived_unit {}; - struct kilobit : units::derived_unit> {}; - struct byte : units::derived_unit> {}; + struct bit : units::coherent_derived_unit {}; + struct kilobit : units::derived_unit> {}; + struct byte : units::derived_unit> {}; inline namespace literals { diff --git a/test/unit_test/runtime/text_test.cpp b/test/unit_test/runtime/text_test.cpp index 4a3e4b2f..6ca8d70e 100644 --- a/test/unit_test/runtime/text_test.cpp +++ b/test/unit_test/runtime/text_test.cpp @@ -48,6 +48,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream]") stream << 72.5kJ; REQUIRE(stream.str() == "72.5 kJ"); } + + SECTION("unit with a prefix") + { + stream << 125us; + REQUIRE(stream.str() == "125 µs"); + } } SECTION("quantity with a predefined dimension but unknown unit") @@ -172,4 +178,13 @@ TEST_CASE("operator<< on a quantity", "[text][ostream]") // } // Restate operator<< definitions in terms of std::format to make I/O manipulators apply to whole objects -// rather than their parts \ No newline at end of file +// rather than their parts + + +// Giving a precision specification +// in the chrono-format-spec is valid only for std::chrono::duration types where the representation type Rep +// is a floating-point type. For all other Rep types, a format_error shall be thrown if the chrono-format-spec +// contains a precision specification. + + // string s = format("{:=>8}", 42ms); // value of s is "====42ms" + diff --git a/test/unit_test/static/custom_unit_test.cpp b/test/unit_test/static/custom_unit_test.cpp index 66660e82..f01f64ca 100644 --- a/test/unit_test/static/custom_unit_test.cpp +++ b/test/unit_test/static/custom_unit_test.cpp @@ -35,12 +35,10 @@ namespace { template concept DigitalInformation = units::QuantityOf; - using namespace units::hacks; - struct data_prefix {}; - struct bit : units::coherent_derived_unit {}; - struct byte : units::derived_unit> {}; + struct bit : units::coherent_derived_unit {}; + struct byte : units::derived_unit> {}; inline namespace literals { @@ -65,11 +63,11 @@ namespace { // power spectral density struct power_spectral_density : derived_dimension, units::exp> {}; - struct sq_volt_per_hertz : coherent_derived_unit {}; + struct sq_volt_per_hertz : coherent_derived_unit {}; // amplitude spectral density struct amplitude_spectral_density : derived_dimension, units::exp> {}; - struct volt_per_sqrt_hertz : coherent_derived_unit {}; + struct volt_per_sqrt_hertz : coherent_derived_unit {}; } namespace {