// 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 #include namespace units { template concept bool BaseDimension = std::is_empty_v && requires { { T::value } -> std::same_as; }; namespace detail { template constexpr bool less() { const char* p1 = D1::value; const char* p2 = D2::value; for(; (*p1 != '\0') && (*p2 != '\0'); ++p1, (void) ++p2) { if(*p1 < *p2) return true; if(*p2 < *p1) return false; } return (*p1 == '\0') && (*p2 != '\0'); } } // base_dimension_less template struct base_dimension_less : std::bool_constant()> { }; // is_exp namespace detail { template inline constexpr bool is_exp = false; // partial specialization for an exp type provided below } // namespace detail template concept bool Exponent = detail::is_exp; template struct dimension; // is_dimension namespace detail { template inline constexpr bool is_dimension = false; template inline constexpr bool is_dimension> = true; } // namespace detail template concept bool Dimension = std::is_empty_v && detail::is_dimension>; // exp template requires BaseDimension || Dimension 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 template struct exp_invert; template struct exp_invert> { using type = exp; }; template using exp_invert_t = exp_invert::type; // exp_multiply template struct exp_multiply { // todo: provide custom implementation for ratio_add using r1 = std::ratio; using r2 = std::ratio; using r = std::ratio_multiply; using type = exp; }; template using exp_multiply_t = exp_multiply::type; // dimension template struct dimension : downcast_base> {}; // same_dim template inline constexpr bool same_dim = std::is_same_v; // dim_invert template struct dim_invert; template struct dim_invert> : std::type_identity...>>> {}; template using dim_invert_t = dim_invert>::type; // todo: force as the only user interface to create dimensions through modules // make_dimension namespace detail { template struct dim_consolidate; template using dim_consolidate_t = dim_consolidate::type; template<> struct dim_consolidate> { using type = dimension<>; }; template struct dim_consolidate> { using type = dimension; }; template struct dim_consolidate> { using type = type_list_push_front>, 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>, dim_consolidate_t, ERest...>>>; }; template struct extract; template using extract_t = extract::type; template<> struct extract<> { using type = dimension<>; }; template struct extract, ERest...> { using type = type_list_push_front, exp>; }; template struct extract, Num, Den>, ERest...> { using type = type_list_push_front, exp_multiply_t...>; }; template struct extract, ERest...> { using type = extract_t, Num, Den>, ERest...>; }; } // namespace detail template struct make_dimension { using type = detail::dim_consolidate_t, exp_less>>; }; template using make_dimension_t = make_dimension::type; template struct merge_dimension { using type = detail::dim_consolidate_t>; }; template using merge_dimension_t = merge_dimension::type; // dimension_multiply template struct dimension_multiply; template struct dimension_multiply, dimension> : std::type_identity, dimension>>> {}; template using dimension_multiply_t = dimension_multiply::type; // dimension_divide template struct dimension_divide; template struct dimension_divide, dimension> : dimension_multiply, dimension...>> { }; template using dimension_divide_t = dimension_divide::type; // dimension_sqrt template struct dimension_sqrt; template struct dimension_sqrt> : std::type_identity...>>> {}; template using dimension_sqrt_t = dimension_sqrt::type; // dimension_pow template struct dimension_pow; template struct dimension_pow, N> : std::type_identity...>>> {}; template using dimension_pow_t = dimension_pow::type; } // namespace units