Deduced units symbols refactoring started

This commit is contained in:
Mateusz Pusz
2019-11-04 06:37:50 +00:00
parent 7e844ef773
commit 91bcfedf1e
31 changed files with 329 additions and 128 deletions

View File

@@ -246,15 +246,21 @@ concept Unit =
detail::is_unit<downcast_base_t<T>>; // exposition only detail::is_unit<downcast_base_t<T>>; // exposition only
``` ```
Coherent derived units (units with `ratio<1>`) are created with a `coherent_derived_unit` class Coherent derived units (units with `ratio<1>`) are created with a `named_coherent_derived_unit`
template: or `coherent_derived_unit` class templates:
```cpp ```cpp
template<typename Child, fixed_string Symbol, Dimension D, typename PrefixType = no_prefix> template<typename Child, basic_fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> { struct named_coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
using prefix_type = PrefixType; using prefix_type = PrefixType;
}; };
template<typename Child, Dimension D, typename PrefixType = no_prefix>
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
static constexpr auto symbol = /* ... */;
using prefix_type = PrefixType;
};
``` ```
The above exposes public `prefix_type` member type and `symbol` used to print unit symbol The above exposes public `prefix_type` member type and `symbol` used to print unit symbol
@@ -264,26 +270,31 @@ data).
For example to define the coherent unit of `length`: For example to define the coherent unit of `length`:
```cpp ```cpp
struct metre : coherent_derived_unit<metre, "m", length, si_prefix> {}; struct metre : named_coherent_derived_unit<metre, "m", length, si_prefix> {};
``` ```
Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used
to provide downcasting facility (described below). to provide downcasting facility (described below).
To create the rest of derived units the following class template can be used: To create the rest of derived units the following class templates can be used:
```cpp ```cpp
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R> template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
struct derived_unit : downcast_child<Child, unit<D, R>> { struct named_derived_unit : downcast_child<Child, unit<D, R>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
}; };
template<typename Child, Dimension D, Ratio R>
struct derived_unit : downcast_child<Child, unit<D, R>> {
static constexpr auto symbol = /* ... */;
};
``` ```
User has to provide a symbol name, dimension, and a ratio relative to a coherent derived unit. User has to provide a symbol name (in case of a named unit), dimension, and a ratio relative
For example to define `minute`: to a coherent derived unit. For example to define `minute`:
```cpp ```cpp
struct minute : derived_unit<minute, "min", time, ratio<60>> {}; struct minute : named_derived_unit<minute, "min", time, ratio<60>> {};
``` ```
The `mp-units` library provides also a few helper class templates to simplify the above process. The `mp-units` library provides also a few helper class templates to simplify the above process.
@@ -329,16 +340,22 @@ For the cases where determining the exact ratio is not trivial another helper ca
```cpp ```cpp
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us> template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> { struct named_deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
}; };
template<typename Child, Dimension D, Unit U, Unit... Us>
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
static constexpr auto symbol = /* ... */;
};
``` ```
This will deduce the ratio based on the ingredient units and their relation defined in the This will deduce the ratio based on the ingredient units and their relation defined in the
dimension: dimension and in case the symbol name is not explicitly provided it with create one based
on the provided ingredients:
```cpp ```cpp
struct mile_per_hour : deduced_derived_unit<mile_per_hour, "mi/h", velocity, mile, hour> {}; struct mile_per_hour : deduced_derived_unit<mile_per_hour, velocity, mile, hour> {};
``` ```

View File

@@ -22,7 +22,8 @@
#pragma once #pragma once
#include <units/unit.h> #include <units/dimension.h>
#include <units/prefix.h>
#include <ostream> #include <ostream>
#include <string_view> #include <string_view>
@@ -61,30 +62,92 @@ namespace units {
} }
} }
template<typename CharT, typename Traits, typename... Es>
void print_dimensions(std::basic_ostream<CharT, Traits>& os, dimension<Es...>) template<int Value>
requires (0 <= Value) && (Value < 10)
inline constexpr basic_fixed_string superscript_number = "\u2070";
// template<> inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
template<> inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
template<> inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
template<> inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
template<> inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
template<> inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
template<> inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
template<> inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
template<> inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
template<> inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
template<int Value>
requires (Value >= 0)
constexpr auto superscript()
{ {
bool first = true; if constexpr(Value < 10)
auto ingr_printer = [&]<typename E>(E) { return superscript_number<Value>;
if constexpr(E::num < 0) { else
os << (first ? "1/" : "/"); return superscript<Value / 10>() + superscript<Value % 10>();
}
template<int Value>
requires (Value >= 0)
constexpr auto regular()
{
if constexpr(Value < 10)
return basic_fixed_string(static_cast<char>('0' + Value));
else
return regular<Value / 10>() + regular<Value % 10>();
}
template<bool Divide, std::size_t Idx>
constexpr auto operator_txt()
{
if constexpr(Idx == 0) {
if constexpr(Divide) {
return basic_fixed_string("1/");
} }
else { else {
os << (first ? "" : ""); return basic_fixed_string("");
} }
os << E::dimension::symbol; }
else {
if constexpr(Divide) {
return basic_fixed_string("/");
}
else {
return basic_fixed_string("");
}
}
}
template<typename E, std::size_t Idx>
constexpr auto exp_txt()
{
// get calculation operator + symbol
const auto txt = operator_txt<E::num < 0, Idx>() + E::dimension::symbol;
if constexpr(E::den != 1) { if constexpr(E::den != 1) {
os << "^(" << abs(E::num) << "/" << E::den << ")"; // add root part
return txt + basic_fixed_string("^(") + regular<abs(E::num)>() + basic_fixed_string("/") + regular<E::den>() + basic_fixed_string(")");
} }
else if constexpr(abs(E::num) != 1) { else if constexpr(abs(E::num) != 1) {
// if constexpr(is_unicode<CharT>) // add exponent part
// os << superscript<abs(E::num)>; return txt + superscript<abs(E::num)>();
// else
os << "^" << abs(E::num);
} }
first = false; else {
}; return txt;
(ingr_printer(Es{}), ...); }
}
template<typename... Es, std::size_t... Idxs>
constexpr auto symbol_text_impl(dimension<Es...>, std::index_sequence<Idxs...>)
{
return (exp_txt<Es, Idxs>() + ...);
}
template<typename... Es>
constexpr auto symbol_text(dimension<Es...> d)
{
return symbol_text_impl<>(d, std::index_sequence_for<Es...>());
} }
} }

View File

@@ -31,7 +31,7 @@ namespace units {
template<typename T> template<typename T>
concept Acceleration = QuantityOf<T, acceleration>; concept Acceleration = QuantityOf<T, acceleration>;
struct metre_per_second_sq : coherent_derived_unit<metre_per_second_sq, "m/s^2", acceleration> {}; struct metre_per_second_sq : coherent_derived_unit<metre_per_second_sq, acceleration> {};
inline namespace literals { inline namespace literals {

View File

@@ -31,11 +31,11 @@ namespace units {
template<typename T> template<typename T>
concept Area = QuantityOf<T, area>; concept Area = QuantityOf<T, area>;
struct square_metre : coherent_derived_unit<square_metre, "m^2", area> {}; struct square_metre : coherent_derived_unit<square_metre, area> {};
struct square_millimetre : deduced_derived_unit<square_millimetre, "mm^2", area, millimetre> {}; struct square_millimetre : deduced_derived_unit<square_millimetre, area, millimetre> {};
struct square_centimetre : deduced_derived_unit<square_centimetre, "cm^2", area, centimetre> {}; struct square_centimetre : deduced_derived_unit<square_centimetre, area, centimetre> {};
struct square_kilometre : deduced_derived_unit<square_kilometre, "km^2", area, kilometre> {}; struct square_kilometre : deduced_derived_unit<square_kilometre, area, kilometre> {};
struct square_foot : deduced_derived_unit<square_foot, "ft^2", area, foot> {}; struct square_foot : deduced_derived_unit<square_foot, area, foot> {};
inline namespace literals { inline namespace literals {

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept Capacitance = QuantityOf<T, capacitance>; concept Capacitance = QuantityOf<T, capacitance>;
struct farad : coherent_derived_unit<farad, "F", capacitance, si_prefix> {}; struct farad : named_coherent_derived_unit<farad, "F", capacitance, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,7 +32,7 @@ namespace units {
template<typename T> template<typename T>
concept Current = QuantityOf<T, current>; concept Current = QuantityOf<T, current>;
struct ampere : coherent_derived_unit<ampere, "A", current, si_prefix> {}; struct ampere : named_coherent_derived_unit<ampere, "A", current, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept ElectricCharge = QuantityOf<T, electric_charge>; concept ElectricCharge = QuantityOf<T, electric_charge>;
struct coulomb : coherent_derived_unit<coulomb, "C", electric_charge, si_prefix> {}; struct coulomb : named_coherent_derived_unit<coulomb, "C", electric_charge, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -34,7 +34,7 @@ namespace units {
template<typename T> template<typename T>
concept Energy = QuantityOf<T, energy>; concept Energy = QuantityOf<T, energy>;
struct joule : coherent_derived_unit<joule, "J", energy, si_prefix> {}; struct joule : named_coherent_derived_unit<joule, "J", energy, si_prefix> {};
struct millijoule : prefixed_derived_unit<millijoule, milli, joule> {}; struct millijoule : prefixed_derived_unit<millijoule, milli, joule> {};
struct kilojoule : prefixed_derived_unit<kilojoule, kilo, joule> {}; struct kilojoule : prefixed_derived_unit<kilojoule, kilo, joule> {};
struct megajoule : prefixed_derived_unit<megajoule, mega, joule> {}; struct megajoule : prefixed_derived_unit<megajoule, mega, joule> {};

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept Force = QuantityOf<T, force>; concept Force = QuantityOf<T, force>;
struct newton : coherent_derived_unit<newton, "N", force, si_prefix> {}; struct newton : named_coherent_derived_unit<newton, "N", force, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept Frequency = QuantityOf<T, frequency>; concept Frequency = QuantityOf<T, frequency>;
struct hertz : coherent_derived_unit<hertz, "Hz", frequency, si_prefix> {}; struct hertz : named_coherent_derived_unit<hertz, "Hz", frequency, si_prefix> {};
struct millihertz : prefixed_derived_unit<millihertz, milli, hertz> {}; struct millihertz : prefixed_derived_unit<millihertz, milli, hertz> {};
struct kilohertz : prefixed_derived_unit<kilohertz, kilo, hertz> {}; struct kilohertz : prefixed_derived_unit<kilohertz, kilo, hertz> {};
struct megahertz : prefixed_derived_unit<megahertz, mega, hertz> {}; struct megahertz : prefixed_derived_unit<megahertz, mega, hertz> {};

View File

@@ -34,7 +34,7 @@ namespace units {
concept Length = QuantityOf<T, length>; concept Length = QuantityOf<T, length>;
// SI units // SI units
struct metre : coherent_derived_unit<metre, "m", length, si_prefix> {}; struct metre : named_coherent_derived_unit<metre, "m", length, si_prefix> {};
struct millimetre : prefixed_derived_unit<millimetre, milli, metre> {}; struct millimetre : prefixed_derived_unit<millimetre, milli, metre> {};
struct centimetre : prefixed_derived_unit<centimetre, centi, metre> {}; struct centimetre : prefixed_derived_unit<centimetre, centi, metre> {};
struct kilometre : prefixed_derived_unit<kilometre, kilo, metre> {}; struct kilometre : prefixed_derived_unit<kilometre, kilo, metre> {};
@@ -60,10 +60,10 @@ namespace units {
} // namespace literals } // namespace literals
// US customary units // US customary units
struct yard : derived_unit<yard, "yd", length, ratio<9'144, 10'000>> {}; struct yard : named_derived_unit<yard, "yd", length, ratio<9'144, 10'000>> {};
struct foot : derived_unit<foot, "ft", length, ratio_multiply<ratio<1, 3>, yard::ratio>> {}; struct foot : named_derived_unit<foot, "ft", length, ratio_multiply<ratio<1, 3>, yard::ratio>> {};
struct inch : derived_unit<inch, "in", length, ratio_multiply<ratio<1, 12>, foot::ratio>> {}; struct inch : named_derived_unit<inch, "in", length, ratio_multiply<ratio<1, 12>, foot::ratio>> {};
struct mile : derived_unit<mile, "mi", length, ratio_multiply<ratio<1'760>, yard::ratio>> {}; struct mile : named_derived_unit<mile, "mi", length, ratio_multiply<ratio<1'760>, yard::ratio>> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,7 +32,7 @@ namespace units {
template<typename T> template<typename T>
concept LuminousIntensity = QuantityOf<T, luminous_intensity>; concept LuminousIntensity = QuantityOf<T, luminous_intensity>;
struct candela : coherent_derived_unit<candela, "cd", luminous_intensity, si_prefix> {}; struct candela : named_coherent_derived_unit<candela, "cd", luminous_intensity, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,8 +32,8 @@ namespace units {
template<typename T> template<typename T>
concept Mass = QuantityOf<T, mass>; concept Mass = QuantityOf<T, mass>;
struct kilogram : coherent_derived_unit<kilogram, "kg", mass> {}; struct gram : named_derived_unit<gram, "g", mass, ratio<1, 1000>> {};
struct gram : derived_unit<gram, "g", mass, ratio<1, 1000>> {}; struct kilogram : prefixed_derived_unit<kilogram, kilo, gram> {};
inline namespace literals { inline namespace literals {

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept Power = QuantityOf<T, power>; concept Power = QuantityOf<T, power>;
struct watt : coherent_derived_unit<watt, "W", power, si_prefix> {}; struct watt : named_coherent_derived_unit<watt, "W", power, si_prefix> {};
struct milliwatt : prefixed_derived_unit<milliwatt, milli, watt> {}; struct milliwatt : prefixed_derived_unit<milliwatt, milli, watt> {};
struct kilowatt : prefixed_derived_unit<kilowatt, kilo, watt> {}; struct kilowatt : prefixed_derived_unit<kilowatt, kilo, watt> {};
struct megawatt : prefixed_derived_unit<megawatt, mega, watt> {}; struct megawatt : prefixed_derived_unit<megawatt, mega, watt> {};

View File

@@ -33,7 +33,7 @@ namespace units {
template<typename T> template<typename T>
concept Pressure = QuantityOf<T, pressure>; concept Pressure = QuantityOf<T, pressure>;
struct pascal : coherent_derived_unit<pascal, "Pa", pressure, si_prefix> {}; struct pascal : named_coherent_derived_unit<pascal, "Pa", pressure, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -36,7 +36,7 @@ namespace units {
struct femto : prefix<femto, si_prefix, ratio<1, std::femto::den>, "f"> {}; struct femto : prefix<femto, si_prefix, ratio<1, std::femto::den>, "f"> {};
struct pico : prefix<pico, si_prefix, ratio<1, std::pico::den>, "p"> {}; struct pico : prefix<pico, si_prefix, ratio<1, std::pico::den>, "p"> {};
struct nano : prefix<nano, si_prefix, ratio<1, std::nano::den>, "n"> {}; struct nano : prefix<nano, si_prefix, ratio<1, std::nano::den>, "n"> {};
struct micro : prefix<micro, si_prefix, ratio<1, std::micro::den>, "µ"> {}; struct micro : prefix<micro, si_prefix, ratio<1, std::micro::den>, "\u00b5"> {};
struct milli : prefix<milli, si_prefix, ratio<1, std::milli::den>, "m"> {}; struct milli : prefix<milli, si_prefix, ratio<1, std::milli::den>, "m"> {};
struct centi : prefix<centi, si_prefix, ratio<1, std::centi::den>, "c"> {}; struct centi : prefix<centi, si_prefix, ratio<1, std::centi::den>, "c"> {};
struct deci : prefix<deci, si_prefix, ratio<1, std::deci::den>, "d"> {}; struct deci : prefix<deci, si_prefix, ratio<1, std::deci::den>, "d"> {};

View File

@@ -32,7 +32,7 @@ namespace units {
template<typename T> template<typename T>
concept Substance = QuantityOf<T, substance>; concept Substance = QuantityOf<T, substance>;
struct mole : coherent_derived_unit<mole, "mol", substance, si_prefix> {}; struct mole : named_coherent_derived_unit<mole, "mol", substance, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,7 +32,7 @@ namespace units {
template<typename T> template<typename T>
concept ThermodynamicTemperature = QuantityOf<T, temperature>; concept ThermodynamicTemperature = QuantityOf<T, temperature>;
struct kelvin : coherent_derived_unit<kelvin, "K", temperature> {}; struct kelvin : named_coherent_derived_unit<kelvin, "K", temperature> {};
inline namespace literals { inline namespace literals {

View File

@@ -33,12 +33,12 @@ namespace units {
template<typename T> template<typename T>
concept Time = QuantityOf<T, time>; concept Time = QuantityOf<T, time>;
struct second : coherent_derived_unit<second, "s", time, si_prefix> {}; struct second : named_coherent_derived_unit<second, "s", time, si_prefix> {};
struct nanosecond : prefixed_derived_unit<nanosecond, nano, second> {}; struct nanosecond : prefixed_derived_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_derived_unit<microsecond, micro, second> {}; struct microsecond : prefixed_derived_unit<microsecond, micro, second> {};
struct millisecond : prefixed_derived_unit<millisecond, milli, second> {}; struct millisecond : prefixed_derived_unit<millisecond, milli, second> {};
struct minute : derived_unit<minute, "min", time, ratio<60>> {}; struct minute : named_derived_unit<minute, "min", time, ratio<60>> {};
struct hour : derived_unit<hour, "h", time, ratio<3600>> {}; struct hour : named_derived_unit<hour, "h", time, ratio<3600>> {};
inline namespace literals { inline namespace literals {

View File

@@ -32,9 +32,9 @@ namespace units {
template<typename T> template<typename T>
concept Velocity = QuantityOf<T, velocity>; concept Velocity = QuantityOf<T, velocity>;
struct metre_per_second : coherent_derived_unit<metre_per_second, "m/s", velocity> {}; struct metre_per_second : coherent_derived_unit<metre_per_second, velocity> {};
struct kilometre_per_hour : deduced_derived_unit<kilometre_per_hour, "km/h", velocity, kilometre, hour> {}; struct kilometre_per_hour : deduced_derived_unit<kilometre_per_hour, velocity, kilometre, hour> {};
struct mile_per_hour : deduced_derived_unit<mile_per_hour, "mi/h", velocity, mile, hour> {}; struct mile_per_hour : deduced_derived_unit<mile_per_hour, velocity, mile, hour> {};
inline namespace literals { inline namespace literals {

View File

@@ -35,7 +35,7 @@ namespace units {
template<typename T> template<typename T>
concept Voltage = QuantityOf<T, voltage>; concept Voltage = QuantityOf<T, voltage>;
struct volt : coherent_derived_unit<volt, "V", voltage, si_prefix> {}; struct volt : named_coherent_derived_unit<volt, "V", voltage, si_prefix> {};
inline namespace literals { inline namespace literals {

View File

@@ -31,11 +31,11 @@ namespace units {
template<typename T> template<typename T>
concept Volume = QuantityOf<T, volume>; concept Volume = QuantityOf<T, volume>;
struct cubic_metre : coherent_derived_unit<cubic_metre, "m^3", volume> {}; struct cubic_metre : coherent_derived_unit<cubic_metre, volume> {};
struct cubic_millimetre : deduced_derived_unit<cubic_millimetre, "mm^3", volume, millimetre> {}; struct cubic_millimetre : deduced_derived_unit<cubic_millimetre, volume, millimetre> {};
struct cubic_centimetre : deduced_derived_unit<cubic_centimetre, "cm^3", volume, centimetre> {}; struct cubic_centimetre : deduced_derived_unit<cubic_centimetre, volume, centimetre> {};
struct cubic_kilometre : deduced_derived_unit<cubic_kilometre, "km^3", volume, kilometre, metre> {}; struct cubic_kilometre : deduced_derived_unit<cubic_kilometre, volume, kilometre, metre> {};
struct cubic_foot : deduced_derived_unit<cubic_foot, "ft^3", volume, foot> {}; struct cubic_foot : deduced_derived_unit<cubic_foot, volume, foot> {};
inline namespace literals { inline namespace literals {

View File

@@ -25,6 +25,7 @@
#include <units/quantity.h> #include <units/quantity.h>
#include <fmt/format.h> #include <fmt/format.h>
template<typename U, typename Rep, typename CharT> template<typename U, typename Rep, typename CharT>
struct fmt::formatter<units::quantity<U, Rep>, CharT> { struct fmt::formatter<units::quantity<U, Rep>, CharT> {
template<typename ParseContext> template<typename ParseContext>

View File

@@ -0,0 +1,65 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/downcasting.h>
#include <units/bits/fixed_string.h>
#include <units/ratio.h>
namespace units {
namespace detail {
template<typename PrefixType, Ratio R>
struct prefix_base : downcast_base<prefix_base<PrefixType, R>> {
using prefix_type = PrefixType;
using ratio = R;
};
}
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
struct prefix : downcast_child<Child, detail::prefix_base<PrefixType, R>> {
static constexpr auto symbol = Symbol;
};
// TODO gcc:92150
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150
// namespace detail {
// template<typename T>
// inline constexpr bool is_prefix = false;
// template<typename PrefixType, Ratio R, basic_fixed_string Symbol>
// inline constexpr bool is_prefix<prefix<PrefixType, R, Symbol>> = true;
// } // namespace detail
template<typename T>
// concept Prefix = detail::is_prefix<T>;
concept Prefix = true;
struct no_prefix;
} // namespace units

View File

@@ -302,7 +302,7 @@ namespace units {
detail::print_ratio<ratio>(os); detail::print_ratio<ratio>(os);
// print coherent unit dimensions and their exponents // print coherent unit dimensions and their exponents
detail::print_dimensions(os, dim{}); os << detail::symbol_text(dim{});
} }
} }
return os; return os;

View File

@@ -22,7 +22,9 @@
#pragma once #pragma once
#include <units/bits/format_utils.h>
#include <units/dimension.h> #include <units/dimension.h>
#include <units/prefix.h>
#include <units/ratio.h> #include <units/ratio.h>
#include <ratio> #include <ratio>
@@ -52,38 +54,6 @@ namespace units {
std::is_empty_v<T> && std::is_empty_v<T> &&
detail::is_unit<downcast_base_t<T>>; detail::is_unit<downcast_base_t<T>>;
namespace detail {
template<typename PrefixType, Ratio R>
struct prefix_base : downcast_base<prefix_base<PrefixType, R>> {
using prefix_type = PrefixType;
using ratio = R;
};
}
template<typename Child, typename PrefixType, Ratio R, basic_fixed_string Symbol>
struct prefix : downcast_child<Child, detail::prefix_base<PrefixType, R>> {
static constexpr auto symbol = Symbol;
};
// TODO gcc:92150
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150
// namespace detail {
// template<typename T>
// inline constexpr bool is_prefix = false;
// template<typename PrefixType, Ratio R, basic_fixed_string Symbol>
// inline constexpr bool is_prefix<prefix<PrefixType, R, Symbol>> = true;
// } // namespace detail
template<typename T>
// concept Prefix = detail::is_prefix<T>;
concept Prefix = true;
// make_derived_unit // make_derived_unit
namespace detail { namespace detail {
@@ -150,16 +120,27 @@ namespace units {
struct no_prefix; struct no_prefix;
template<typename Child, basic_fixed_string Symbol, Dimension D, typename PrefixType = no_prefix> template<typename Child, basic_fixed_string Symbol, Dimension D, typename PrefixType = no_prefix>
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> { struct named_coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
using prefix_type = PrefixType; using prefix_type = PrefixType;
}; };
template<typename Child, Dimension D, typename PrefixType = no_prefix>
struct coherent_derived_unit : downcast_child<Child, unit<D, ratio<1>>> {
static constexpr auto symbol = detail::symbol_text(D());
using prefix_type = PrefixType;
};
template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R> template<typename Child, basic_fixed_string Symbol, Dimension D, Ratio R>
struct derived_unit : downcast_child<Child, unit<D, R>> { struct named_derived_unit : downcast_child<Child, unit<D, R>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
}; };
template<typename Child, Dimension D, Ratio R>
struct derived_unit : downcast_child<Child, unit<D, R>> {
static constexpr auto symbol = "aaa";
};
template<typename Child, Prefix P, Unit U> template<typename Child, Prefix P, Unit U>
requires requires { U::symbol; } requires requires { U::symbol; }
struct prefixed_derived_unit : downcast_child<Child, unit<typename U::dimension, ratio_multiply<typename P::ratio, typename U::ratio>>> { struct prefixed_derived_unit : downcast_child<Child, unit<typename U::dimension, ratio_multiply<typename P::ratio, typename U::ratio>>> {
@@ -168,8 +149,13 @@ namespace units {
}; };
template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us> template<typename Child, basic_fixed_string Symbol, Dimension D, Unit U, Unit... Us>
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> { struct named_deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
static constexpr auto symbol = Symbol; static constexpr auto symbol = Symbol;
}; };
template<typename Child, Dimension D, Unit U, Unit... Us>
struct deduced_derived_unit : downcast_child<Child, detail::make_derived_unit<D, U, Us...>> {
static constexpr auto symbol = "bbb";
};
} // namespace units } // namespace units

View File

@@ -38,9 +38,9 @@ namespace data {
struct kibi : units::prefix<kibi, data_prefix, units::ratio< 1'024>, "Ki"> {}; struct kibi : units::prefix<kibi, data_prefix, units::ratio< 1'024>, "Ki"> {};
struct mebi : units::prefix<mebi, data_prefix, units::ratio<1'048'576>, "Mi"> {}; struct mebi : units::prefix<mebi, data_prefix, units::ratio<1'048'576>, "Mi"> {};
struct bit : units::coherent_derived_unit<bit, "b", digital_information, data_prefix> {}; struct bit : units::named_coherent_derived_unit<bit, "b", digital_information, data_prefix> {};
struct kilobit : units::prefixed_derived_unit<kilobit, kibi, bit> {}; struct kilobit : units::prefixed_derived_unit<kilobit, kibi, bit> {};
struct byte : units::derived_unit<byte, "B", digital_information, units::ratio<8>> {}; struct byte : units::named_derived_unit<byte, "B", digital_information, units::ratio<8>> {};
struct kilobyte : units::prefixed_derived_unit<kilobyte, kibi, byte> {}; struct kilobyte : units::prefixed_derived_unit<kilobyte, kibi, byte> {};
inline namespace literals { inline namespace literals {

View File

@@ -46,15 +46,51 @@ TEST_CASE("operator<< on a quantity", "[text][ostream]")
SECTION("floating-point representation") SECTION("floating-point representation")
{ {
stream << 72.5kJ; stream << 1023.5Pa;
REQUIRE(stream.str() == "72.5 kJ"); REQUIRE(stream.str() == "1023.5 Pa");
}
} }
SECTION("unit with a prefix") SECTION("quantity with a predefined unit + prefix")
{
SECTION("in terms of base units")
{ {
stream << 125us; stream << 125us;
REQUIRE(stream.str() == "125 µs"); REQUIRE(stream.str() == "125 µs");
} }
SECTION("in terms of derived units")
{
stream << 60kJ;
REQUIRE(stream.str() == "60 kJ");
}
}
SECTION("quantity with a deduced unit")
{
SECTION("coherent derived unit")
{
SECTION("acceleration")
{
stream << 20.m / 2s / 1s;
REQUIRE(stream.str() == "10 m/s²");
}
SECTION("volume")
{
stream << 2m * 1m * 1m;
REQUIRE(stream.str() == "2 m³");
}
}
SECTION("deduced derived unit")
{
SECTION("velocity")
{
stream << 20.km / 2h;
REQUIRE(stream.str() == "10 km/h");
}
}
} }
SECTION("quantity with a predefined dimension but unknown unit") SECTION("quantity with a predefined dimension but unknown unit")
@@ -68,7 +104,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream]")
SECTION("unit::ratio for a dimension without a special symbol") SECTION("unit::ratio for a dimension without a special symbol")
{ {
stream << 2.cm * 2m * 2m; stream << 2.cm * 2m * 2m;
REQUIRE(stream.str() == "8 [1/100]m^3"); REQUIRE(stream.str() == "8 [1/100]m³");
} }
SECTION("unit::ratio::num != 1 && unit::ratio::den == 1") SECTION("unit::ratio::num != 1 && unit::ratio::den == 1")
@@ -131,19 +167,19 @@ TEST_CASE("operator<< on a quantity", "[text][ostream]")
SECTION("exp::num == 2 && exp::den == 1 for positive exponent") SECTION("exp::num == 2 && exp::den == 1 for positive exponent")
{ {
stream << 4m * 2s * 2s; stream << 4m * 2s * 2s;
REQUIRE(stream.str() == "16 m⋅s^2"); REQUIRE(stream.str() == "16 m⋅s²");
} }
SECTION("exp::num == 2 && exp::den == 1 for negative exponent (first dimension)") SECTION("exp::num == 2 && exp::den == 1 for negative exponent (first dimension)")
{ {
stream << 8.s / 2m / 2m; stream << 8.s / 2m / 2m;
REQUIRE(stream.str() == "2 1/m^2⋅s"); REQUIRE(stream.str() == "2 1/m²⋅s");
} }
SECTION("exp::num == 2 && exp::den == 1 for negative exponent (not first dimension)") SECTION("exp::num == 2 && exp::den == 1 for negative exponent (not first dimension)")
{ {
stream << 8.m / 2kg / 2kg; stream << 8.m / 2kg / 2kg;
REQUIRE(stream.str() == "2 m/kg^2"); REQUIRE(stream.str() == "2 m/kg²");
} }
SECTION("fractional positive exponent") SECTION("fractional positive exponent")

View File

@@ -30,12 +30,12 @@ namespace cgs {
using units::centimetre; using units::centimetre;
using units::gram; using units::gram;
using units::second; using units::second;
struct centimetre_per_second : units::deduced_derived_unit<centimetre_per_second, "cm/s", units::velocity, centimetre, second> {}; struct centimetre_per_second : units::deduced_derived_unit<centimetre_per_second, units::velocity, centimetre, second> {};
struct gal : units::deduced_derived_unit<gal, "Gal", units::acceleration, centimetre, second> {}; struct gal : units::named_deduced_derived_unit<gal, "Gal", units::acceleration, centimetre, second> {};
struct dyne : units::deduced_derived_unit<dyne, "dyn", units::force, centimetre, gram, second> {}; struct dyne : units::named_deduced_derived_unit<dyne, "dyn", units::force, centimetre, gram, second> {};
struct erg : units::deduced_derived_unit<erg, "erg", units::energy, centimetre, gram, second> {}; struct erg : units::named_deduced_derived_unit<erg, "erg", units::energy, centimetre, gram, second> {};
struct ergps : units::deduced_derived_unit<ergps, "erg/s", units::power, centimetre, gram, second> {}; struct ergps : units::named_deduced_derived_unit<ergps, "erg/s", units::power, centimetre, gram, second> {}; // TODO make it work for erg and non-named
struct barye : units::deduced_derived_unit<barye, "Ba", units::pressure, centimetre, gram, second> {}; struct barye : units::named_deduced_derived_unit<barye, "Ba", units::pressure, centimetre, gram, second> {};
inline namespace literals { inline namespace literals {

View File

@@ -39,10 +39,10 @@ namespace {
struct kibi : units::prefix<kibi, data_prefix, units::ratio< 1'024>, "Ki"> {}; struct kibi : units::prefix<kibi, data_prefix, units::ratio< 1'024>, "Ki"> {};
struct bit : units::coherent_derived_unit<bit, "b", digital_information, data_prefix> {}; struct bit : units::named_coherent_derived_unit<bit, "b", digital_information, data_prefix> {};
struct kilobit : units::prefixed_derived_unit<kilobit, kibi, bit> {}; struct kilobit : units::prefixed_derived_unit<kilobit, kibi, bit> {};
struct byte : units::derived_unit<byte, "B", digital_information, units::ratio<8>> {}; struct byte : units::named_derived_unit<byte, "B", digital_information, units::ratio<8>> {};
struct kilobyte : units::prefixed_derived_unit<kilobyte, kibi, byte> {}; struct kilobyte : units::prefixed_derived_unit<kilobyte, kibi, byte> {};
inline namespace literals { inline namespace literals {
@@ -71,11 +71,11 @@ namespace {
// power spectral density // power spectral density
struct power_spectral_density : derived_dimension<power_spectral_density, units::exp<voltage, 2>, units::exp<frequency, -1>> {}; struct power_spectral_density : derived_dimension<power_spectral_density, units::exp<voltage, 2>, units::exp<frequency, -1>> {};
struct sq_volt_per_hertz : coherent_derived_unit<sq_volt_per_hertz, "V^2/Hz", power_spectral_density> {}; struct sq_volt_per_hertz : coherent_derived_unit<sq_volt_per_hertz, power_spectral_density> {};
// amplitude spectral density // amplitude spectral density
struct amplitude_spectral_density : derived_dimension<amplitude_spectral_density, units::exp<voltage, 1>, units::exp<frequency, -1, 2>> {}; struct amplitude_spectral_density : derived_dimension<amplitude_spectral_density, units::exp<voltage, 1>, units::exp<frequency, -1, 2>> {};
struct volt_per_sqrt_hertz : coherent_derived_unit<volt_per_sqrt_hertz, "V/Hz^(1/2)", amplitude_spectral_density> {}; struct volt_per_sqrt_hertz : coherent_derived_unit<volt_per_sqrt_hertz, amplitude_spectral_density> {};
} }
namespace { namespace {

View File

@@ -48,10 +48,6 @@ namespace {
/* ************** BASE DIMENSIONS **************** */ /* ************** BASE DIMENSIONS **************** */
// time
static_assert(1h == 3600s);
// length // length
static_assert(1km == 1000m); static_assert(1km == 1000m);
@@ -69,6 +65,33 @@ namespace {
static_assert(5in + 8cm == 207mm); static_assert(5in + 8cm == 207mm);
static_assert(millimetre::symbol == "mm");
static_assert(centimetre::symbol == "cm");
static_assert(kilometre::symbol == "km");
// mass
static_assert(1kg == 1000g);
static_assert(kilogram::symbol == "kg");
// time
static_assert(1h == 3600s);
static_assert(nanosecond::symbol == "ns");
static_assert(microsecond::symbol == "µs");
static_assert(millisecond::symbol == "ms");
// current
// temperature
// substance
// luminous intensity
/* ************** DERIVED DIMENSIONS WITH NAMED UNITS **************** */ /* ************** DERIVED DIMENSIONS WITH NAMED UNITS **************** */
// frequency // frequency
@@ -80,6 +103,12 @@ namespace {
static_assert(3.2GHz == 3'200'000'000Hz); static_assert(3.2GHz == 3'200'000'000Hz);
static_assert(10Hz * 1min == 600); static_assert(10Hz * 1min == 600);
static_assert(millihertz::symbol == "mHz");
static_assert(kilohertz::symbol == "kHz");
static_assert(megahertz::symbol == "MHz");
static_assert(gigahertz::symbol == "GHz");
static_assert(terahertz::symbol == "THz");
// force // force
static_assert(10kg * 10mps_sq == 100N); static_assert(10kg * 10mps_sq == 100N);
@@ -134,6 +163,10 @@ namespace {
// static_assert(2000m / 2kmph == 1h); // should not compile // static_assert(2000m / 2kmph == 1h); // should not compile
static_assert(quantity_cast<quantity<kilometre, int>>(2000m) / 2kmph == 1h); static_assert(quantity_cast<quantity<kilometre, int>>(2000m) / 2kmph == 1h);
// static_assert(metre_per_second::symbol == basic_fixed_string("m/s"));
// static_assert(kilometre_per_hour::symbol == basic_fixed_string("km/h"));
// acceleration // acceleration
static_assert(10mps / 10s == 1mps_sq); static_assert(10mps / 10s == 1mps_sq);