From b1b63e1b3af5e5508b28bb58309e0c2d44e6bcc6 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 14 Dec 2019 11:44:56 +0100 Subject: [PATCH] 2 parital specializations of a derived_dimension split to different types --- src/include/units/bits/deduced_symbol_text.h | 4 +- src/include/units/bits/deduced_unit.h | 12 +- src/include/units/bits/dimension_op.h | 47 +++---- src/include/units/bits/unit_text.h | 11 +- src/include/units/concepts.h | 9 +- src/include/units/derived_dimension.h | 128 +++++++++---------- src/include/units/unit.h | 2 +- test/unit_test/static/dimension_op_test.cpp | 80 +++++------- test/unit_test/static/quantity_test.cpp | 15 +-- test/unit_test/static/type_list_test.cpp | 10 +- 10 files changed, 152 insertions(+), 166 deletions(-) diff --git a/src/include/units/bits/deduced_symbol_text.h b/src/include/units/bits/deduced_symbol_text.h index 04476b27..05015919 100644 --- a/src/include/units/bits/deduced_symbol_text.h +++ b/src/include/units/bits/deduced_symbol_text.h @@ -68,7 +68,7 @@ constexpr auto exp_text() } template -constexpr auto deduced_symbol_text(derived_dimension, std::index_sequence) +constexpr auto deduced_symbol_text(exp_list, std::index_sequence) { return (exp_text() + ...); } @@ -76,7 +76,7 @@ constexpr auto deduced_symbol_text(derived_dimension, std::index_sequence template constexpr auto deduced_symbol_text() { - return deduced_symbol_text(Dim(), std::index_sequence_for()); + return deduced_symbol_text(typename Dim::recipe(), std::index_sequence_for()); } } // namespace units::detail diff --git a/src/include/units/bits/deduced_unit.h b/src/include/units/bits/deduced_unit.h index 7d846b45..9f36466b 100644 --- a/src/include/units/bits/deduced_unit.h +++ b/src/include/units/bits/deduced_unit.h @@ -27,11 +27,11 @@ namespace units::detail { // same_scaled_units -template +template inline constexpr bool same_scaled_units = false; template -inline constexpr bool same_scaled_units, Us...> = (UnitOf && ...); +inline constexpr bool same_scaled_units, Us...> = (UnitOf && ...); // deduced_unit template @@ -50,17 +50,17 @@ struct ratio_op { using ratio = ratio_op::ratio; }; -template +template struct derived_ratio; template -struct derived_ratio, Us...> { +struct derived_ratio, Us...> { using ratio = ::units::ratio<1>; }; template -struct derived_ratio, U, URest...> { - using rest_ratio = derived_ratio, URest...>::ratio; +struct derived_ratio, U, URest...> { + using rest_ratio = derived_ratio, URest...>::ratio; using ratio = ratio_op::ratio; }; diff --git a/src/include/units/bits/dimension_op.h b/src/include/units/bits/dimension_op.h index 520086c8..6ca7122e 100644 --- a/src/include/units/bits/dimension_op.h +++ b/src/include/units/bits/dimension_op.h @@ -51,7 +51,7 @@ struct equivalent_derived_dim : std::false_type {}; template requires (sizeof...(Es1) == sizeof...(Es2)) -struct equivalent_derived_dim, derived_dimension> : std::conjunction...> {}; +struct equivalent_derived_dim, derived_dimension_base> : std::conjunction...> {}; template struct equivalent_dim_impl : std::disjunction, equivalent_derived_dim, downcast_base_t>> {}; @@ -84,7 +84,7 @@ struct check_unknown { // downcast did not find a user predefined type template -struct check_unknown> { +struct check_unknown> { using type = unknown_dimension; }; @@ -114,17 +114,17 @@ struct dim_invert_impl; template struct dim_invert_impl { - using type = downcast_dimension>>; + using type = downcast_dimension>>; }; template -struct dim_invert_impl>> { +struct dim_invert_impl>> { using type = D; }; template -struct dim_invert_impl> { - using type = downcast_dimension...>>; +struct dim_invert_impl> { + using type = downcast_dimension...>>; }; template @@ -139,18 +139,21 @@ using dim_invert = detail::dim_invert_impl::type; // dimension_multiply namespace detail { -template -struct dim_unpack { - using type = D; +template +struct to_dimension; + +template +struct to_dimension> { + using type = derived_dimension_base; }; template -struct dim_unpack>> { +struct to_dimension>> { using type = D; }; /** - * @brief Merges 2 sorted derived dimensions into one units::derived_dimension + * @brief Merges 2 sorted derived dimensions into one units::derived_dimension_base * * A result of a dimensional calculation may result with many exponents of the same base dimension orginated * from different parts of the equation. As the exponents lists of both operands it is enough to merge them @@ -159,19 +162,19 @@ struct dim_unpack>> { * dimension itself. */ template -using merge_dimension = dim_unpack>::type>::type; +using merge_dimension = to_dimension>::type>::type; template struct dimension_multiply_impl; template struct dimension_multiply_impl { - using type = downcast_dimension>, derived_dimension>>>; + using type = downcast_dimension>, derived_dimension_base>>>; }; template struct dimension_multiply_impl { - using type = downcast_dimension>, typename D2::downcast_base_type>>; + using type = downcast_dimension>, typename D2::downcast_base_type>>; }; template @@ -200,11 +203,11 @@ struct dimension_sqrt_impl; template struct dimension_sqrt_impl { - using type = downcast_dimension>>; + using type = downcast_dimension>>; }; template -struct dimension_sqrt_impl>> { +struct dimension_sqrt_impl>> { using type = D; }; @@ -214,8 +217,8 @@ struct dimension_sqrt_impl { }; template -struct dimension_sqrt_impl> { - using type = downcast_dimension...>>; +struct dimension_sqrt_impl> { + using type = downcast_dimension...>>; }; } // namespace detail @@ -231,7 +234,7 @@ struct dimension_pow_impl; template struct dimension_pow_impl { - using type = downcast_dimension>>; + using type = downcast_dimension>>; }; template @@ -240,7 +243,7 @@ struct dimension_pow_impl { }; template -struct dimension_pow_impl>, N> { +struct dimension_pow_impl>, N> { using type = D; }; @@ -250,8 +253,8 @@ struct dimension_pow_impl { }; template -struct dimension_pow_impl, N> { - using type = downcast_dimension...>>; +struct dimension_pow_impl, N> { + using type = downcast_dimension...>>; }; } // namespace detail diff --git a/src/include/units/bits/unit_text.h b/src/include/units/bits/unit_text.h index af95c30e..f1fc8152 100644 --- a/src/include/units/bits/unit_text.h +++ b/src/include/units/bits/unit_text.h @@ -22,7 +22,6 @@ #pragma once -#include #include namespace units::detail { @@ -73,19 +72,19 @@ constexpr auto prefix_or_ratio_text() } template -constexpr auto derived_dimension_unit_text(derived_dimension, std::index_sequence) +constexpr auto derived_dimension_unit_text(exp_list, std::index_sequence) { return (exp_text::symbol, Idxs>() + ...); } template -constexpr auto derived_dimension_unit_text(derived_dimension d) +constexpr auto derived_dimension_unit_text(exp_list list) { - return derived_dimension_unit_text(d, std::index_sequence_for()); + return derived_dimension_unit_text(list, std::index_sequence_for()); } template -constexpr bool all_named(derived_dimension) +constexpr bool all_named(exp_list) { return (dimension_unit::is_named && ...); } @@ -97,7 +96,7 @@ constexpr auto derived_dimension_unit_text() if constexpr(all_named(recipe())) return derived_dimension_unit_text(recipe()); else - return derived_dimension_unit_text(Dim()); + return derived_dimension_unit_text(typename Dim::exponents()); } // TODO Inline below concept when switched to gcc-10 diff --git a/src/include/units/concepts.h b/src/include/units/concepts.h index 9f6184f6..46fe4668 100644 --- a/src/include/units/concepts.h +++ b/src/include/units/concepts.h @@ -112,7 +112,7 @@ inline constexpr bool is_base_dimension> = true; } // namespace detail template -concept BaseDimension = detail::is_base_dimension; // TODO Replace with is_derived_from_instantiation when fixed +concept BaseDimension = detail::is_base_dimension; // Exponent namespace detail { @@ -126,11 +126,12 @@ template concept Exponent = detail::is_exp; // DerivedDimension -template -struct derived_dimension; +template + requires (BaseDimension && ... && BaseDimension) +struct derived_dimension_base; template -concept DerivedDimension = std::is_empty_v && is_instantiation, derived_dimension>; +concept DerivedDimension = is_instantiation, derived_dimension_base>; // Dimension template diff --git a/src/include/units/derived_dimension.h b/src/include/units/derived_dimension.h index 73870a26..b50c4dde 100644 --- a/src/include/units/derived_dimension.h +++ b/src/include/units/derived_dimension.h @@ -31,41 +31,6 @@ namespace units { -/** - * @brief A derived dimension - * - * There are 2 partial specializations of this primary class template. One of them is used by the library engine - * and another one is the interface for the user to define a derived dimension. - */ -template -struct derived_dimension; - -/** - * @brief Dimensionless quantity - */ -template<> -struct derived_dimension<> : downcast_base> {}; - -/** - * @brief A dimension of a derived quantity - * - * Expression of the dependence of a quantity on the base quantities (and their base dimensions) of a system of - * quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors. - * A power of a factor is the factor raised to an exponent. - * - * A derived dimension can be formed from multiple exponents (i.e. velocity is represented as "exp, exp"). - * It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just - * "exp"). - * - * @note This partial class template specialization is used by the library engine and should not be directly instantiated - * by the user (see the other partial specialization). - * - * @tparam E a first exponent of a derived dimension - * @tparam ERest zero or more following exponents of a derived dimension - */ -template -struct derived_dimension : downcast_base> {}; // TODO rename to 'dimension'? - /** * @brief A power of factor corresponding to the dimension of a quantity * @@ -119,6 +84,31 @@ struct exp_multiply_impl { template using exp_multiply = detail::exp_multiply_impl::type; +template +struct exp_list {}; + +/** + * @brief A dimension of a derived quantity + * + * Expression of the dependence of a quantity on the base quantities (and their base dimensions) of a system of + * quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors. + * A power of a factor is the factor raised to an exponent. + * + * A derived dimension can be formed from multiple exponents (i.e. velocity is represented as "exp, exp"). + * It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just + * "exp"). + * + * @note This class template is used by the library engine and should not be directly instantiated by the user. + * + * @tparam E a first exponent of a derived dimension + * @tparam ERest zero or more following exponents of a derived dimension + */ +template + requires (BaseDimension && ... && BaseDimension) +struct derived_dimension_base : downcast_base> { + using exponents = exp_list; +}; + // make_dimension namespace detail { @@ -130,32 +120,32 @@ namespace detail { * * @tparam D derived dimension to consolidate */ -template +template struct dim_consolidate; template<> -struct dim_consolidate> { - using type = derived_dimension<>; +struct dim_consolidate> { + using type = exp_list<>; }; template -struct dim_consolidate> { - using type = derived_dimension; +struct dim_consolidate> { + using type = exp_list; }; template -struct dim_consolidate> { - using type = type_list_push_front>::type, E1>; +struct dim_consolidate> { + using type = type_list_push_front>::type, E1>; }; template -struct dim_consolidate, exp, ERest...>> { +struct dim_consolidate, exp, ERest...>> { // TODO: provide custom implementation for ratio_add using r1 = std::ratio; using r2 = std::ratio; using r = std::ratio_add; - using type = conditional>::type, - typename dim_consolidate, ERest...>>::type>; + using type = conditional>::type, + typename dim_consolidate, ERest...>>::type>; }; /** @@ -168,7 +158,7 @@ struct extract; template<> struct extract<> { - using type = derived_dimension<>; + using type = exp_list<>; }; template @@ -182,12 +172,21 @@ struct extract, ERest...> { }; template -struct extract, Num, Den>, ERest...> { +struct extract, Num, Den>, ERest...> { using type = type_list_push_front::type, exp_multiply...>; }; +template +struct to_derived_dimension_base; + +template +struct to_derived_dimension_base> { + using type = derived_dimension_base; +}; + + /** - * @brief Converts user provided derived dimension specification into a valid units::derived_dimension definition + * @brief Converts user provided derived dimension specification into a valid units::derived_dimension_base definition * * User provided definition of a derived dimension may contain the same base dimension repeated more than once on the * list possibly hidden in other derived units provided by the user. The process here should: @@ -197,7 +196,7 @@ struct extract, Num, Den>, ERest...> { * this base dimension. */ template -using make_dimension = dim_consolidate::type, exp_less>>::type; +using make_dimension = to_derived_dimension_base::type, exp_less>>::type>::type; template requires (E::den == 1 || E::den == 2) // TODO provide support for any den @@ -209,31 +208,31 @@ struct exp_ratio { using type = conditional, pow>; }; -template +template struct base_units_ratio_impl; template -struct base_units_ratio_impl> { - using type = ratio_multiply::type, typename base_units_ratio_impl>::type>; +struct base_units_ratio_impl> { + using type = ratio_multiply::type, typename base_units_ratio_impl>::type>; }; template -struct base_units_ratio_impl> { +struct base_units_ratio_impl> { using type = exp_ratio::type; }; /** * @brief Calculates the common ratio of all the references of base units in the derived dimension */ -template -using base_units_ratio = base_units_ratio_impl::type; +template +using base_units_ratio = base_units_ratio_impl::type; } // namespace detail /** * @brief The list of exponents of dimensions (both base and derived) provided by the user * - * This is the primary interface to create derived dimensions. Exponents list can contain powers of factors of both + * This is the user's interface to create derived dimensions. Exponents list can contain powers of factors of both * base and derived dimensions. This is called a "recipe" of the dimension and among others is used to print * unnamed coherent units of this dimension. * @@ -241,21 +240,18 @@ using base_units_ratio = base_units_ratio_impl::type; * of powers of base units with no other proportionality factor than one. * * The implementation is responsible for unpacking all of the dimensions into a list containing only base dimensions - * and their factors and putting them to the other (private) units::derived_dimension class template partial - * specialization. - * - * @note User should always use only this partial specialization to create derived dimensions. + * and their factors and putting them to derived_dimension_base class template. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) - * @tparam E The list of exponents of ingredient dimensions - * @tparam ERest The list of exponents of ingredient dimensions + * @tparam U a coherent unit of a derived dimension + * @tparam E the list of exponents of ingredient dimensions + * @tparam ERest the list of exponents of ingredient dimensions */ template - requires (!Exponent) -struct derived_dimension : downcast_child> { - using recipe = derived_dimension; +struct derived_dimension : downcast_child> { + using recipe = exp_list; using coherent_unit = U; - using base_units_ratio = detail::base_units_ratio>::downcast_base_type>; + using base_units_ratio = detail::base_units_ratio; }; } // namespace units diff --git a/src/include/units/unit.h b/src/include/units/unit.h index cc7973d8..c465c4c8 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -164,7 +164,7 @@ template (U::is_named && (URest::is_named && ... && true)) struct deduced_unit : downcast_child> { static constexpr bool is_named = false; - static constexpr auto symbol = detail::deduced_symbol_text(); + static constexpr auto symbol = detail::deduced_symbol_text(); using prefix_type = no_prefix; }; diff --git a/test/unit_test/static/dimension_op_test.cpp b/test/unit_test/static/dimension_op_test.cpp index 900a8b02..0da9dd31 100644 --- a/test/unit_test/static/dimension_op_test.cpp +++ b/test/unit_test/static/dimension_op_test.cpp @@ -28,13 +28,13 @@ using namespace units; namespace { -struct u0 : unit {}; +struct u0 : named_unit {}; struct d0 : base_dimension<"d0", u0> {}; -struct u1 : unit {}; +struct u1 : named_unit {}; struct d1 : base_dimension<"d1", u1> {}; -struct u2 : unit {}; +struct u2 : named_unit {}; struct d2 : base_dimension<"d2", u2> {}; -struct u3 : unit {}; +struct u3 : named_unit {}; struct d3 : base_dimension<"d3", u3> {}; // exp_invert @@ -50,77 +50,67 @@ struct typeinfo; template using extract = detail::extract::type; -static_assert(std::is_same_v, derived_dimension<>>); -static_assert(std::is_same_v>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension, exp>>); -using dim0 = derived_dimension<>; -using dim1 = derived_dimension>; -using dim2 = derived_dimension, exp>; -static_assert(std::is_same_v, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension, exp>>); +static_assert(std::is_same_v, exp_list<>>); +static_assert(std::is_same_v>, exp_list>>); +static_assert(std::is_same_v, exp>, exp_list, exp>>); +using dim1 = derived_dimension_base>; +using dim2 = derived_dimension_base, exp>; +static_assert(std::is_same_v, exp>, exp_list, exp>>); static_assert(std::is_same_v, exp, exp>, - derived_dimension, exp, exp, exp>>); + exp_list, exp, exp, exp>>); // dim_invert -static_assert(std::is_same_v>>, d0>); -static_assert(std::is_same_v>>, unknown_dimension>>); +static_assert(std::is_same_v>>, d0>); +static_assert(std::is_same_v>>, unknown_dimension>>); static_assert( - std::is_same_v, exp>>, unknown_dimension, exp>>); + std::is_same_v, exp>>, unknown_dimension, exp>>); // make_dimension template using make_dimension = detail::make_dimension; -static_assert(std::is_same_v>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension, exp>>); -static_assert(std::is_same_v, exp>, derived_dimension, exp>>); -static_assert(std::is_same_v, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension<>>); -static_assert(std::is_same_v, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp>, derived_dimension>>); +static_assert(std::is_same_v>, derived_dimension_base>>); +static_assert(std::is_same_v, exp>, derived_dimension_base, exp>>); +static_assert(std::is_same_v, exp>, derived_dimension_base, exp>>); +static_assert(std::is_same_v, exp>, derived_dimension_base>>); +static_assert(std::is_same_v, exp>, derived_dimension_base>>); +static_assert(std::is_same_v, exp>, derived_dimension_base>>); +static_assert(std::is_same_v, exp>, derived_dimension_base>>); static_assert(std::is_same_v, exp, exp, exp>, - derived_dimension, exp>>); + derived_dimension_base, exp>>); static_assert(std::is_same_v, exp, exp, exp>, - derived_dimension, exp>>); + derived_dimension_base, exp>>); -static_assert(std::is_same_v, exp, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp, exp>, derived_dimension>>); -static_assert(std::is_same_v, exp, exp, exp>, derived_dimension<>>); +static_assert(std::is_same_v, exp, exp>, derived_dimension_base>>); +static_assert(std::is_same_v, exp, exp>, derived_dimension_base>>); +static_assert(std::is_same_v, exp, exp>, derived_dimension_base>>); // dimension_multiply -static_assert(std::is_same_v>, derived_dimension>>, +static_assert(std::is_same_v>, derived_dimension_base>>, unknown_dimension, exp>>); static_assert( - std::is_same_v>, d1>, unknown_dimension, exp>>); + std::is_same_v>, d1>, unknown_dimension, exp>>); static_assert( - std::is_same_v>>, unknown_dimension, exp>>); + std::is_same_v>>, unknown_dimension, exp>>); static_assert(std::is_same_v, unknown_dimension, exp>>); static_assert(std::is_same_v< - dimension_multiply, exp, exp>, derived_dimension>>, + dimension_multiply, exp, exp>, derived_dimension_base>>, unknown_dimension, exp, exp, exp>>); static_assert(std::is_same_v< - dimension_multiply, exp, exp>, derived_dimension>>, + dimension_multiply, exp, exp>, derived_dimension_base>>, unknown_dimension, exp, exp>>); static_assert(std::is_same_v< - dimension_multiply, exp, exp>, derived_dimension>>, + dimension_multiply, exp, exp>, derived_dimension_base>>, unknown_dimension, exp>>); -static_assert(std::is_same_v>, derived_dimension>>, - unknown_dimension<>>); -static_assert(std::is_same_v>, derived_dimension>>, d0>); +static_assert(std::is_same_v>, derived_dimension_base>>, d0>); // dimension_divide -static_assert(std::is_same_v>, derived_dimension>>, +static_assert(std::is_same_v>, derived_dimension_base>>, unknown_dimension, exp>>); -static_assert(std::is_same_v>, derived_dimension>>, - unknown_dimension<>>); -static_assert(std::is_same_v>, derived_dimension>>, - unknown_dimension<>>); -static_assert(std::is_same_v>, unknown_dimension>>, d0>); +static_assert(std::is_same_v>, unknown_dimension>>, d0>); } // namespace diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 7de30728..ff4edce3 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -237,15 +237,13 @@ static_assert( std::is_same_v() * si::time()), length>); static_assert( std::is_same_v() * si::time()), length>, int>>); -// TODO uncomment below when fixed in gcc -// static_assert(std::is_same_v() * si::time()), -// quantity, exp>, scaled_unit>>>); +static_assert(std::is_same_v() * si::time()), + quantity, units::exp>, scaled_unit>>>); static_assert(std::is_same_v()), frequency>); static_assert(std::is_same_v()), frequency>, int>>); static_assert(std::is_same_v()), si::time>); -// TODO uncomment below when fixed in gcc -// static_assert(std::is_same_v()), -// quantity>, scaled_unit>>>); +static_assert(std::is_same_v()), + quantity>, scaled_unit>>>); static_assert(std::is_same_v() / 1.0), length>); static_assert(std::is_same_v() / length()), double>); static_assert(std::is_same_v() / length()), double>); @@ -253,9 +251,8 @@ static_assert( std::is_same_v() / si::time()), velocity>); static_assert( std::is_same_v() / si::time()), velocity>>>); -// TODO uncomment below when fixed in gcc -// static_assert(std::is_same_v() / length()), -// quantity, exp>, scaled_unit>>>); +static_assert(std::is_same_v() / length()), + quantity, units::exp>, scaled_unit>>>); static_assert(std::is_same_v() % short(1)), length>); static_assert(std::is_same_v() % length(1)), length>); diff --git a/test/unit_test/static/type_list_test.cpp b/test/unit_test/static/type_list_test.cpp index 9c5bec90..f4236a6a 100644 --- a/test/unit_test/static/type_list_test.cpp +++ b/test/unit_test/static/type_list_test.cpp @@ -84,9 +84,9 @@ static_assert( std::is_same_v>::second_list, type_list>); // type_list_merge_sorted -struct u0 : unit {}; +struct u0 : named_unit {}; struct d0 : base_dimension<"d0", u0> {}; -struct u1 : unit {}; +struct u1 : named_unit {}; struct d1 : base_dimension<"d1", u1> {}; static_assert(std::is_same_v>, type_list>, exp_less>, @@ -99,10 +99,10 @@ static_assert(std::is_same_v>, type_ template using exp_sort = type_list_sort; -static_assert(std::is_same_v>>, derived_dimension>>); +static_assert(std::is_same_v>>, exp_list>>); static_assert( - std::is_same_v, exp>>, derived_dimension, exp>>); + std::is_same_v, exp>>, exp_list, exp>>); static_assert( - std::is_same_v, exp>>, derived_dimension, exp>>); + std::is_same_v, exp>>, exp_list, exp>>); } // namespace