// 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 std::experimental::units { struct base_dimension { const char* name; }; constexpr bool operator==(const base_dimension& lhs, const base_dimension& rhs) { const char* p1 = lhs.name; const char* p2 = rhs.name; for(; (*p1 != '\0') && (*p2 != '\0'); ++p1, (void)++p2) { if(*p1 != *p2) return false; } return *p1 == *p2; } constexpr bool operator<(const base_dimension& lhs, const base_dimension& rhs) { const char* p1 = lhs.name; const char* p2 = rhs.name; 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 { }; // exp template struct exp { static constexpr const base_dimension& dimension = BaseDimension; static constexpr int value = Value; }; // is_exp namespace detail { template inline constexpr bool is_exp = false; template inline constexpr bool is_exp> = true; } // namespace detail template concept bool Exponent = detail::is_exp; // exp_dim_id_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; // dimension template struct dimension : downcast_base> {}; // 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>; // dim_invert template struct dim_invert; template struct dim_invert> : std::type_identity...>>> {}; template using dim_invert_t = dim_invert::type; // 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 rest = dim_consolidate_t>; using type = conditional>, dimension, type_list_push_front>; }; template struct dim_consolidate, exp, ERest...>> { using type = conditional>, dim_consolidate_t, 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; } // namespace std::experimental::units