From 8d1eb4c41595cc8ef7ab6d7af327c622b6737d1f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 14 Dec 2019 12:23:47 +0100 Subject: [PATCH] derived_dimension code split to a few smaller files --- src/include/units/bits/base_units_ratio.h | 60 ++++++ .../units/bits/derived_dimension_base.h | 61 ++++++ src/include/units/bits/dim_consolidate.h | 67 ++++++ src/include/units/bits/dim_unpack.h | 59 ++++++ src/include/units/concepts.h | 6 +- src/include/units/derived_dimension.h | 191 +----------------- src/include/units/exp.h | 87 ++++++++ test/unit_test/static/dimension_op_test.cpp | 69 ++++--- 8 files changed, 381 insertions(+), 219 deletions(-) create mode 100644 src/include/units/bits/base_units_ratio.h create mode 100644 src/include/units/bits/derived_dimension_base.h create mode 100644 src/include/units/bits/dim_consolidate.h create mode 100644 src/include/units/bits/dim_unpack.h create mode 100644 src/include/units/exp.h diff --git a/src/include/units/bits/base_units_ratio.h b/src/include/units/bits/base_units_ratio.h new file mode 100644 index 00000000..06ef2a5c --- /dev/null +++ b/src/include/units/bits/base_units_ratio.h @@ -0,0 +1,60 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace units::detail { + +template + requires (E::den == 1 || E::den == 2) // TODO provide support for any den +struct exp_ratio { + using base_ratio = E::dimension::base_unit::ratio; + using positive_ratio = conditional, base_ratio>; + static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num; + using pow = ratio_pow; + using type = conditional, pow>; +}; + +template +struct base_units_ratio_impl; + +template +struct base_units_ratio_impl> { + using type = ratio_multiply::type, typename base_units_ratio_impl>::type>; +}; + +template +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; + +} // namespace units::detail diff --git a/src/include/units/bits/derived_dimension_base.h b/src/include/units/bits/derived_dimension_base.h new file mode 100644 index 00000000..c58ec217 --- /dev/null +++ b/src/include/units/bits/derived_dimension_base.h @@ -0,0 +1,61 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace units::detail { + +/** + * @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; +}; + +template +struct to_derived_dimension_base; + +template +struct to_derived_dimension_base> { + using type = derived_dimension_base; +}; + +} // namespace units::detail diff --git a/src/include/units/bits/dim_consolidate.h b/src/include/units/bits/dim_consolidate.h new file mode 100644 index 00000000..5a433706 --- /dev/null +++ b/src/include/units/bits/dim_consolidate.h @@ -0,0 +1,67 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include // TODO remove this dependency with #11 + +namespace units::detail { + +/** + * @brief Consolidates contiguous ranges of exponents of the same dimension + * + * If there is more than one exponent with the same dimension they are aggregated into one exponent by adding + * their exponents. If this accumulation will result with 0, such a dimension is removed from the list. + * + * @tparam D derived dimension to consolidate + */ +template +struct dim_consolidate; + +template<> +struct dim_consolidate> { + using type = exp_list<>; +}; + +template +struct dim_consolidate> { + using type = exp_list; +}; + +template +struct dim_consolidate> { + using type = type_list_push_front>::type, E1>; +}; + +template +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>; +}; + +} // namespace units::detail diff --git a/src/include/units/bits/dim_unpack.h b/src/include/units/bits/dim_unpack.h new file mode 100644 index 00000000..710ee17b --- /dev/null +++ b/src/include/units/bits/dim_unpack.h @@ -0,0 +1,59 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace units::detail { + +/** + * @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions + * + * @tparam Es Exponents of potentially derived dimensions + */ +template +struct dim_unpack; + +template<> +struct dim_unpack<> { + using type = exp_list<>; +}; + +template +struct dim_unpack, ERest...> { + using type = type_list_push_front::type, exp>; +}; + +template +struct dim_unpack, ERest...> { + using type = dim_unpack, Num, Den>, ERest...>::type; +}; + +template +struct dim_unpack, Num, Den>, ERest...> { + using type = type_list_push_front::type, exp_multiply...>; +}; + +} // namespace units::detail diff --git a/src/include/units/concepts.h b/src/include/units/concepts.h index 46fe4668..3934a93c 100644 --- a/src/include/units/concepts.h +++ b/src/include/units/concepts.h @@ -126,12 +126,16 @@ template concept Exponent = detail::is_exp; // DerivedDimension +namespace detail { + template requires (BaseDimension && ... && BaseDimension) struct derived_dimension_base; +} // namespace detail + template -concept DerivedDimension = is_instantiation, derived_dimension_base>; +concept DerivedDimension = is_instantiation, detail::derived_dimension_base>; // Dimension template diff --git a/src/include/units/derived_dimension.h b/src/include/units/derived_dimension.h index b50c4dde..753c31a4 100644 --- a/src/include/units/derived_dimension.h +++ b/src/include/units/derived_dimension.h @@ -23,168 +23,18 @@ #pragma once #include +#include +#include +#include +#include #include -#include #include -#include -#include +#include namespace units { -/** - * @brief A power of factor corresponding to the dimension of a quantity - * - * @tparam Dim component dimension of a derived quantity - * @tparam Num numinator of the factor - * @tparam Den denominator of the factor - */ -template -struct exp { - using dimension = Dim; - static constexpr int num = Num; - static constexpr int den = Den; -}; - -// is_exp namespace detail { -template -inline constexpr bool is_exp> = true; - -} // namespace detail - -// exp_less -template -struct exp_less : base_dimension_less {}; - -// exp_invert -namespace detail { - -template -constexpr exp exp_invert_impl(exp); - -} // namespace detail - -template -using exp_invert = decltype(detail::exp_invert_impl(E())); - -// exp_multiply -namespace detail { - -template -struct exp_multiply_impl { - using r1 = ratio; - using r2 = ratio; - using r = ratio_multiply; - using type = exp; -}; - -} // namespace detail - -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 { - -/** - * @brief Consolidates contiguous ranges of exponents of the same dimension - * - * If there is more than one exponent with the same dimension they are aggregated into one exponent by adding - * their exponents. If this accumulation will result with 0, such a dimension is removed from the list. - * - * @tparam D derived dimension to consolidate - */ -template -struct dim_consolidate; - -template<> -struct dim_consolidate> { - using type = exp_list<>; -}; - -template -struct dim_consolidate> { - using type = exp_list; -}; - -template -struct dim_consolidate> { - using type = type_list_push_front>::type, E1>; -}; - -template -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>; -}; - -/** - * @brief Extracts the list of potentially derived dimensions to a list containing only base dimensions - * - * @tparam Es Exponents of potentially derived dimensions - */ -template -struct extract; - -template<> -struct extract<> { - using type = exp_list<>; -}; - -template -struct extract, ERest...> { - using type = type_list_push_front::type, exp>; -}; - -template -struct extract, ERest...> { - using type = extract, Num, Den>, ERest...>::type; -}; - -template -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_base definition * @@ -196,36 +46,7 @@ struct to_derived_dimension_base> { * this base dimension. */ template -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 -struct exp_ratio { - using base_ratio = E::dimension::base_unit::ratio; - using positive_ratio = conditional, base_ratio>; - static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num; - using pow = ratio_pow; - using type = conditional, pow>; -}; - -template -struct base_units_ratio_impl; - -template -struct base_units_ratio_impl> { - using type = ratio_multiply::type, typename base_units_ratio_impl>::type>; -}; - -template -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; +using make_dimension = to_derived_dimension_base::type, exp_less>>::type>::type; } // namespace detail diff --git a/src/include/units/exp.h b/src/include/units/exp.h new file mode 100644 index 00000000..b2d71d67 --- /dev/null +++ b/src/include/units/exp.h @@ -0,0 +1,87 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace units { + +/** + * @brief A power of factor corresponding to the dimension of a quantity + * + * @tparam Dim component dimension of a derived quantity + * @tparam Num numinator of the factor + * @tparam Den denominator of the factor + */ +template +struct exp { + using dimension = Dim; + static constexpr int num = Num; + static constexpr int den = Den; +}; + +// is_exp +namespace detail { + +template +inline constexpr bool is_exp> = true; + +} // namespace detail + +// exp_less +template + requires BaseDimension && BaseDimension +struct exp_less : base_dimension_less {}; + +// exp_invert +namespace detail { + +template +constexpr exp exp_invert_impl(exp); + +} // namespace detail + +template +using exp_invert = decltype(detail::exp_invert_impl(E())); + +// exp_multiply +namespace detail { + +template +struct exp_multiply_impl { + using r1 = ratio; + using r2 = ratio; + using r = ratio_multiply; + using type = exp; +}; + +} // namespace detail + +template +using exp_multiply = detail::exp_multiply_impl::type; + +template +struct exp_list {}; + +} // namespace units diff --git a/test/unit_test/static/dimension_op_test.cpp b/test/unit_test/static/dimension_op_test.cpp index 0da9dd31..4ac7fa61 100644 --- a/test/unit_test/static/dimension_op_test.cpp +++ b/test/unit_test/static/dimension_op_test.cpp @@ -42,75 +42,78 @@ struct d3 : base_dimension<"d3", u3> {}; static_assert(std::is_same_v>, exp>); static_assert(std::is_same_v>, exp>); -// extract +// dim_unpack template struct typeinfo; template -using extract = detail::extract::type; +using dim_unpack = detail::dim_unpack::type; -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>, +template +using derived_dim = detail::derived_dimension_base; + +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_dim>; +using dim2 = derived_dim, exp>; +static_assert(std::is_same_v, exp>, exp_list, exp>>); +static_assert(std::is_same_v, 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_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>, derived_dim>>); +static_assert(std::is_same_v, exp>, derived_dim, exp>>); +static_assert(std::is_same_v, exp>, derived_dim, exp>>); +static_assert(std::is_same_v, exp>, derived_dim>>); +static_assert(std::is_same_v, exp>, derived_dim>>); +static_assert(std::is_same_v, exp>, derived_dim>>); +static_assert(std::is_same_v, exp>, derived_dim>>); static_assert(std::is_same_v, exp, exp, exp>, - derived_dimension_base, exp>>); + derived_dim, exp>>); static_assert(std::is_same_v, exp, exp, exp>, - derived_dimension_base, exp>>); + derived_dim, exp>>); -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>>); +static_assert(std::is_same_v, exp, exp>, derived_dim>>); +static_assert(std::is_same_v, exp, exp>, derived_dim>>); +static_assert(std::is_same_v, exp, exp>, derived_dim>>); // dimension_multiply -static_assert(std::is_same_v>, derived_dimension_base>>, +static_assert(std::is_same_v>, derived_dim>>, 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_base>>, + dimension_multiply, exp, exp>, derived_dim>>, unknown_dimension, exp, exp, exp>>); static_assert(std::is_same_v< - dimension_multiply, exp, exp>, derived_dimension_base>>, + dimension_multiply, exp, exp>, derived_dim>>, unknown_dimension, exp, exp>>); static_assert(std::is_same_v< - dimension_multiply, exp, exp>, derived_dimension_base>>, + dimension_multiply, exp, exp>, derived_dim>>, unknown_dimension, exp>>); -static_assert(std::is_same_v>, derived_dimension_base>>, d0>); +static_assert(std::is_same_v>, derived_dim>>, d0>); // dimension_divide -static_assert(std::is_same_v>, derived_dimension_base>>, +static_assert(std::is_same_v>, derived_dim>>, unknown_dimension, exp>>); -static_assert(std::is_same_v>, unknown_dimension>>, d0>); +static_assert(std::is_same_v>, unknown_dimension>>, d0>); } // namespace