diff --git a/include/xo/unit/mpl/basis_unit.hpp b/include/xo/unit/mpl/basis_unit.hpp deleted file mode 100644 index 6be71a22..00000000 --- a/include/xo/unit/mpl/basis_unit.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/** @file basis_unit.hpp **/ - -#include "dim_util.hpp" -#include "ratio_util.hpp" - -namespace xo { - namespace unit { - /** @class mpl_basis_unit - * - * @brief A dimensionless multiple with natively-specified (i.e. at compile-time) dimension - **/ - template , - typename InnerScale = std::ratio<1>> - struct basis_unit { - static_assert(ratio_concept); - - static constexpr dim c_native_dim = BasisDim; - static constexpr basis_unit c_native_unit = NativeUnitId; - - using scalefactor_type = InnerScale; - }; - - /** Using struct wrapper so we can partially specialize - * Specializations in [dimension.hpp], see also - **/ - template - struct native_unit_abbrev_helper; - - - template <> - struct native_unit_abbrev_helper { - static constexpr auto value = stringliteral("g"); - }; - - template <> - struct native_unit_abbrev_helper { - static constexpr auto value = stringliteral("m"); - }; - - template <> - struct native_unit_abbrev_helper { - static constexpr auto value = stringliteral("s"); - }; - - template<> - struct native_unit_abbrev_helper { - static constexpr auto value = stringliteral("ccy"); - }; - - template<> - struct native_unit_abbrev_helper { - static constexpr auto value = stringliteral("px"); - }; - - template - constexpr auto native_unit_abbrev_v = native_unit_abbrev_helper::value; - - namespace units { - // ----- scaled_native_unit_abbrev_helper ----- - - /* Require: InnerScale is ratio type; InnerScale >= 1 */ - template - struct scaled_native_unit_abbrev; - - template - struct scaled_native_unit_abbrev> { - static constexpr auto value = native_unit_abbrev_v; - }; - - template - struct scaled_native_unit_abbrev { - /* e.g. unit of '1000 grams' will have abbrev '1000g' in absence - * of a specialization for scaled_native_unit_abbrev - */ - static constexpr auto value = stringliteral_concat(stringliteral_from_ratio().value_, - native_unit_abbrev_helper::value.value_); - }; - - template - constexpr auto scaled_native_unit_abbrev_v = scaled_native_unit_abbrev::value; - } - } /*namespace unit*/ -} /*namespace xo*/ - -/** end basis_unit.hpp **/ diff --git a/include/xo/unit/mpl/detail/promoter.hpp b/include/xo/unit/mpl/detail/promoter.hpp deleted file mode 100644 index 3e85324a..00000000 --- a/include/xo/unit/mpl/detail/promoter.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/** @file promoter.hpp - * - * Author: Roland Conybeare - **/ - -#pragma once - -#include "../unit.hpp" - -namespace xo { - namespace unit { - /** @class promoter - * - * Auxiliary class driver for quantity::promote(). - * promoter has two specializations: - * 1. if Unit is dimensionless, @c promoter::promote() is the identity function. - * This has the effect of collapsing dimensionless quantities to their representation. - * 2. if Unit has at least one non-empty dimension, - * @c promoter::promote() builds an xo::unit::quantity instance - **/ - template > - struct promoter; - - template - class quantity; - - /* collapse dimensionless quantity to its repr_type> */ - template - struct promoter { - static constexpr Repr promote(Repr x) { return x; }; - }; - - template - struct promoter { - static constexpr quantity promote(Repr x) { return quantity(x); } - }; - } /*namespace unit*/ -} /*namespace xo*/ - -/** end promoter.hpp **/ diff --git a/include/xo/unit/mpl/dim_util.hpp b/include/xo/unit/mpl/dim_util.hpp deleted file mode 100644 index 7d369bc2..00000000 --- a/include/xo/unit/mpl/dim_util.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* @file dim_util.hpp */ - -#pragma once - -//#include "stringliteral.hpp" -//#include "xo/flatstring/flatstring.hpp" -#include - -namespace xo { - namespace unit { - enum class dim { - invalid = -1, - - /** weight. native unit = 1 gram **/ - mass, - /** distance. native unit = 1 meter **/ - distance, - /** time. native unit = 1 second **/ - time, - /** a currency amount. native unit depends on actual currency. - * For USD: one US dollar. - * - * NOTE: unit system isn't suitable for multicurrency work: - * (1usd + 1eur) is well-defined, but (1sec + 1m) is not. - **/ - currency, - /** a screen price **/ - price, - - /** comes last, counts entries **/ - n_dim - }; - - inline const char * - dim2str(dim x) - { - switch(x) { - case dim::mass: return "mass"; - case dim::distance: return "distance"; - case dim::time: return "time"; - case dim::currency: return "currency"; - case dim::price: return "price"; - default: break; - } - return "?dim"; - } - - static constexpr std::size_t n_dim = static_cast(dim::n_dim); - - enum class native_unit_id { - gram, - meter, - second, - currency, - price - }; - - template - struct native_unit_for; - - template <> - struct native_unit_for { static constexpr auto value = native_unit_id::gram; }; - - template <> - struct native_unit_for { static constexpr auto value = native_unit_id::meter; }; - - template <> - struct native_unit_for { static constexpr auto value = native_unit_id::second; }; - - template <> - struct native_unit_for { static constexpr auto value = native_unit_id::currency; }; - - template <> - struct native_unit_for { static constexpr auto value = native_unit_id::price; }; - - template - constexpr auto native_unit_for_v = native_unit_for::value; - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end dim_util.hpp */ diff --git a/include/xo/unit/mpl/dimension_concept.hpp b/include/xo/unit/mpl/dimension_concept.hpp deleted file mode 100644 index c670c3e1..00000000 --- a/include/xo/unit/mpl/dimension_concept.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* @file dimension_concept.hpp */ - -#pragma once - -#include "native_bpu_concept.hpp" - -namespace xo { - namespace unit { - /** checks most non-empty BPU (basis power unit) node types; - * cannot check BpuList::rest_type, because concept definition - * can't (as of c++23) be recursive. - * - * As workaround, revert to type traits, seend below. - **/ - template - concept bpu_node_concept = requires(BpuList bpulist) - { - typename BpuList::front_type; - typename BpuList::rest_type; - } - && (native_bpu_concept - && (std::is_integral_v) - //&& (std::same_as - // or nonempty_bpu_list_concept)) - ); - - namespace detail { - // ------------------------------------------------------------ - - /* check for 'list of native_bpu_concept'. - * Need type trait for this, to access partial specializations - */ - template < typename BpuList > - struct bpu_list_traits; - - /* void (representing empty list) is fine */ - template <> - struct bpu_list_traits : public std::true_type {}; - - /* non-void must satisfy bpu-list rules */ - template - struct bpu_list_traits { - /* checks everything except BpuList::rest_type */ - static constexpr bool _value1 = bpu_node_concept; - static constexpr bool _value2 = bpu_list_traits::value; - - static constexpr bool value = (_value1 && _value2); - }; - - // ---------------------------------------------------------------- - - template - constexpr bool bpu_list_v = bpu_list_traits::value; - } - - /* may want to rename this -> native_bpu_list */ - template - concept bpu_list_concept = detail::bpu_list_v; - - // ---------------------------------------------------------------- - - /* TODO: retire in favor of unit_concept? */ - template - concept dimension_concept = requires(Dimension dim) - { - typename Dimension::dim_type; - typename Dimension::canon_type; - } - && (bpu_list_concept - && bpu_list_concept - ); - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end dimension_concept.hpp */ diff --git a/include/xo/unit/mpl/dimension_impl.hpp b/include/xo/unit/mpl/dimension_impl.hpp deleted file mode 100644 index d241f9ec..00000000 --- a/include/xo/unit/mpl/dimension_impl.hpp +++ /dev/null @@ -1,558 +0,0 @@ -/* @file dimension_impl.hpp */ - -#pragma once - -#include "dimension_concept.hpp" -#include "native_bpu.hpp" -#include "dim_util.hpp" -#include "ratio_util.hpp" -//#include -#include -#include -#include -#include - -namespace xo { - /* TODO: - * - bpu_list -> bpu_node - */ - - namespace unit { - // ----- lookup_bpu ----- - - /** - * Select from dimension_impl by known index value - * - * Example: - * using t1 = native_bpu, std::ratio<1,1>>; - * using t2 = native_bpu, std::ratio<-1,2>>; - * using dim = dimension_impl - * - * then - * lookup_bpu --> t1 - * lookup_bpu --> t2 - **/ - template - struct lookup_bpu { - using power_unit_type = lookup_bpu::power_unit_type; - }; - - template - struct lookup_bpu { - using power_unit_type = Dim::front_type; - }; - - // ----- di_find_bpu ----- - - /** - * @brief Select from dimension_impl by native_dim_id - * - * Example: - * using t1 = native_bpu, std::ratio<-2>>; - * using t2 = native_bpu, std::ratio<1>>; - * using di = dimension_impl; - * - * then - * di_find_bpu -> t1 - * di_find_bpu -> t2 - * di_find_bpu -> native_bpu {dim::mass, std::ratio<1>, std::ratio<0>} - **/ - template - struct di_find_bpu; - - /** - * @brief Aux template helper for di_find_bpu<..> - **/ - template - struct di_find_bpu_aux; - - /** specialization for non-empty BpuList **/ - template - struct di_find_bpu { - using type = di_find_bpu_aux::type; - }; - - /** specialization for empty BpuList **/ - template - struct di_find_bpu { - using type = bpu, std::ratio<0>>; - }; - - template - struct di_find_bpu_aux { - using type = Front; - }; - - template - struct di_find_bpu_aux { - using type = di_find_bpu::type; - }; - - // ---------------------------------------------------------------- - - /** - * Promise: - * - bpu_list::front_type - * - bpu_list::rest_type - * - bpu_node_concept> - **/ - template - struct bpu_node; - - // ---------------------------------------------------------------- - - template - constexpr bool FrontHasZeroPower = (Front::power_type::num == 0); //std::ratio_equal_v< typename Front::power_type, std::ratio<0,1> >; - - template > - struct bpu_smart_cons; - - template - struct bpu_smart_cons { - using type = Rest; - }; - - template - struct bpu_smart_cons { - using type = bpu_node; - }; - - template - using bpu_smart_cons_t = bpu_smart_cons::type; - - // ---------------------------------------------------------------- - - /** @class bwp - - @brief represent (compile-time) result of search in a bpu_list<> type - - short for (basis-with-native-power-unit) - **/ - template - struct bwp { - static constexpr int c_index = index_arg; - static constexpr dim c_basis = basis_arg; - }; - - template - using bwp_incr_pos_type = bwp; - - // ----- lo_basis_with_pos_type ----- - - template < typename BasisWithPos1, typename BasisWithPos2> - using lo_basis_with_pos_type = std::conditional_t<(BasisWithPos1::c_basis < BasisWithPos2::c_basis), - BasisWithPos1, BasisWithPos2>; - - // ----- native_lo_bwp_of ----- - - /* helper for canonically-ordering native dimension power-units */ - template - struct native_lo_bwp_of { - using _bwp_front = bwp<0, Dim::front_type::c_native_dim>; - using _pu_rest = native_lo_bwp_of; - using _bwp_rest = typename _pu_rest::bwp_type; - - using bwp_type = lo_basis_with_pos_type<_bwp_front, - bwp_incr_pos_type<_bwp_rest>>; - }; - - template - struct native_lo_bwp_of> { - using bwp_type = bwp<0, P0::c_native_dim>; - }; - - // ----- without_elt ----- - - template - struct without_elt { - using _without_rest_type = typename without_elt::dim_type; - - using dim_type = bpu_node< typename Dim::front_type, _without_rest_type >; - }; - - template - struct without_elt { - using dim_type = typename Dim::rest_type; - }; - - // ----- bpu_node ----- - - /** Represents the cartesian product of a list of 'native basis power units'; - * represents something with dimensions - * - * Expect: - * - P isa native_bpu type - * - D satisfies bpu_list_concept - **/ - template - struct bpu_node { - static_assert(native_bpu_concept

); - static_assert(bpu_list_concept); - - /** For example: - * using b1 = basis_power_unit>; - * using b2 = basis_power_unit>; - * using foo = dimension_impl>; - * - * then - * foo::lookup_bpu<0> -> b1 - * foo::lookup_bpu<1> -> b2 - * foo::lookup_bpu<2> -> not defined - **/ - using front_type = P; - using rest_type = D; - - static constexpr std::uint32_t n_dimension = rest_type::n_dimension + 1; - }; - - /** @class dimension - - @brief represent a composite dimension - **/ - template - struct bpu_node { - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - - using front_type = P0; - using rest_type = void; - - /** For example: - * using b1 = basis_power_unit>; - * using foo = dimension_impl; - * then - * foo::lookup_bpu<0> --> b1 - * foo::lookup_bpu<1> --> not defined - **/ - - /** number of dimensions represented by this struct **/ - static constexpr std::uint32_t n_dimension = 1; - }; - - // ----- di_replace_basis_scale ----- - - /** - * @brief Replace BpuList member with matching BasisDim, preserving everything except (inner) scalefactor - **/ - template - struct di_replace_basis_scale; - - template - struct di_replace_basis_scale_aux; - - /** specialization for non-empty BpuList **/ - template - struct di_replace_basis_scale { - using type = di_replace_basis_scale_aux::type; - }; - - /** specialization for empty BpuList -- error not found **/ - template - struct di_replace_basis_scale {}; - - /** specialization for matching front **/ - template - struct di_replace_basis_scale_aux { - using _replace_bpu_type = bpu; - - static_assert(native_bpu_concept<_replace_bpu_type>); - - /* NewBpu replaces Front */ - using type = bpu_node<_replace_bpu_type, Rest>; - }; - - template - struct di_replace_basis_scale_aux { - /* keep Front, replace NewBpu in rest */ - using type = bpu_node::type>; - }; - - // ----- bpu_cartesian_product ----- - - /** Require: - * - B isa native_bpu type - * - DI_Front is a native_bpu type - * - DI_Rest is a dimension_impl type - * - * Promise: - * - type isa dimension_impl type - **/ - template < typename B, - typename DI_Front, - typename DI_Rest, - bool MatchesFront = (B::c_native_dim == DI_Front::c_native_dim) > - struct bpu_cartesian_product_helper; - - /** require: - * - B isa native_bpu type - * - DI isa (bpu_list | void) type - **/ - template < typename B, typename DI > - struct bpu_cartesian_product { - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - - using _tmp = bpu_cartesian_product_helper; - - using outer_scalefactor_type = typename _tmp::outer_scalefactor_type; - static constexpr double c_outer_scalefactor_inexact = _tmp::c_outer_scalefactor_inexact; - - using bpu_list_type = typename _tmp::bpu_list_type; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - /** Reminder: void represents the 'no dimension' of a dimensionless quantity **/ - template < typename B > - struct bpu_cartesian_product { - using outer_scalefactor_type = std::ratio<1>; - static constexpr double c_outer_scalefactor_inexact = 1.0; - - using bpu_list_type = bpu_node; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - /* specialize for matching front */ - template - struct bpu_cartesian_product_helper { - static_assert(native_bpu_concept); - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - - /* _mult_type may have zero exponent (power_type); - * in that case bpu_smart_cons will collapse to DI_Rest - */ - using _front_mult_type = bpu_product; - - using _front_type = typename _front_mult_type::native_bpu_type; - using _rest_type = DI_Rest; - - using outer_scalefactor_type = typename _front_mult_type::outer_scalefactor_type; - static constexpr double c_outer_scalefactor_inexact = _front_mult_type::c_outer_scalefactor_inexact; - - using bpu_list_type = bpu_smart_cons_t<_front_type, DI_Rest>; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - /* specialize for not-matching-front */ - template - struct bpu_cartesian_product_helper { - static_assert(native_bpu_concept); - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - - using _rest_mult_type = bpu_cartesian_product< B, DI_Rest >; - - using _front_type = DI_Front; - using _rest_type = typename _rest_mult_type::bpu_list_type; - - using outer_scalefactor_type = typename _rest_mult_type::outer_scalefactor_type; - static constexpr double c_outer_scalefactor_inexact = _rest_mult_type::c_outer_scalefactor_inexact; - - using bpu_list_type = bpu_node; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - // ----- di_cartesian_product ----- - - template < typename D1, typename D2 > struct di_cartesian_product; - - // ----- bpu_cartesian_product1 ----- - - template < typename B1, typename R1, typename D2 > - struct di_cartesian_product1 { - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - static_assert(bpu_list_concept); - - using _tmp1_mult_type = bpu_cartesian_product; - using _tmp1_scalefactor_type = _tmp1_mult_type::outer_scalefactor_type; - using _tmp1_bpu_list_type = _tmp1_mult_type::bpu_list_type; - - using _tmp2_mult_type = di_cartesian_product; - using _tmp2_scalefactor_type = _tmp2_mult_type::outer_scalefactor_type; - using _tmp2_bpu_list_type = _tmp2_mult_type::bpu_list_type; - - using outer_scalefactor_type = std::ratio_multiply< - _tmp1_scalefactor_type, - _tmp2_scalefactor_type>; - static constexpr double c_outer_scalefactor_inexact = (_tmp1_mult_type::c_outer_scalefactor_inexact - * _tmp2_mult_type::c_outer_scalefactor_inexact); - - using bpu_list_type = _tmp2_bpu_list_type; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - template < typename B1, typename D2 > - struct di_cartesian_product1 { - static_assert(native_bpu_concept); - static_assert(bpu_list_concept); - - using _tmp_mult_type = bpu_cartesian_product; - - using outer_scalefactor_type = _tmp_mult_type::outer_scalefactor_type; - static constexpr double c_outer_scalefactor_inexact = _tmp_mult_type::c_outer_scalefactor_inexact; - - using bpu_list_type = _tmp_mult_type::bpu_list_type; - }; - - // ----- di_invert ----- - - /* note: rescaling never required here, - * since not combining basis dimensions. - */ - template - struct di_invert; - - template <> - struct di_invert { - using type = void; - }; - - template - struct di_invert { - using type = bpu_node< - typename bpu_invert::type, - typename di_invert::type - >; - }; - - // ----- di_cartesian_product ----- - - template < typename D1, typename D2 > - struct di_cartesian_product { - static_assert(bpu_list_concept); - static_assert(bpu_list_concept); - - using _mult_type = di_cartesian_product1< - typename D1::front_type, - typename D1::rest_type, - D2>; - - using outer_scalefactor_type = _mult_type::outer_scalefactor_type; - static constexpr double c_outer_scalefactor_inexact = _mult_type::c_outer_scalefactor_inexact; - - using bpu_list_type = _mult_type::bpu_list_type; - - static_assert(ratio_concept); - static_assert(bpu_list_concept); - }; - - template < typename D2 > - struct di_cartesian_product< void, D2 > { - static_assert(bpu_list_concept); - - using outer_scalefactor_type = std::ratio<1>; - static constexpr double c_outer_scalefactor_inexact = 1.0; - using bpu_list_type = D2; - }; - - template - struct di_cartesian_product< D1, void > { - static_assert(bpu_list_concept); - - using outer_scalefactor_type = std::ratio<1>; - static constexpr double c_outer_scalefactor_inexact = 1.0; - using bpu_list_type = D1; - }; - - // ----- di_assemble_abbrev ----- - - /* reminder: can't partially specialize a template function -> need struct wrapper */ - template < typename DI > - struct di_assemble_abbrev; - - /** Expect: - * - P isa native_bpu type - * - P::power_type = std::ratio<..> - * - P::c_native_dim :: dim - * - P::c_num :: int - * - P::c_den :: int - * - D isa dimension_impl type - * - D::front_type = native_bpu<..> - * - D::rest_type = dimension_impl<..> - * - D::n_dimension :: int - **/ - template - struct di_assemble_abbrev_helper { - static_assert(native_bpu_concept

); - static_assert(bpu_list_concept); - - static constexpr auto _prefix = bpu_assemble_abbrev

(); - static constexpr auto _suffix = di_assemble_abbrev::value; - - static constexpr auto value = stringliteral_concat(_prefix.value_, - ".", - _suffix.value_); - }; - - template - struct di_assemble_abbrev_helper { - static constexpr auto value = bpu_assemble_abbrev

(); - }; - - template < typename DI > - struct di_assemble_abbrev { - static_assert(bpu_list_concept); - - using _helper_type = di_assemble_abbrev_helper ; - - static constexpr auto value = _helper_type::value; - }; - - template <> - struct di_assemble_abbrev { - static constexpr auto value = stringliteral(""); - }; - - // ----- canonical_impl ----- - - template - struct canonical_impl { - /* - * bwp_front::c_index - * bwp_front::c_native_dim - */ - using _bwp_front = native_lo_bwp_of::bwp_type; - - using _front_type = typename lookup_bpu::power_unit_type; - using _rest0_type = typename without_elt::dim_type; - using _rest_type = canonical_impl<_rest0_type>::dim_type; - - using dim_type = bpu_node<_front_type, _rest_type>; - }; - - /** compute canonical renumbering of a dimension - **/ - template <> - struct canonical_impl { - using dim_type = void; - }; - - template - using canonical_t = canonical_impl::dim_type; - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end dimension_impl.hpp */ diff --git a/include/xo/unit/mpl/native_bpu.hpp b/include/xo/unit/mpl/native_bpu.hpp deleted file mode 100644 index 44e1a54d..00000000 --- a/include/xo/unit/mpl/native_bpu.hpp +++ /dev/null @@ -1,259 +0,0 @@ -/* @file native_bpu.hpp */ - -#pragma once - -#include "native_bpu_concept.hpp" -#include "basis_unit.hpp" -#include - -namespace xo { - namespace unit { - // ----- native_bpu ----- - - /** @class native_bpu - - @brief represent product of a compile-time scale-factor with a rational power of a native unit - - Example: - native_bpu, ratio<-1,2>> represents unit of 1/sqrt(t) - **/ - template< - dim DimId, - typename InnerScale, - typename Power = std::ratio<1> > - struct bpu : basis_unit, InnerScale> { - static_assert(ratio_concept); - - /* native_unit provides - * - scalefactor_type --> std::ratio - * - c_native_dim :: dim - * - c_native_unit :: native_unit - */ - - using power_type = Power; - - static const int c_num = Power::num; - static const int c_den = Power::den; - }; - - /** @class bpu_assemble_abbrev - * - * @brief generate abbreviation literal. - * - * Abbreviation literal ignores outer scale factor; - * (outer scale factor should be multiplied by run-time scale when printing a quantity) - * - * Separate template from native_bpu so that abbrev can independently be specialized - **/ - template < dim dim_id, - typename InnerScale, - typename Power = std::ratio<1> > - constexpr auto bpu_assemble_abbrev_helper() { - static_assert(ratio_concept); - - return stringliteral_concat(units::scaled_native_unit_abbrev_v.value_, - stringliteral_from_exponent().value_); - }; - - /** Expect: - * - BPU is a native_bpu type: - * - BPU::scalefactor_type = std::ratio<..> - * - BPU::c_native_dim :: dim - * - BPU::power_type = std::ratio<..> - * - BPU::c_num :: int - * - BPU::c_den :: int - **/ - template < typename BPU > - constexpr auto bpu_assemble_abbrev() { - static_assert(native_bpu_concept); - - return bpu_assemble_abbrev_helper< BPU::c_native_dim, - typename BPU::scalefactor_type, - typename BPU::power_type >(); - }; - - // ----- bpu_rescale ----- - - /** - * Part I - * ------ - * We have B satisfying native_bpu_concept: - * B represents a basis-power-unit - * p - * (b.u) - * - * with - * b = B::scalefactor_type, e.g. 60 for a 1-minute unit - * u = B::dim, e.g. 1second for time - * p = B::power_type - * - * We want to construct something with similar form: - * - * p - * a'.(b'.u) - * - * representing the same dimensioned unit, - * i.e. - * p p' - * (b.u) = a'.(b'.u) - * - * with NewInnerScale -> b' - * - * p p p p - * (b.u) = (b/b') . (b'.u) = a'.(b'.u) - * - * p - * with a' = (b/b') - * - * For example: if we have B(b=60,u=time,p=2), NewInnerScale=1: - * then we want a'=3600, B'(b=1,u=time,p=2) - * - * Result represented with - * bpu_rescale::outer_scalefactor_type -> 'a - * bpu_rescale::native_bpu_type -> B' - * - * Part II - * ------- - * Want ability to rescale when p is a non-integer rational. - * In that case a' = (b/b')^p won't in general be exactly-representable, - * so we are forced to accept some loss of precision. - * - * Want to write: - * p as p' + q' with: - * p' = integer part of p - * q' = fractional part of p - * Then we can write - * a' as c'.d' with: - * c' = (b/b')^p' [exactly represented] - * d' = (b/b')^q' [floating point] - **/ - template - struct bpu_rescale { - static_assert(native_bpu_concept); - static_assert(ratio_concept); - - /* TODO: - * - native_unit::c_scale -> std::ratio, call it c_inner_scalefactor - * - ++ native_bpu::c_outer_scalefactor, will be a std::ratio - */ - - /* b/b' */ - using _t1_type = std::ratio_divide - < typename B::scalefactor_type, NewInnerScale >; - - /* p' */ - using p1_type = ratio_floor_t; - /* q' */ - using q1_type = ratio_frac_t; - - /** require p must be integral **/ - static_assert(p1_type::den == 1); - - /* note: constexpr from c++26, but already present in earlier gcc */ - static constexpr double c_outer_scalefactor_inexact = ::pow(from_ratio(), - from_ratio()); - - /** p - * a' = (b/b') - **/ - using outer_scalefactor_type = ratio_power_t< _t1_type, p1_type::num >; - - /** - * p - * (b'.u) - **/ - using native_bpu_type = bpu < B::c_native_dim, - NewInnerScale, - typename B::power_type >; - }; - - // ----- bpu_invert ----- - - /** invert a native bpu: create type for space 1/B **/ - template - struct bpu_invert { - using type = bpu < - B::c_native_dim, - typename B::scalefactor_type, - std::ratio_multiply, typename B::power_type> - >; - }; - - // ----- bpu_product ----- - - /** Suppose we have two native_bpu's {B1, B2} that scale the same native basis unit u. - * B1,B2 may be using different units {b1,b2} for u - * - * p1 - * B1 (b1, u, p1) = (b1.u) - * - * p2 - * B2 (b2, u, p2) = (b2.u) - * - * we want a representation in similar form: - * - * p' - * a' . B' (b', u, p') = a'.(b'.u) - * - * for the product (B1 x B2), i.e. - * - * p' p1 p2 - * a'.(b'.u) = (b1.u) (b2.u) - * - * We can use bpu_rescale to rewrite B2 in the form - * - * p2 - * B2' = (c'.d').(b1.u) - * - * where c' is exact, d' is inexact. - * (note however d' will be exactly 1.0 whenever p2 is integral) - * - * so we have - * - * p1 p2 - * (B1 x B2) = (b1.u) (c'.d').(b1.u) - * - * p1+p2 - * = (c'.d').(b1.u) - * - **/ - template < typename B1, typename B2 > - struct bpu_product { - static_assert(native_bpu_concept); - static_assert(native_bpu_concept); - static_assert(B1::c_native_dim == B2::c_native_dim); - - /* c'.d'.B2' = c'.d'.(b1.u)^p2 - * - * _b2p_rescaled_type::native_bpu_type -> B2' (b1, u, p2) [same basis scalefactor as B1] - * _b2p_rescaled_type::outer_scalefactor_type -> c' [exact factor] - * _b2p_rescaled_type::c_outer_scalefactor_type -> d' [inexact factor, from fractional powers] - */ - using _b2p_rescaled_type = bpu_rescale; - /* (b1.u)^p2 */ - using _b2p_sf_bpu_type = _b2p_rescaled_type::native_bpu_type; - - /* p1+p2 */ - using _p_type = std::ratio_add< - typename B1::power_type, - typename B2::power_type - >; - - /* c' */ - using outer_scalefactor_type = _b2p_rescaled_type::outer_scalefactor_type; - /* d' */ - static constexpr double c_outer_scalefactor_inexact = _b2p_rescaled_type::c_outer_scalefactor_inexact; - - /* (b1.u)^(p1+p2) */ - using native_bpu_type = bpu < - B1::c_native_dim, - typename B1::scalefactor_type, - _p_type /*Power*/ >; - }; - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end native_bpu.hpp */ diff --git a/include/xo/unit/mpl/native_bpu_concept.hpp b/include/xo/unit/mpl/native_bpu_concept.hpp deleted file mode 100644 index f72c60ca..00000000 --- a/include/xo/unit/mpl/native_bpu_concept.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* @file native_bpu_concept.hpp */ - -#pragma once - -#include "ratio_concept.hpp" -#include "dim_util.hpp" -#include - -namespace xo { - namespace unit { - /** - * e.g. see native_bpu> - * - * bpu short for 'basis power unit'. - * - * NOTE: in typical c++ use, there won't be a reason to declare - * a variable of type NativeBpu. Instead will appear - * as a template argument. - **/ - template - concept native_bpu_concept = requires(NativeBpu bpu) - { - typename NativeBpu::scalefactor_type; - typename NativeBpu::power_type; - - // NativeBpu::c_native_dim :: native_dim_id - // NativeBpu::c_scale :: std::intmax_t - // NativeBpu::num :: int - // NativeBpu::den :: int - } - && ((std::is_same_v) - && ratio_concept - && ratio_concept - && (std::is_signed_v) - && (std::is_signed_v)) - // && std::copyable - ; - } /*namespace unit*/ -} /*namespace xo*/ - -/* end native_bpu_concept.hpp */ diff --git a/include/xo/unit/mpl/numeric_concept.hpp b/include/xo/unit/mpl/numeric_concept.hpp deleted file mode 100644 index f1d32f58..00000000 --- a/include/xo/unit/mpl/numeric_concept.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* @file numeric_concept.hpp */ - -#pragma once - -#include - -namespace xo { - namespace unit { - /** @concept numeric_concept - * @brief Concept for values that participate in arithmetic operations (+,-,*,/) and comparisons - * - * Intended to include at least: - * - built-in integral and floating-point types - * - xo::raio - * - xo::unit::quantity - * - * Intend numeric_concept to apply to types suitable for - * xo::unit::quantity::repr_type. - **/ - template - concept numeric_concept = requires(T x, U y) - { - { -x }; - { x - y }; - { x + y }; - { x * y }; - { x / y }; - { x == y }; - { x != y }; - }; - } /*namespace unit*/ -} /*namespace xo*/ - -/* end numeric_concept.hpp */ diff --git a/include/xo/unit/mpl/quantity.hpp b/include/xo/unit/mpl/quantity.hpp deleted file mode 100644 index c58ba080..00000000 --- a/include/xo/unit/mpl/quantity.hpp +++ /dev/null @@ -1,831 +0,0 @@ -/* @file quantity.hpp */ - -#pragma once - -#include "quantity_concept.hpp" -#include "unit.hpp" -#include "detail/promoter.hpp" -//#include "xo/reflect/Reflect.hpp" -//#include "xo/indentlog/scope.hpp" - -namespace xo { - namespace unit { - // ----- quantity ----- - - /** @class quantity - * - * @brief represents a scalar quantity; enforces dimensional consistency at compile time. - * - * - @p Unit is a type identifying dimension and scale attaching to this quantity. - * Unit must satisfy @c unit_concept - * - @p Repr is a type used to represent quantity values, scaled by @p Unit. - * Repr must satisfy @c numeric_concept - * - * A quantity's run-time state consists of exactly one @p Repr - * instance: - * @c sizeof(quantity) == sizeof(Repr) - **/ - template - class quantity { - public: - /** @defgroup mpl-quantity-traits **/ - ///@{ - /** @brief type capturing the units (and dimension) of this quantity **/ - using unit_type = Unit; - /** @brief type used for representation of this quantity **/ - using repr_type = Repr; - ///@} - - static_assert(unit_concept); - static_assert(numeric_concept); - /* non-unity compile-time scale factors can arise during unit conversion; - * for example see method quantity::in_units_of() - */ - static_assert(std::same_as< typename Unit::scalefactor_type, std::ratio<1> >); - static_assert(std::same_as< typename Unit::canon_type, typename Unit::canon_type >); - - public: - /** @defgroup mpl-quantity-ctors constructors - **/ - ///@{ - constexpr quantity() = default; - constexpr quantity(quantity const & x) = default; - constexpr quantity(quantity && x) = default; - ///@} - - /** @defgroup quantity-named-ctors named constructors - **/ - ///@{ - /** @brief construct a unit quantity using @c unit_type - * - * @code - * auto q = qty::milliseconds(17) / qty::kilometers(23.0); - * q::unit_quantity(); // 1ms.km^-1 - * @endcode - **/ - static constexpr quantity unit_quantity() { return quantity(1); } - /** @brief promote representation to quantity. Same as multiplying by Unit - **/ - static constexpr auto promote(Repr x); - ///@} - - /** @addtogroup mpl-quantity-traits **/ - ///@{ - - /** @brief report this quantity's basis-power-unit type for a given basis dimension - * - * Example: - * @code - * auto q = 1.0 / (qty::milliseconds(5) * qty::seconds(100.0)); - * q.unit_cstr(); // "ms^-2" - * - * using tmp = q.find_bpu_t; - * - * tmp::c_native_dim; // dim::time - * tmp::c_native_unit; // native_unit_id::second - * tmp::scalefactor_type::num; // 1 - * tmp::scalefactor_type::den; // 1000 - * tmp::power_type::num; // -2 - * tmp::pwoer_type::den; // 1 - * @endcode - **/ - template - using find_bpu_t = unit_find_bpu_t; - - /** @brief report this quantity's scalefactor type for given basis dimension **/ - template - using basis_scale_type = typename find_bpu_t::scalefactor_type::type; - - ///@} - - /** @defgroup mpl-quantity-access-methods **/ - ///@{ - /** @brief get scale value (relative to unit) (@ref scale_) **/ - constexpr Repr scale() const { return scale_; } - /** @brief abbreviation for this quantity's units - * - * This string literal is constructed at compile-time by concatenating - * abbreviations for each basis-power-unit. - * For implementation see: - * * @c xo::unit::native_unit_abbrev_helper - * (in xo/unit/basis_unit.hpp) for each native dimension - * * @c xo::unit::scaled_native_unit_abbrev - * (in xo/unit/basis_unit.hpp) last-resort handling for scaled native dimensions - * * @c xo::unit::scaled_native_unit_abbrev - * (in xo/unit/unit.hpp) specializations for scaled native dimensions - **/ - static constexpr char const * unit_cstr() { return unit_abbrev_v.c_str(); } - ///@} - - /** @defgroup mpl-quantity-constants constants - **/ - ///@{ - /** @brief report exponent of @p BasisDim in dimension of this quantity - * - * For example: - * @code - * auto q = qty::milliseconds(5) * qty::seconds(1); - * int p1 = q.basis_power; // p1 == 2 - * int p2 = q.basis_power; // p2 == 0 - * @endcode - **/ - template - static constexpr PowerRepr basis_power = from_ratio::power_type>(); - ///@} - - /** @defgroup quantity-unit-conversion **/ - ///@{ - /** @brief convert to quantity representing the same amount, but changing units and perhaps representation. - * - * These two expressions are equivalent: - * @code - * q.with_unit(); - * quantity(q); - * @endcode - * - **/ - template - constexpr quantity with_unit() const { return *this; } - - /** - * @brief produce quantity scaled according to @p BasisUnit2, representing the same value as @c *this. - * - * For example: - * - * @code{.cpp} - * auto q1 = 1.0 / minutes(1) * kilograms(2.5); // q1 = 2.5kg.min^-1 - * auto q2 = q1.with_basis_unit(); // q2 in kg.ms^-1 - * @endcode - * - * Motivation is ability to chain rescaling to reach desired compound unit - * - * @code - * auto q3 = q1.with_basis_unit() - * .with_basis_unit(); // q3 in g.s^-1 - * @endcode - **/ - template - constexpr auto with_basis_unit() const { - static_assert(basis_unit_concept); - - using new_bpu_type = BasisUnit2::dim_type::front_type; - using old_bpulist_type = unit_type::dim_type; - using new_bpulist_type = di_replace_basis_scale::type; - using new_unit_type = wrap_unit, new_bpulist_type>; - -# ifdef NOT_USING_DEBUG - using xo::reflect::Reflect; - scope log(XO_DEBUG(true /*c_debug_flag*/)); - log && log(xtag("old_unit_type", Reflect::require()->canonical_name())); - log && log(xtag("new_unit_type", Reflect::require()->canonical_name())); -# endif - - return this->with_unit(); - } - - /** - * @brief express this quantity in the same units as @p q - * - * @pre @c *this and @p q must have the same dimension - * - * @param q take units from @c q::unit_type, ignoring @c q.scale() - * @return this amount, but expressed using the same units as @p q - **/ - template - auto with_units_from(Quantity q) const { - return this->with_units(); - } - - /** - * @brief express this quantity in units of @p Unit2. - * - * @p Unit2 specifies new units - * @p Repr2 specifies representation - * @return this amount, but expressed as a multiple of @p Unit2 - **/ - template - auto with_units() const { - Repr2 x = this->in_units_of(); - - return quantity::promote(x); - } - - /** - * @brief compute scale with respect to @p Unit2 - * - * @pre @c *this must have the same dimension as @p Unit2 - * - * @p Unit2 rescale in terms of this unit. - * @p Repr2 compute scale in this representation - * @return scale to use for @c quantity representing the same amount as @c *this. - **/ - template - Repr2 in_units_of() const { - // static_assert(dimension_of == dimension_of); // discard all the scaling values - - static_assert(same_dimension_v); - - using _convert_to_u2_type = unit_cartesian_product>; - - using exact_scalefactor_type = _convert_to_u2_type::exact_unit_type::scalefactor_type; - constexpr double c_scalefactor_inexact = _convert_to_u2_type::c_scalefactor_inexact; - - // _convert_u2_type - // - scalefactor_type - // - dim_type - // - canon_type - - /* if _convert_u2_type isn't dimensionless, then {Unit2, Unit} have different dimensions */ - - return ((this->scale_ * c_scalefactor_inexact * exact_scalefactor_type::num) / exact_scalefactor_type::den); - } - - /** - * @brief convert to quantity with representation @p Repr2 - * - * @return a quantity representing the same amount as @c *this, but using representation @p Repr2 - **/ - template - constexpr quantity with_repr() const { return quantity::promote(scale_); } - ///@} - - - /** @defgroup quantity-arithmeticsupport **/ - ///@{ - /** - * @brief multiply this quantity *x* by another quantity *y*. - * - * Result will propagate dimension and units appropriately. - * If *x* and *y* use conflicting scale factors for a dimension, - * adopt scalefactor from *x*. - * - * note: result will be a dimensionless value (e.g. type @c double) - * if units cancel. - * - * @pre @p Quantity2 must satisfy @c quantity_concept - * - * @param y multiply by this amount - * @return x.multiply(y) returns amount representing x*y - **/ - template - auto multiply(Quantity2 y) const { - //constexpr bool c_debug_flag = false; - //using Reflect = xo::reflect::Reflect; - - //scope log(XO_DEBUG(c_debug_flag)); - - static_assert(quantity_concept); - - /* unit: may have non-unit scalefactor_type */ - using unit_product_type = unit_cartesian_product; - using exact_unit_type = unit_product_type::exact_unit_type; - using norm_unit_type = normalize_unit_t; - - using exact_scalefactor_type = exact_unit_type::scalefactor_type; - constexpr double c_scalefactor_inexact = unit_product_type::c_scalefactor_inexact; - - using repr_type = std::common_type_t; - - repr_type r_scale = ((scale() * y.scale() * c_scalefactor_inexact * exact_scalefactor_type::num) - / exact_scalefactor_type::den); - -# ifdef NOT_USING_DEBUG - log && log(xtag("unit_product_type", Reflect::require()->canonical_name())); - log && log(xtag("exact_unit_type", Reflect::require()->canonical_name())); - log && log(xtag("norm_unit_type", Reflect::require()->canonical_name())); - log && log(xtag("exact_scalefactor_type", Reflect::require()->canonical_name())); - log && log(xtag("c_scalefactor_inexact", c_scalefactor_inexact)); - log && log(xtag("repr_type", Reflect::require()->canonical_name())); - log && log(xtag("repr_type", Reflect::require()->canonical_name())); -# endif - - return quantity::promote(r_scale); - } - - /** - * @brief multiply this quantity *x* by another quantity *y* - * - * Result will propagate dimension and units appropriately. - * If *x* and *y* use conflicting scale factors for a dimension, - * adopt scalefactor from *x*. - * - * note: result will be a dimensionless value (e.g. type @c double) - * if units cancel. - * - * @pre @p Quantity2 must satisfy @c quantity_concept - * - * @param y divide by this amount - * @return x.divide(y) returns amount representing x/y - **/ - template - auto divide(Quantity2 y) const { - using unit_divide_type = unit_divide; - using exact_unit_type = unit_divide_type::exact_unit_type; - using norm_unit_type = normalize_unit_t; - - using exact_scalefactor_type = exact_unit_type::scalefactor_type; - constexpr double c_scalefactor_inexact = unit_divide_type::c_scalefactor_inexact; - - using repr_type = std::common_type_t; - - repr_type r_scale = ((scale() * c_scalefactor_inexact * exact_scalefactor_type::num) - / (y.scale() * exact_scalefactor_type::den)); - -# ifdef NOT_USING_DEBUG - using xo::reflect::Reflect; - scope log(XO_DEBUG(true /*c_debug_flag*/)); - log && log(xtag("unit_divide_type", Reflect::require()->canonical_name())); - log && log(xtag("exact_unit_type", Reflect::require()->canonical_name())); - log && log(xtag("norm_unit_type", Reflect::require()->canonical_name())); - log && log(xtag("exact_scalefactor_type", Reflect::require()->canonical_name())); - log && log(xtag("c_scalefactor_inexact", c_scalefactor_inexact)); - log && log(xtag("r_scale", r_scale)); - log && log(xtag("repr_type", Reflect::require()->canonical_name())); -# endif - - return quantity::promote(r_scale); - } - - // quantity operator*=() - // quantity operator/=() - - /** - * @brief scale this quantity *x* by dimensionless amount @p y - * - * @return quantity representing @c x*y - **/ - template - auto scale_by(Repr2 y) const { - static_assert(!quantity_concept); - - using r_repr_type = std::common_type_t; - - r_repr_type r_scale = this->scale_ * y; - - //std::cerr << "quantity::scale_by: scale=" << scale << ", repr_type=" << reflect::Reflect::require()->canonical_name() << std::endl; - - return quantity::promote(r_scale); - } - - /** - * @brief divide this quantity *x* by dimensionless amount @p y - * - * @return quantity representing @c x/y - **/ - template - auto divide_by(Repr2 x) const { - using r_repr_type = std::common_type_t; - - r_repr_type r_scale = this->scale_ / x; - - return quantity::promote(r_scale); - } - - /** - * @brief divide dimensionless number @p x by this quantity @c y - * - * @return quantity representing @c x/y - **/ - template - auto divide_into(Repr2 x) const { - using r_unit_type = unit_invert_t; - using r_repr_type = std::common_type_t; - - r_repr_type r_scale = ((x * r_unit_type::scalefactor_type::num) - / (this->scale_ * r_unit_type::scalefactor_type::den)); - - return quantity::promote(r_scale); - } - ///@} - - /** @defgroup mpl-quantity-arithmetic **/ - ///@{ - /** @brief add quantity in-place - * - * @pre @p y must have the same dimension as @c *this. - * - * @param y quantity to add - * @return this quantity after adding y - **/ - template - quantity & operator+=(Quantity2 y) { - static_assert(same_dimension_v); - - /* relying on assignment that correctly converts-to-lhs-units */ - quantity y2 = y; - - this->scale_ += y2.scale(); - - return *this; - } - - /** @brief subtract quantity in-place - * - * @pre @p y must have the same dimensions as @c *this - * - * @param y quantity to subtract - * @return this quantity after subtracting y - **/ - template - quantity & operator-=(Quantity2 y) { - static_assert(same_dimension_v); - - quantity y2 = y; - - /* relying on assignment that correctly converts-to-lhs-units */ - this->scale_ -= y2.scale(); - - return *this; - } - ///@} - - /** @defgroup quantity-comparisonsupport **/ - ///@{ - /** @brief compare this quantity with another, return 3-way comparison - * - * @pre arguments must be quantities having the same dimension - * - * @param y rhs quantity to compare - * @return signed integer; {-ve, 0, +ve} when @c *this is {less than, equal, greater than} @p y - **/ - template - requires quantity_concept && same_dimension_v - auto compare(Quantity2 y) const { - /* convert y to same {units, repr} as *this */ - quantity y2 = y; - - auto cmp = (this->scale_ <=> y2.scale()); - - return cmp; - } - ///@} - - /** @defgroup quantity-comparison **/ - ///@{ - /** @brief 3-way comparison of two quantities - * - * @pre arguments must be quantities having the same dimension - * - * @param y rhs quantity to compare - * @return std::partial_ordering - **/ - template - requires quantity_concept && same_dimension_v - auto operator<=>(Quantity2 y) const { - return this->compare(y); - } - - /** @brief compare two quantities for equality - * - * Although compiler generates this (due to presence of 3-way comparison operator), - * it flags ambiguous overload when included alongside .h files from std::distribution. - * Look like ambiguity would need to be resolved by a header change - **/ - template - requires quantity_concept && same_dimension_v - bool operator==(Quantity2 y) const { - return std::is_eq(this->compare(y)); - } - - template - requires quantity_concept && same_dimension_v - bool operator!=(Quantity2 y) const { - return std::is_neq(this->compare(y)); - } - - - /** @addtogroup mpl-quantity-unit-conversion **/ - ///@{ - /** @brief convert to quantity with same dimension, different {unit_type, repr_type} - * - * @pre @c Quantity2 must have the same dimension as @c *this. - **/ - template - requires quantity_concept && same_dimension_v - constexpr operator Quantity2 () const { - /* avoid truncating precision when converting: - * use best available representation - */ - using tmp_repr_type = std::common_type_t; - - return Quantity2::promote(this->in_units_of()); - } - ///@} - - /** @defgroup mpl-quantity-print-support **/ - ///@{ - /** @brief write printed representation on stream - * - * @param os write on this output stream - **/ - void display(std::ostream & os) const { - os << this->scale() << unit_cstr(); - } - ///@} - - /** @defgroup mpl-quantity-assignment **/ - ///@{ - /** @brief copy constructor **/ - quantity & operator=(quantity const & x) = default; - /** @brief move constructor **/ - quantity & operator=(quantity && x) = default; - ///@} - - private: - explicit constexpr quantity(Repr x) : scale_{x} {} - - friend class promoter; - friend class promoter; - - private: - /** @brief quantity represents this multiple of a unit (that has compile-time outer-scalefactor of 1) **/ - Repr scale_ = 0; - }; /*quantity*/ - - template - constexpr auto - quantity::promote(Repr x) { - //std::cerr << "quantity::promote: x=" << x << ", R=" << reflect::Reflect::require()->canonical_name() << std::endl; - return promoter::promote(x); - } - - // ----- operator+ ----- - - template - inline constexpr Quantity1 operator+ (Quantity1 x, Quantity2 y) { - static_assert(same_dimension_v); - - /* convert y to match units used by x; - * would fail at compile time if this isn't well-defined - */ - Quantity1 y2 = y; - - return Quantity1::promote(x.scale() + y2.scale()); - } - - template - inline constexpr Quantity1 operator- (Quantity1 x, Quantity2 y) { - static_assert(std::same_as - < typename Quantity1::unit_type::dimension_type::canon_type, - typename Quantity2::unit_type::dimension_type::canon_type >); - - /* convert y to match units used by x */ - Quantity1 y2 = y; - - return Quantity1::promote(x.scale() - y2.scale()); - } - - template - inline Quantity operator- (Quantity x) { - return Quantity::promote(- x.scale()); - } - - template - inline constexpr auto operator* (Quantity1 x, Quantity2 y) { - static_assert(quantity_concept); - static_assert(quantity_concept); - - return x.multiply(y); - } - - /** e.g. DECLARE_LH_MULT(int32_t) **/ -# define DECLARE_LH_MULT(lhtype) \ - template \ - inline constexpr auto \ - operator* (lhtype x, Quantity y) { \ - static_assert(quantity_concept); \ - return y.scale_by(x); \ - } - - DECLARE_LH_MULT(int8_t); - DECLARE_LH_MULT(uint8_t); - DECLARE_LH_MULT(int16_t); - DECLARE_LH_MULT(uint16_t); - DECLARE_LH_MULT(int32_t); - DECLARE_LH_MULT(uint32_t); - DECLARE_LH_MULT(int64_t); - DECLARE_LH_MULT(uint64_t); - DECLARE_LH_MULT(float); - DECLARE_LH_MULT(double); -# undef DECLARE_LH_MULT - - /** e.g. DECLARE_RH_MULT(int32_t) **/ -# define DECLARE_RH_MULT(rhtype) \ - template \ - inline constexpr auto \ - operator* (Quantity x, rhtype y) { \ - static_assert(quantity_concept); \ - return x.scale_by(y); \ - } - - DECLARE_RH_MULT(int8_t); - DECLARE_RH_MULT(uint8_t); - DECLARE_RH_MULT(int16_t); - DECLARE_RH_MULT(uint16_t); - DECLARE_RH_MULT(int32_t); - DECLARE_RH_MULT(uint32_t); - DECLARE_RH_MULT(int64_t); - DECLARE_RH_MULT(uint64_t); - DECLARE_RH_MULT(float); - DECLARE_RH_MULT(double); -# undef DECLARE_LH_MULT - - template - inline constexpr auto operator/ (Quantity1 x, Quantity2 y) { - static_assert(quantity_concept); - static_assert(quantity_concept); - - return x.divide(y); - } - -# define DECLARE_LH_DIV(lhtype) \ - template \ - inline constexpr auto \ - operator/ (lhtype x, Quantity y) { \ - static_assert(quantity_concept); \ - return y.divide_into(x); \ - } - - DECLARE_LH_DIV(int8_t); - DECLARE_LH_DIV(uint8_t); - DECLARE_LH_DIV(int16_t); - DECLARE_LH_DIV(uint16_t); - DECLARE_LH_DIV(int32_t); - DECLARE_LH_DIV(uint32_t); - DECLARE_LH_DIV(int64_t); - DECLARE_LH_DIV(uint64_t); - DECLARE_LH_DIV(float); - DECLARE_LH_DIV(double); -# undef DECLARE_LH_DIV - -# define DECLARE_RH_DIV(rhtype) \ - template \ - inline constexpr auto \ - operator/ (Quantity x, rhtype y) { \ - static_assert(quantity_concept); \ - return x.divide_by(y); \ - } - - DECLARE_RH_DIV(int8_t) - DECLARE_RH_DIV(uint8_t) - DECLARE_RH_DIV(int16_t) - DECLARE_RH_DIV(uint16_t) - DECLARE_RH_DIV(int32_t) - DECLARE_RH_DIV(uint32_t) - DECLARE_RH_DIV(int64_t) - DECLARE_RH_DIV(uint64_t) - DECLARE_RH_DIV(float) - DECLARE_RH_DIV(double) -# undef DECLARE_RH_DIV - - template - inline std::ostream & - operator<< (std::ostream & os, quantity const & x) { - x.display(os); - return os; - } - - namespace qty { - // ----- mass ----- - - /** @brief create quantity representing @p x milligrams **/ - template - inline constexpr auto milligrams(Repr x) -> quantity { - return quantity::promote(x); - }; - - /** @brief create quantity representing @p x grams **/ - template - inline constexpr auto grams(Repr x) -> quantity { - return quantity::promote(x); - }; - - /** @brief create quantity representing @p x kilograms **/ - template - inline constexpr auto kilograms(Repr x) -> quantity { - return quantity::promote(x); - }; - - // ----- distance ----- - - /** @brief create quantity representing @p x millimeters **/ - template - inline constexpr auto millimeters(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x meters **/ - template - inline constexpr auto meters(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x kilometers **/ - template - inline constexpr auto kilometers(Repr x) -> quantity { - return quantity::promote(x); - } - - // ----- time ----- - - /** @brief create quantity representing @p x nanoseconds **/ - template - inline constexpr auto nanoseconds(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x microseconds **/ - template - inline constexpr auto microseconds(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x milliseconds **/ - template - inline constexpr auto milliseconds(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x seconds **/ - template - inline constexpr auto seconds(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x minutes **/ - template - inline constexpr auto minutes(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x hours **/ - template - inline constexpr auto hours(Repr x) -> quantity { - return quantity::promote(x); - } - - /** @brief create quantity representing @p x days (1 day = exactly 24 hours) **/ - template - inline constexpr auto days(Repr x) -> quantity { - return quantity::promote(x); - } - - // ----- time/volatility ----- - - /** quantity in units of 1/sqrt(1dy) **/ - template - inline constexpr auto volatility1d(Repr x) -> quantity { - return quantity::promote(x); - } - - /** quantity in units of 1/sqrt(30days) - **/ - template - inline constexpr auto volatility30d(Repr x) -> quantity { - return quantity::promote(x); - } - - /** quantity in units of 1/sqrt(250days) - **/ - template - inline constexpr auto volatility250d(Repr x) -> quantity { - return quantity::promote(x); - } - } /*namespace qty*/ - - namespace unit_qty { - /** @brief quantity with mass dimension, representing 1mg (1 milligram = 10^-3 grams) **/ - static constexpr auto milligram = qty::milligrams(1.0); - /** @brief quantity with mass dimension, representing 1g (1 gram) **/ - static constexpr auto gram = qty::grams(1.0); - /** @brief quantity with mass dimension, representing 1kg (1 kilogram = 1000 grams) **/ - static constexpr auto kilogram = qty::kilograms(1.0); - - /** @brief quantity with length dimension representing 1mm (10^-3 meters) **/ - static constexpr auto millimeter = qty::millimeters(1.0); - /** @brief quantity with length dimension representing 1m (1 meter) **/ - static constexpr auto meter = qty::meters(1.0); - /** @brief quantity with length dimension representing 1km (1 kilometer = 1000 meters) **/ - static constexpr auto kilometer = qty::kilometers(1.0); - - /** @brief quantity with time dimension representing 1ns (1 nanosecond = 10^-9 seconds) **/ - static constexpr auto nanosecond = qty::microseconds(1); - /** @brief quantity with time dimension representing 1us (1 microsecond = 10^-6 seconds) **/ - static constexpr auto microsecond = qty::microseconds(1); - /** @brief quantity with time dimension representing 1ms (1 milliseconds = 10^-3 seconds) **/ - static constexpr auto millisecond = qty::milliseconds(1); - /** @brief quantity with time dimension representing 1s (1 second) **/ - static constexpr auto second = qty::seconds(1); - /** @brief quantity with time dimension representing 1min (1 minute = 60 seconds) **/ - static constexpr auto minute = qty::minutes(1); - /** @brief quantity with time dimension representing 1hr (1 hour = 60 minutes) **/ - static constexpr auto hour = qty::hours(1); - /** @brief quantity with time dimension representing 1dy (1 day = 24 hours) **/ - static constexpr auto day = qty::days(1); - } - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end quantity.hpp */ diff --git a/include/xo/unit/mpl/quantity_concept.hpp b/include/xo/unit/mpl/quantity_concept.hpp deleted file mode 100644 index 1edb2c59..00000000 --- a/include/xo/unit/mpl/quantity_concept.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/** @file quantity_concept.hpp **/ - -#pragma once - -#include "unit_concept.hpp" -#include "numeric_concept.hpp" - -namespace xo { - namespace unit { - template - concept quantity_concept = requires(Quantity qty, typename Quantity::repr_type repr) - { - typename Quantity::unit_type; - typename Quantity::repr_type; - - { qty.scale() } -> std::same_as; - { Quantity::unit_cstr() } -> std::same_as; - { Quantity::unit_quantity() } -> std::same_as; - { Quantity::promote(repr) } -> std::same_as; - } && (unit_concept - && numeric_concept); - } /*namespace unit*/ -} /*namespace xo*/ diff --git a/include/xo/unit/mpl/ratio_concept.hpp b/include/xo/unit/mpl/ratio_concept.hpp deleted file mode 100644 index ecfeb4bf..00000000 --- a/include/xo/unit/mpl/ratio_concept.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/* @file ratio_concept.hpp */ - -#pragma once - -#include - -namespace xo { - namespace unit { - template - concept ratio_concept = (std::is_signed_v - && std::is_signed_v); - } /*namespace unit*/ -} /*namespace xo*/ diff --git a/include/xo/unit/mpl/ratio_util.hpp b/include/xo/unit/mpl/ratio_util.hpp deleted file mode 100644 index 970068d8..00000000 --- a/include/xo/unit/mpl/ratio_util.hpp +++ /dev/null @@ -1,242 +0,0 @@ -/* @file ratio_util.hpp */ - -#pragma once - -#include "ratio_concept.hpp" -#include "stringliteral.hpp" -#include -#include - -namespace xo { - namespace unit { - // ----- ratio_floor ----- - - template - struct ratio_floor { - using type = std::ratio; - }; - - template - using ratio_floor_t = ratio_floor::type; - - // ----- ratio_frac ----- - - template - struct ratio_frac { - static_assert(ratio_concept); - - using type = std::ratio_subtract>::type; - }; - - template - using ratio_frac_t = ratio_frac::type; - - // ----- ratio_power ----- - - /** ratio to an integer power - * - * ratio_power::type - * - * yields a std::ratio representing Base^Power. - **/ - template - struct ratio_power_aux; - - template - struct ratio_power_aux { - - /** std::ratio representing Base^(-Power) **/ - using _inverse_ratio_type = typename ratio_power_aux::type; - - /** Base^(-Power)^-1 = Base^Power **/ - using type = std::ratio_divide, _inverse_ratio_type>; - - static_assert(ratio_concept); - }; - - template - struct ratio_power_aux { - using type = std::ratio<1>; - }; - - template - struct ratio_power_aux { - using type = Base; - }; - - template - struct ratio_power_aux { - /** Base^(Power/2) **/ - using _p2_ratio_type = ratio_power_aux::type; - /** Base^(Power%2) : - * - Base^0 if Power is even - * - Base^1 if Power is odd - **/ - using _x_ratio_type = ratio_power_aux::type; - - using type = std::ratio_multiply< _x_ratio_type, - std::ratio_multiply<_p2_ratio_type, - _p2_ratio_type> >; - - static_assert(ratio_concept); - }; - - // ----- ratio_power_v ----- - - /** compute Base^Power at compile time **/ - template - using ratio_power_t = ratio_power_aux::type; - - // ----- from_ratio ----- - - /** Example: - * from_ratio --> 0.1 - * from_ratio --> 0.8 - **/ - template - constexpr Repr from_ratio() { - static_assert(ratio_concept); - - return Ratio::num / static_cast(Ratio::den); - } - - // ----- ratio2str_aux ----- - - /* note: using struct wrapper because partial specialization of function templates - * is not allowed - */ - template - struct ratio2str_aux; - - template - struct ratio2str_aux { - static constexpr auto value = stringliteral_concat("(", - stringliteral_from_int_v().value_, - "/", - stringliteral_from_int_v().value_, - ")"); - }; - - template - struct ratio2str_aux { - /* note: using struct wrapper because partial specialization of function templates - * is not allowed - */ - static constexpr auto value = stringliteral_concat("-(", - stringliteral_from_int_v<-Num>().value_, - "/", - stringliteral_from_int_v().value_, - ")"); - }; - - template - struct ratio2str_aux { - static constexpr auto value = stringliteral_concat("-", - stringliteral_from_int_v<-Num>().value_); - }; - - template - struct ratio2str_aux { - static constexpr auto value = stringliteral_from_int_v(); - }; - - template <> - struct ratio2str_aux<1, 1, false> { - static constexpr auto value = stringliteral(""); - }; - - // ----- stringliteral_from_ratio ----- - - /** Example: - * - stringliteral_from_ratio -> "^(2,3)" - **/ - template - constexpr auto stringliteral_from_ratio() { - static_assert(ratio_concept); - - using lowest_terms_type = Ratio::type; - - return ratio2str_aux().value; - }; - - template - constexpr char const * cstr_from_ratio() { - static_assert(ratio_concept); - - using lowest_terms_type = Ratio::type; - - return ratio2str_aux().value.c_str(); - }; - - // ----- exponent2str_aux ----- - - /* note: using struct wrapper because partial specialization of function templates - * is not allowed - */ - template - struct exponent2str_aux; - - template - struct exponent2str_aux { - static constexpr auto value = stringliteral_concat("^(", - stringliteral_from_int_v().value_, - "/", - stringliteral_from_int_v().value_, - ")"); - }; - - template - struct exponent2str_aux { - /* note: using struct wrapper because partial specialization of function templates - * is not allowed - */ - static constexpr auto value = stringliteral_concat("^-(", - stringliteral_from_int_v<-Num>().value_, - "/", - stringliteral_from_int_v().value_, - ")"); - }; - - template - struct exponent2str_aux { - static constexpr auto value = stringliteral_concat("^", - stringliteral_from_int_v().value_); - }; - - template - struct exponent2str_aux { - /* Example: - * - exponent2str_aux<-1, 1, true> --> "^-1" - * - exponent2str_aux<-2, 1, true> --> "^-2" - */ - static constexpr auto value = stringliteral_concat("^", - stringliteral_from_int_v().value_); - }; - - template <> - struct exponent2str_aux<1, 1, false> { - static constexpr auto value = stringliteral(""); - }; - - // ----- stringliteral_from_exponent ----- - - template - constexpr auto stringliteral_from_exponent() { - static_assert(ratio_concept); - - return exponent2str_aux().value; - }; - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end ratio_util.hpp */ diff --git a/include/xo/unit/mpl/stringliteral.hpp b/include/xo/unit/mpl/stringliteral.hpp deleted file mode 100644 index b3e68fe8..00000000 --- a/include/xo/unit/mpl/stringliteral.hpp +++ /dev/null @@ -1,170 +0,0 @@ -/* @file stringliteral.hpp */ - -#pragma once - -#include -#include -#include -#include - -namespace xo { - namespace unit { - - // ----- stringliteral ----- - - /** @class stringliteral - * - * @brief class to represent a literal string at compile time, for use as template argument - **/ - template - struct stringliteral { - constexpr stringliteral() { if (N > 0) value_[0] = '\0'; } - constexpr stringliteral(const char (&str)[N]) { std::copy_n(str, N, value_); } - constexpr int size() const { return N; } - - constexpr char const * c_str() const { return value_; } - - char value_[N]; - }; - - template < typename First, typename... Rest > - constexpr auto - all_same_v = std::conjunction_v< std::is_same... >; - - /** args and result must be stringliteral **/ - template < typename... Ts> - constexpr auto - stringliteral_concat(Ts && ... args) - { -#ifdef NOT_USING - static_assert(all_same_v...>, - "string must share the same char type"); - - using char_type = std::remove_const_t< std::remove_pointer_t < std::common_type_t < Ts... > > >; -#endif - using char_type = char; - - /** n1: total number of bytes used by arguments **/ - constexpr size_t n1 = (sizeof(Ts) + ...); - /** z1: each string arg has a null terminator included in its size, - * z1 is the number of arguments in parameter pack Ts, - * which equals the number of null terminators used - **/ - constexpr size_t z1 = sizeof...(Ts); - - /** n: number of chars in concatenated string. +1 for final null **/ - constexpr size_t n - = (n1 / sizeof(char_type)) - z1 + 1; - - stringliteral result; - - size_t pos = 0; - - auto detail_concat = [ &pos, &result ](auto && arg) { - constexpr auto count = (sizeof(arg) - sizeof(char_type)) / sizeof(char_type); - - std::copy_n(arg, count, result.value_ + pos); - pos += count; - }; - - (detail_concat(args), ...); - - return result; - } - - template - constexpr auto - stringliteral_compare(stringliteral && s1, stringliteral && s2) - { - return std::string_view(s1.value_) <=> std::string_view(s2.value_); - } - - // ----- literal_size ----- - - /** @brief compute number of chars needed to stringify an int **/ - template < int d, bool signbit = std::signbit(d) > - struct literal_size; - - template < int d > - struct literal_size { - /* d < 0 */ - static constexpr int size = 1 + literal_size<-d, false>::size; - }; - - template < int d > - struct literal_size { - /* d >= 0 */ - static constexpr int size = 1 + literal_size::size; - }; - - template <> struct literal_size<0, false> { static constexpr int size = 1; }; - template <> struct literal_size<1, false> { static constexpr int size = 1; }; - template <> struct literal_size<2, false> { static constexpr int size = 1; }; - template <> struct literal_size<3, false> { static constexpr int size = 1; }; - template <> struct literal_size<4, false> { static constexpr int size = 1; }; - template <> struct literal_size<5, false> { static constexpr int size = 1; }; - template <> struct literal_size<6, false> { static constexpr int size = 1; }; - template <> struct literal_size<7, false> { static constexpr int size = 1; }; - template <> struct literal_size<8, false> { static constexpr int size = 1; }; - template <> struct literal_size<9, false> { static constexpr int size = 1; }; - - template < int d > - constexpr int literal_size_v = literal_size::size; - - // ----- literal_from_digit ----- - - constexpr auto /*stringliteral<2>*/ stringliteral_from_digit( int d ) { - return stringliteral({ static_cast('0' + d), '\0' }); - } - -#ifdef NOT_YET_22mar24 - template < int d > - struct literal_from_digit; - - template <> struct literal_from_digit<0> { static constexpr auto value = stringliteral("0"); }; - template <> struct literal_from_digit<1> { static constexpr auto value = stringliteral("1"); }; - template <> struct literal_from_digit<2> { static constexpr auto value = stringliteral("2"); }; - template <> struct literal_from_digit<3> { static constexpr auto value = stringliteral("3"); }; - template <> struct literal_from_digit<4> { static constexpr auto value = stringliteral("4"); }; - template <> struct literal_from_digit<5> { static constexpr auto value = stringliteral("5"); }; - template <> struct literal_from_digit<6> { static constexpr auto value = stringliteral("6"); }; - template <> struct literal_from_digit<7> { static constexpr auto value = stringliteral("7"); }; - template <> struct literal_from_digit<8> { static constexpr auto value = stringliteral("8"); }; - template <> struct literal_from_digit<9> { static constexpr auto value = stringliteral("9"); }; - - template < int d > - constexpr auto literal_from_digit_v() { return literal_from_digit::value; } -#endif - - // ----- stringliteral_from_int ----- - - template < int D, int N = literal_size_v, bool signbit = std::signbit(D) > - struct stringliteral_from_int; - - template < int D, int N = literal_size_v, bool signbit = std::signbit(D) > - constexpr auto stringliteral_from_int_v() { return stringliteral_from_int::value; } - - template < int D > - struct stringliteral_from_int< D, 1, false > { - static constexpr auto value = stringliteral_from_digit(D); - }; - - template < int D, int N > - struct stringliteral_from_int< D, N, false > { - static constexpr auto _prefix = stringliteral_from_int_v< D / 10, N - 1, false >(); - static constexpr auto _suffix = stringliteral_from_digit(D % 10); - - static constexpr auto value = stringliteral_concat(_prefix.value_, _suffix.value_); - }; - - template < int D, int N > - struct stringliteral_from_int< D, N, true > { - static constexpr auto _suffix = stringliteral_from_int_v< -D, N - 1, false>(); - - static constexpr auto value = stringliteral_concat("-", _suffix.value_); - }; - - } /*namespace unit*/ -} /*namespace xo*/ - -/* end stringliteral.hpp */ diff --git a/include/xo/unit/mpl/unit.hpp b/include/xo/unit/mpl/unit.hpp deleted file mode 100644 index 54c8fffc..00000000 --- a/include/xo/unit/mpl/unit.hpp +++ /dev/null @@ -1,395 +0,0 @@ -/* @file unit.hpp */ - -#pragma once - -#include "unit_concept.hpp" -#include "dimension_impl.hpp" - -namespace xo { - namespace unit { - // ----- wrap_unit ----- - - template - struct wrap_unit { - static_assert(ratio_concept); - static_assert(bpu_list_concept); - - //using _norm_type = bpu_normalize; - - using scalefactor_type = Scalefactor; - using dim_type = BpuList; - - /* canon_type just orders dimensions by increasing native_dim_id */ - using canon_type = canonical_impl::dim_type; - - static_assert(bpu_list_concept); - }; - - // ----- normalize_unit ----- - - /* like Unit, but with scalefactor 1 */ - template - struct normalize_unit { - static_assert(unit_concept); - - using type = wrap_unit, typename Unit::dim_type>; - }; - - template - using normalize_unit_t = normalize_unit::type; - - // ----- dimensionless_v ----- - - template - constexpr auto dimensionless_v = std::same_as; - - // ----- unit_find_bpu ----- - - /** @brief find basis-power-unit matching native_dim_id - * - * Constructs dimensionless native_bpu if no match - **/ - template - struct unit_find_bpu { - using type = di_find_bpu::type; - }; - - template - using unit_find_bpu_t = unit_find_bpu::type; - - // ----- unit_abbrev_v ----- - - /** @brief canonical stringliteral abbreviation for dimension D. **/ - template - constexpr auto unit_abbrev_v = di_assemble_abbrev::value; - - // ----- unit_invert ----- - - template - struct unit_invert { - static_assert(unit_concept); - - using _sf = std::ratio_divide, typename U::scalefactor_type>; - using _di = di_invert< typename U::dim_type >::type; - - using type = wrap_unit< _sf, _di >; - - static_assert(unit_concept); - }; - - template - using unit_invert_t = unit_invert::type; - - // ----- unit_cartesian_product ----- - - template - struct unit_cartesian_product { - /* when a basis dimension (represented by a bpu<..>::c_native_dim) - * is present in both {U1, U2}, we need to pick a common unit - * (represented by bpu<..>::scalefactor_type). - * - * scale factors from such conversions are collected in: - * 1a. _mult_type::outer_scalefactor_type (compile-time exact representation using std::ratio) - * 1b. _mult_type::outer_scalefactor_inexact (compile-time constexpr) - */ - - static_assert(unit_concept); - static_assert(unit_concept); - - /* _mult_type -> describes product dimension */ - using _mult_type = di_cartesian_product< - typename U1::dim_type, - typename U2::dim_type>; - - /* compile-time exact scalefactor for product dimension - * (distilled from any forced rescaling) - */ - using _mult_sf_type = _mult_type::outer_scalefactor_type; - /* bpulist specifying basis factors (possibly to rational powers) in product dimension */ - using _mult_di_type = _mult_type::bpu_list_type; - - /* note: inexact scalefactor doesn't come up here. - * It's not present in unit types, only appears as byproduct - * of products/ratios of units - */ - using _sf1_type = typename std::ratio_multiply< - typename U1::scalefactor_type, - typename U2::scalefactor_type>::type; - - using _sf_type = typename std::ratio_multiply<_mult_sf_type, _sf1_type>::type; - - /* note: we can compute inexact scale factor, - * but can't make it a template argument - */ - using exact_unit_type = wrap_unit< _sf_type, _mult_di_type >; - - static constexpr double c_scalefactor_inexact = _mult_type::c_outer_scalefactor_inexact; - - static_assert(unit_concept); - }; - - /* WARNING: omits inexact scalefactor */ - template - using unit_cartesian_product_t = unit_cartesian_product::exact_unit_type; - - // ----- unit_divide ----- - - template - struct unit_divide { - static_assert(unit_concept); - static_assert(unit_concept); - - using _mult_type = unit_cartesian_product>; - using exact_unit_type = _mult_type::exact_unit_type; - - static constexpr double c_scalefactor_inexact = _mult_type::c_scalefactor_inexact; - }; - - /* WARNING: omits inexact scalefactor */ - template - using unit_divide_t = unit_divide::exact_unit_type; - - // ----- same_dimension ----- - - /* true iff U1 and U2 represent the same dimension, i.e. differ only in dimensionless scaling factor - * - * To verify scale also, use same_unit instead - */ - template - struct same_dimension { - static_assert(unit_concept); - static_assert(unit_concept); - - using _unit_ratio_type = typename unit_cartesian_product>::exact_unit_type; - - static_assert(std::same_as); - - static constexpr bool value = std::same_as; - }; - - template - constexpr bool same_dimension_v = same_dimension::value; - - // ----- same_unit ----- - - template - struct same_unit { - static_assert(unit_concept); - static_assert(unit_concept); - - using _unit_ratio_type = unit_cartesian_product>; - using _unit_exact_type = typename _unit_ratio_type::exact_unit_type; - using _unit_scalefactor_type = _unit_exact_type::scalefactor_type; - static constexpr double c_unit_ratio_inexact = _unit_ratio_type::c_scalefactor_inexact; - - static_assert(std::same_as<_unit_scalefactor_type, std::ratio<1>>); - static_assert(std::same_as); - - static constexpr bool value = (std::same_as<_unit_scalefactor_type, std::ratio<1>> - && (c_unit_ratio_inexact == 1.0) - && std::same_as); - }; - - template - constexpr bool same_unit_v = same_unit::value; - - // ----- unit_conversion_factor ----- - - template - struct unit_conversion_factor { - static_assert(same_dimension_v); - - using _unit_ratio_type = typename unit_cartesian_product>::exact_unit_type; - using type = _unit_ratio_type::scalefactor_type; - static constexpr double c_scalefactor_inexact = _unit_ratio_type::c_scalefactor_inexact; - }; - - /** conversion factor from U1 to U2: - * U1 = x.U2 - * with: - * x = R::num / R::den - * R = unit_conversion_factor_t - * - * WARNING: omits inexact scalefactor unit_conversion_factor::c_scalefactor_inexact - **/ - template - using unit_conversion_factor_t = unit_conversion_factor::type; - - // ----- units ----- - - namespace units { - /* computing abbreviations: - * - unit_abbrev_v :: stringliteral<...> - * - unit_abbrev_v.c_str() :: const char * - * - * relies on - * - di_assemble_abbrev, di_assemble_abbrev_helper [dimension_impl.hpp] - * - * - bpu_assemble_abbrev() [native_bpu.hpp] - * - bpu_assemble_abbrev_helper< native_bpu::c_native_dim, - * native_bpu::scalefactor_type, - * native_bpu::power_type > - * -> stringliteral - * - * + can specialize for specific combinations - * - * - native_unit_abbrev_helper< native_bpu::c_native_dim, - * native_bpu::power_type > - */ - - // ----- weight ----- - - /** @brief a unit type representing 1mg (10^-3 grams) **/ - using milligram = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("mg"); - }; - - using gram = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - using kilogram = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("kg"); - }; - - // ----- distance ----- - - using millimeter = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("mm"); - }; - - using meter = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - using kilometer = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("km"); - }; - - // ----- time ----- - - using nanosecond = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("ns"); - }; - - using microsecond = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("us"); - }; - - using millisecond = wrap_unit< std::ratio<1>, bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("ms"); - }; - - using second = wrap_unit< std::ratio<1>, bpu_node< bpu> > >; - using minute = wrap_unit< std::ratio<1>, bpu_node< bpu> > >; - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("min"); - }; - - using hour = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("hr"); - }; - - using day = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("dy"); - }; - - using month = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("mo"); - }; - - using yr250 = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - - template <> - struct scaled_native_unit_abbrev> { - static constexpr auto value = stringliteral("yr250"); - }; - - // ------ volatility ------ - - /* volatility in units of 1/sqrt(1day) - * volatility^2 in units of 1/day - */ - using volatility_1d = wrap_unit< std::ratio<1>, - bpu_node< bpu, - std::ratio<-1,2>> > >; - - /* volatility in units of 1/sqrt(30day) - * volatility^2 in units of 1/(30day) - */ - using volatility_30d = wrap_unit< std::ratio<1>, - bpu_node< bpu, - std::ratio<-1,2>> > >; - - /* volatility in units of 1/sqrt(250day) - * volatility^2 in units of 1/(250day) - */ - using volatility_250d = wrap_unit< std::ratio<1>, - bpu_node< bpu, - std::ratio<-1,2>> > >; - - using currency = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - using price = wrap_unit< std::ratio<1>, - bpu_node< bpu> > >; - } /*namespace units*/ - } /*namespace unit*/ -} /*namespace xo*/ - -/* end unit.hpp */ diff --git a/include/xo/unit/mpl/unit_concept.hpp b/include/xo/unit/mpl/unit_concept.hpp deleted file mode 100644 index 8c5fe59c..00000000 --- a/include/xo/unit/mpl/unit_concept.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* @file unit_concept.hpp */ - -#pragma once - -#include "dimension_concept.hpp" - -namespace xo { - namespace unit { - /** @brief concept for a Unit type, suitable for use with the quantity template - * - * Example: - * @code - * using namespace xo::unit; - * static_assert(unit_concept); - * @endcode - **/ - template - concept unit_concept = requires(Unit unit) - { - typename Unit::scalefactor_type; - typename Unit::dim_type; - typename Unit::canon_type; - } - && (ratio_concept - && bpu_list_concept - && bpu_list_concept); - - - /** @brief concept for a Unit type, that contains exactly one basis dimension - * - * Example: - * @code - * using namespace xo::unit - * static_assert(basis_unit_concept); - * @endcode - **/ - template - concept basis_unit_concept = requires(Unit unit) - { - typename Unit::dim_type; - typename Unit::dim_type::rest_type; - } - && (std::same_as) - && (unit_concept); - } /*namespace unit*/ -} /*namespace xo*/ - - -/* end unit_concept.hpp */