/* @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 obs { // ----- 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_list ----- /** 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; }; // ----- 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 obs*/ } /*namespace xo*/ /* end dimension_impl.hpp */