From 0125bd7762e48049cfd0a1eb201480ef2b7ba03a Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 8 Nov 2019 16:51:45 +0000 Subject: [PATCH] Derived unit factory helpers refactored --- README.md | 5 +- doc/DESIGN.md | 77 +++++++++++-------- src/include/units/dimensions/capacitance.h | 2 +- src/include/units/dimensions/current.h | 2 +- .../units/dimensions/electric_charge.h | 2 +- src/include/units/dimensions/energy.h | 2 +- src/include/units/dimensions/force.h | 2 +- src/include/units/dimensions/frequency.h | 2 +- src/include/units/dimensions/length.h | 10 +-- .../units/dimensions/luminous_intensity.h | 2 +- src/include/units/dimensions/mass.h | 2 +- src/include/units/dimensions/power.h | 2 +- src/include/units/dimensions/pressure.h | 2 +- src/include/units/dimensions/si_prefixes.h | 2 +- src/include/units/dimensions/substance.h | 2 +- src/include/units/dimensions/temperature.h | 2 +- src/include/units/dimensions/time.h | 6 +- src/include/units/dimensions/voltage.h | 2 +- src/include/units/prefix.h | 17 ++-- src/include/units/unit.h | 43 ++++++----- .../runtime/digital_information_test.cpp | 6 +- test/unit_test/static/cgs_test.cpp | 10 +-- test/unit_test/static/custom_unit_test.cpp | 6 +- 23 files changed, 116 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 77396d3f..b2331c6c 100644 --- a/README.md +++ b/README.md @@ -118,9 +118,10 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer. - `units` removed from a `std::experimental` namespace - Downcasting facility refactored so the user does not have to write the boilerplate code anymore - From now on base dimensions should inherit from `base_dimension` class template - - Added unit symbols definitions to `base_dimension` and `derived_unit` - - Added `coherent_derived_unit` helper + - Added unit symbols definitions to `base_dimension` and derived units - Added support for `operator<<` on `quantity` + - `fmt` support added + - Derived unit factory helpers refactored - Refactored the way prefixed units are defined - 0.3.1 Sep 18, 2019 diff --git a/doc/DESIGN.md b/doc/DESIGN.md index 46a6aef9..c1a35c85 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -246,62 +246,74 @@ concept Unit = detail::is_unit>; // exposition only ``` +The library provides a bunch of helpers to create the derived unit: +- `named_coherent_derived_unit` +- `coherent_derived_unit` +- `named_scaled_derived_unit` +- `named_deduced_derived_unit` +- `deduced_derived_unit` +- `prefixed_derived_unit` + Coherent derived units (units with `ratio<1>`) are created with a `named_coherent_derived_unit` or `coherent_derived_unit` class templates: ```cpp -template -struct named_coherent_derived_unit : downcast_child>> { +template +struct named_coherent_derived_unit : downcast_child>> { static constexpr auto symbol = Symbol; - using prefix_type = PrefixType; + using prefix_type = PT; }; -template -struct coherent_derived_unit : downcast_child>> { +template +struct coherent_derived_unit : downcast_child>> { static constexpr auto symbol = /* ... */; - using prefix_type = PrefixType; + using prefix_type = no_prefix; }; ``` 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). +data) and should satisfy the following concept: + +```cpp +template +concept PrefixType = std::derived_from; +``` For example to define the coherent unit of `length`: ```cpp -struct metre : named_coherent_derived_unit {}; +struct metre : named_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 templates can be used: +To create scaled unit the following template should be used: ```cpp -template -struct named_derived_unit : downcast_child> { +template +struct named_scaled_derived_unit : downcast_child> { static constexpr auto symbol = Symbol; + using prefix_type = PT; }; ``` -User has to provide a symbol name (in case of a named unit), dimension, and a ratio relative -to a coherent derived unit. For example to define `minute`: +For example to define `minute`: ```cpp -struct minute : named_derived_unit> {}; +struct minute : named_scaled_derived_unit> {}; ``` -The `mp-units` library provides also a few helper class templates to simplify the above process. - +The `mp-units` library provides also a 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; } + requires (!std::same_as) struct prefixed_derived_unit : downcast_child>> { + ratio_multiply>> { static constexpr auto symbol = P::symbol + U::symbol; using prefix_type = P::prefix_type; }; @@ -310,8 +322,8 @@ struct prefixed_derived_unit : downcast_child -struct prefix : downcast_child> { +template +struct prefix : downcast_child> { static constexpr auto symbol = Symbol; }; ``` @@ -323,25 +335,28 @@ or its symbol and just has to do the following: struct kilometre : prefixed_derived_unit {}; ``` -SI prefixes are predefined in the library and the user may easily predefined his/her own with: +SI prefixes are predefined in the library and the user may easily provide his/her own with: ```cpp -struct data_prefix; +struct data_prefix : units::prefix_type {}; -struct kibi : units::prefix, "Ki"> {}; +struct kibi : units::prefix, "Ki"> {}; +struct mebi : units::prefix, "Mi"> {}; ``` For the cases where determining the exact ratio is not trivial another helper can be used: ```cpp -template -struct named_deduced_derived_unit : downcast_child> { +template +struct named_deduced_derived_unit : downcast_child { static constexpr auto symbol = Symbol; + using prefix_type = PT; }; -template -struct deduced_derived_unit : downcast_child> { - static constexpr auto symbol = /* ... */; +template +struct deduced_derived_unit : downcast_child { + static constexpr auto symbol = /* even more magic to get the correct unit symbol */; + using prefix_type = no_prefix; }; ``` @@ -350,7 +365,7 @@ dimension and in case the symbol name is not explicitly provided it with create on the provided ingredients: ```cpp -struct mile_per_hour : deduced_derived_unit {}; +struct kilometre_per_hour : deduced_derived_unit {}; ``` @@ -590,7 +605,7 @@ aliases. template struct downcast_base { using base_type = BaseType; - friend auto downcast_guide(downcast_base); + friend auto downcast_guide(downcast_base); // declaration only (no implementation) }; ``` diff --git a/src/include/units/dimensions/capacitance.h b/src/include/units/dimensions/capacitance.h index 42558471..736fc9a6 100644 --- a/src/include/units/dimensions/capacitance.h +++ b/src/include/units/dimensions/capacitance.h @@ -33,7 +33,7 @@ namespace units { template concept Capacitance = QuantityOf; - struct farad : named_coherent_derived_unit {}; + struct farad : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/current.h b/src/include/units/dimensions/current.h index bf2c608f..072f9a8e 100644 --- a/src/include/units/dimensions/current.h +++ b/src/include/units/dimensions/current.h @@ -32,7 +32,7 @@ namespace units { template concept Current = QuantityOf; - struct ampere : named_coherent_derived_unit {}; + struct ampere : named_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 98c0f118..20586ef8 100644 --- a/src/include/units/dimensions/electric_charge.h +++ b/src/include/units/dimensions/electric_charge.h @@ -33,7 +33,7 @@ namespace units { template concept ElectricCharge = QuantityOf; - struct coulomb : named_coherent_derived_unit {}; + struct coulomb : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/energy.h b/src/include/units/dimensions/energy.h index 51c7fea5..709a1b14 100644 --- a/src/include/units/dimensions/energy.h +++ b/src/include/units/dimensions/energy.h @@ -34,7 +34,7 @@ namespace units { template concept Energy = QuantityOf; - struct joule : named_coherent_derived_unit {}; + struct joule : named_coherent_derived_unit {}; struct millijoule : prefixed_derived_unit {}; struct kilojoule : prefixed_derived_unit {}; struct megajoule : prefixed_derived_unit {}; diff --git a/src/include/units/dimensions/force.h b/src/include/units/dimensions/force.h index 691f2988..798b3220 100644 --- a/src/include/units/dimensions/force.h +++ b/src/include/units/dimensions/force.h @@ -33,7 +33,7 @@ namespace units { template concept Force = QuantityOf; - struct newton : named_coherent_derived_unit {}; + struct newton : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/frequency.h b/src/include/units/dimensions/frequency.h index 39bd2ebd..ff01380f 100644 --- a/src/include/units/dimensions/frequency.h +++ b/src/include/units/dimensions/frequency.h @@ -33,7 +33,7 @@ namespace units { template concept Frequency = QuantityOf; - struct hertz : named_coherent_derived_unit {}; + struct hertz : named_coherent_derived_unit {}; struct millihertz : prefixed_derived_unit {}; struct kilohertz : prefixed_derived_unit {}; struct megahertz : prefixed_derived_unit {}; diff --git a/src/include/units/dimensions/length.h b/src/include/units/dimensions/length.h index 26c9fa6b..608c87bb 100644 --- a/src/include/units/dimensions/length.h +++ b/src/include/units/dimensions/length.h @@ -34,7 +34,7 @@ namespace units { concept Length = QuantityOf; // SI units - struct metre : named_coherent_derived_unit {}; + struct metre : named_coherent_derived_unit {}; struct millimetre : prefixed_derived_unit {}; struct centimetre : prefixed_derived_unit {}; struct kilometre : prefixed_derived_unit {}; @@ -60,10 +60,10 @@ namespace units { } // namespace literals // US customary units - struct yard : named_derived_unit> {}; - struct foot : named_derived_unit, yard::ratio>> {}; - struct inch : named_derived_unit, foot::ratio>> {}; - struct mile : named_derived_unit, yard::ratio>> {}; + struct yard : named_scaled_derived_unit> {}; + struct foot : named_scaled_derived_unit, yard::ratio>> {}; + struct inch : named_scaled_derived_unit, foot::ratio>> {}; + struct mile : named_scaled_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 dcf8803d..736da752 100644 --- a/src/include/units/dimensions/luminous_intensity.h +++ b/src/include/units/dimensions/luminous_intensity.h @@ -32,7 +32,7 @@ namespace units { template concept LuminousIntensity = QuantityOf; - struct candela : named_coherent_derived_unit {}; + struct candela : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/mass.h b/src/include/units/dimensions/mass.h index b6e72687..d5da2587 100644 --- a/src/include/units/dimensions/mass.h +++ b/src/include/units/dimensions/mass.h @@ -32,7 +32,7 @@ namespace units { template concept Mass = QuantityOf; - struct gram : named_derived_unit> {}; + struct gram : named_scaled_derived_unit, si_prefix> {}; struct kilogram : prefixed_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/power.h b/src/include/units/dimensions/power.h index 3d8ead4b..d83642da 100644 --- a/src/include/units/dimensions/power.h +++ b/src/include/units/dimensions/power.h @@ -33,7 +33,7 @@ namespace units { template concept Power = QuantityOf; - struct watt : named_coherent_derived_unit {}; + struct watt : named_coherent_derived_unit {}; struct milliwatt : prefixed_derived_unit {}; struct kilowatt : prefixed_derived_unit {}; struct megawatt : prefixed_derived_unit {}; diff --git a/src/include/units/dimensions/pressure.h b/src/include/units/dimensions/pressure.h index 85479866..4302ed26 100644 --- a/src/include/units/dimensions/pressure.h +++ b/src/include/units/dimensions/pressure.h @@ -33,7 +33,7 @@ namespace units { template concept Pressure = QuantityOf; - struct pascal : named_coherent_derived_unit {}; + struct pascal : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/si_prefixes.h b/src/include/units/dimensions/si_prefixes.h index 9f43bbb3..a2d5bc5c 100644 --- a/src/include/units/dimensions/si_prefixes.h +++ b/src/include/units/dimensions/si_prefixes.h @@ -28,7 +28,7 @@ namespace units { // prefix tags - struct si_prefix; + struct si_prefix : prefix_type {}; // SI prefixes diff --git a/src/include/units/dimensions/substance.h b/src/include/units/dimensions/substance.h index 191422aa..54b15fa4 100644 --- a/src/include/units/dimensions/substance.h +++ b/src/include/units/dimensions/substance.h @@ -32,7 +32,7 @@ namespace units { template concept Substance = QuantityOf; - struct mole : named_coherent_derived_unit {}; + struct mole : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/temperature.h b/src/include/units/dimensions/temperature.h index d15e9b68..5a26a56a 100644 --- a/src/include/units/dimensions/temperature.h +++ b/src/include/units/dimensions/temperature.h @@ -32,7 +32,7 @@ namespace units { template concept ThermodynamicTemperature = QuantityOf; - struct kelvin : named_coherent_derived_unit {}; + struct kelvin : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/dimensions/time.h b/src/include/units/dimensions/time.h index 4f96c1fc..3c60e384 100644 --- a/src/include/units/dimensions/time.h +++ b/src/include/units/dimensions/time.h @@ -33,12 +33,12 @@ namespace units { template concept Time = QuantityOf; - struct second : named_coherent_derived_unit {}; + struct second : named_coherent_derived_unit {}; struct nanosecond : prefixed_derived_unit {}; struct microsecond : prefixed_derived_unit {}; struct millisecond : prefixed_derived_unit {}; - struct minute : named_derived_unit> {}; - struct hour : named_derived_unit> {}; + struct minute : named_scaled_derived_unit> {}; + struct hour : named_scaled_derived_unit> {}; inline namespace literals { diff --git a/src/include/units/dimensions/voltage.h b/src/include/units/dimensions/voltage.h index 688123ef..b4581061 100644 --- a/src/include/units/dimensions/voltage.h +++ b/src/include/units/dimensions/voltage.h @@ -35,7 +35,7 @@ namespace units { template concept Voltage = QuantityOf; - struct volt : named_coherent_derived_unit {}; + struct volt : named_coherent_derived_unit {}; inline namespace literals { diff --git a/src/include/units/prefix.h b/src/include/units/prefix.h index 6a12c288..1677644b 100644 --- a/src/include/units/prefix.h +++ b/src/include/units/prefix.h @@ -28,18 +28,23 @@ namespace units { + struct prefix_type {}; + + template + concept PrefixType = std::derived_from; + namespace detail { - template - struct prefix_base : downcast_base> { - using prefix_type = PrefixType; + template + struct prefix_base : downcast_base> { + using prefix_type = PT; using ratio = R; }; } - template - struct prefix : downcast_child> { + template + struct prefix : downcast_child> { static constexpr auto symbol = Symbol; }; @@ -60,6 +65,6 @@ namespace units { // concept Prefix = detail::is_prefix; concept Prefix = true; - struct no_prefix; + struct no_prefix : prefix_type {}; } // namespace units diff --git a/src/include/units/unit.h b/src/include/units/unit.h index a4c9b117..218e80c8 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -273,38 +273,41 @@ namespace units { // derived_unit - template - struct named_coherent_derived_unit : downcast_child>> { + template + struct named_coherent_derived_unit : downcast_child>> { static constexpr auto symbol = Symbol; - using prefix_type = PrefixType; + using prefix_type = PT; }; - template - struct coherent_derived_unit : downcast_child>> { - static constexpr auto symbol = detail::symbol_text(D()); - using prefix_type = PrefixType; + template + struct coherent_derived_unit : downcast_child>> { + static constexpr auto symbol = detail::symbol_text(Dim()); + using prefix_type = no_prefix; }; - template - struct named_derived_unit : downcast_child> { + template + struct named_scaled_derived_unit : downcast_child> { static constexpr auto symbol = Symbol; + using prefix_type = PT; + }; + + template + struct named_deduced_derived_unit : downcast_child> { + static constexpr auto symbol = Symbol; + using prefix_type = PT; + }; + + template + struct deduced_derived_unit : downcast_child> { + static constexpr auto symbol = basic_fixed_string("bbb"); + using prefix_type = no_prefix; }; template - requires requires { U::symbol; } + requires (!std::same_as) struct prefixed_derived_unit : downcast_child>> { static constexpr auto symbol = P::symbol + U::symbol; using prefix_type = P::prefix_type; }; - template - struct named_deduced_derived_unit : downcast_child> { - static constexpr auto symbol = Symbol; - }; - - template - struct deduced_derived_unit : downcast_child> { - static constexpr auto symbol = basic_fixed_string("bbb"); - }; - } // namespace units diff --git a/test/unit_test/runtime/digital_information_test.cpp b/test/unit_test/runtime/digital_information_test.cpp index 822ac5c1..600c17e6 100644 --- a/test/unit_test/runtime/digital_information_test.cpp +++ b/test/unit_test/runtime/digital_information_test.cpp @@ -33,14 +33,14 @@ namespace data { template concept DigitalInformation = units::QuantityOf; - struct data_prefix; + struct data_prefix : units::prefix_type {}; struct kibi : units::prefix, "Ki"> {}; struct mebi : units::prefix, "Mi"> {}; - struct bit : units::named_coherent_derived_unit {}; + struct bit : units::named_coherent_derived_unit {}; struct kilobit : units::prefixed_derived_unit {}; - struct byte : units::named_derived_unit> {}; + struct byte : units::named_scaled_derived_unit, data_prefix> {}; struct kilobyte : units::prefixed_derived_unit {}; inline namespace literals { diff --git a/test/unit_test/static/cgs_test.cpp b/test/unit_test/static/cgs_test.cpp index ab8e3140..341126f2 100644 --- a/test/unit_test/static/cgs_test.cpp +++ b/test/unit_test/static/cgs_test.cpp @@ -31,11 +31,11 @@ namespace cgs { using units::gram; using units::second; struct centimetre_per_second : units::deduced_derived_unit {}; - struct gal : units::named_deduced_derived_unit {}; - struct dyne : units::named_deduced_derived_unit {}; - struct erg : units::named_deduced_derived_unit {}; - struct ergps : units::named_deduced_derived_unit {}; // TODO make it work for erg and non-named - struct barye : units::named_deduced_derived_unit {}; + struct gal : units::named_deduced_derived_unit {}; + struct dyne : units::named_deduced_derived_unit {}; + struct erg : units::named_deduced_derived_unit {}; + struct ergps : units::named_deduced_derived_unit {}; // TODO make it work for erg and non-named + struct barye : units::named_deduced_derived_unit {}; inline namespace literals { diff --git a/test/unit_test/static/custom_unit_test.cpp b/test/unit_test/static/custom_unit_test.cpp index 95f923ec..2df947e8 100644 --- a/test/unit_test/static/custom_unit_test.cpp +++ b/test/unit_test/static/custom_unit_test.cpp @@ -35,14 +35,14 @@ namespace { template concept DigitalInformation = units::QuantityOf; - struct data_prefix {}; + struct data_prefix : units::prefix_type {}; struct kibi : units::prefix, "Ki"> {}; - struct bit : units::named_coherent_derived_unit {}; + struct bit : units::named_coherent_derived_unit {}; struct kilobit : units::prefixed_derived_unit {}; - struct byte : units::named_derived_unit> {}; + struct byte : units::named_scaled_derived_unit, data_prefix> {}; struct kilobyte : units::prefixed_derived_unit {}; inline namespace literals {