diff --git a/src/core/include/mp-units/bits/algorithm.h b/src/core/include/mp-units/bits/algorithm.h index 1028962b..b9a8ca96 100644 --- a/src/core/include/mp-units/bits/algorithm.h +++ b/src/core/include/mp-units/bits/algorithm.h @@ -132,6 +132,38 @@ constexpr T max(std::initializer_list ilist) return *max_element(ilist.begin(), ilist.end()); } +template +constexpr const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +constexpr ForwardIt min_element(ForwardIt first, ForwardIt last) +{ + if (first == last) return last; + + ForwardIt smallest = first; + ++first; + + for (; first != last; ++first) + if (*first < *smallest) smallest = first; + + return smallest; +} + +template +constexpr T min(std::initializer_list ilist) +{ + return *min_element(ilist.begin(), ilist.end()); +} + +template +constexpr const T& min(const T& a, const T& b) +{ + return (b < a) ? b : a; +} + template struct in_out_result { [[no_unique_address]] I in; diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index 1a55f50c..fde4d157 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -702,7 +702,7 @@ struct explode_result { template [[nodiscard]] consteval explode_result common_convertibility_with(explode_to_equation_result res) const { - return {quantity, std::min(result, res.result)}; + return {quantity, min(result, res.result)}; } }; @@ -724,10 +724,10 @@ template d ? n : d; + constexpr auto max_compl = n > d ? n : d; - if constexpr (max == Complexity || ((n >= d && !requires { explode_to_equation(Num{}); }) || - (n < d && !requires { explode_to_equation(Den{}); }))) + if constexpr (max_compl == Complexity || ((n >= d && !requires { explode_to_equation(Num{}); }) || + (n < d && !requires { explode_to_equation(Den{}); }))) return explode_result{(map_power(Num{}) * ... * map_power(Nums{})) / (map_power(Den{}) * ... * map_power(Dens{}))}; else { if constexpr (n >= d) { @@ -932,23 +932,19 @@ template; if constexpr (Entities == process_entities::numerators) { if constexpr (Ext.prepend == prepend_rest::first) - return std::min(res, - are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to)); + return min(res, are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to)); else - return std::min(res, - are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to)); + return min(res, are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to)); } else { if constexpr (Ext.prepend == prepend_rest::first) - return std::min(res, - are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to)); + return min(res, are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to)); else - return std::min(res, - are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{})); + return min(res, are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{})); } } } else { @@ -995,30 +991,30 @@ template 1) { - if constexpr (num_from_compl == max) { + constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl, den_to_compl}); + if constexpr (max_compl > 1) { + if constexpr (num_from_compl == max_compl) { constexpr auto res = explode_to_equation(NumFrom{}); return convertible_impl( (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); - } else if constexpr (den_from_compl == max) { + } else if constexpr (den_from_compl == max_compl) { constexpr auto res = explode_to_equation(DenFrom{}); return convertible_impl( (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); - } else if constexpr (num_to_compl == max) { + } else if constexpr (num_to_compl == max_compl) { constexpr auto res = explode_to_equation(NumTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / - (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - (res.equation * ... * map_power(NumsTo{})) / - (map_power(DenTo{}) * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { constexpr auto res = explode_to_equation(DenTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / - (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - (map_power(NumTo{}) * ... * map_power(NumsTo{})) / - (res.equation * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } } } @@ -1041,25 +1037,23 @@ template 1) { - if constexpr (den_from_compl == max) { + constexpr auto max_compl = max({num_to_compl, den_from_compl, den_to_compl}); + if constexpr (max_compl > 1) { + if constexpr (den_from_compl == max_compl) { constexpr auto res = explode_to_equation(DenFrom{}); return convertible_impl( dimensionless / (res.equation * ... * map_power(DensFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); - } else if constexpr (num_to_compl == max) { + } else if constexpr (num_to_compl == max_compl) { constexpr auto res = explode_to_equation(NumTo{}); - return std::min( - res.result, convertible_impl( - dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - (res.equation * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { constexpr auto res = explode_to_equation(DenTo{}); - return std::min( - res.result, convertible_impl( - dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (res.equation * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } } } @@ -1082,23 +1076,23 @@ template 1) { - if constexpr (num_from_compl == max) { + constexpr auto max_compl = max({num_from_compl, num_to_compl, den_to_compl}); + if constexpr (max_compl > 1) { + if constexpr (num_from_compl == max_compl) { constexpr auto res = explode_to_equation(NumFrom{}); return convertible_impl( (res.equation * ... * map_power(NumsFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); - } else if constexpr (num_to_compl == max) { + } else if constexpr (num_to_compl == max_compl) { constexpr auto res = explode_to_equation(NumTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), - (res.equation * ... * map_power(NumsTo{})) / - (map_power(DenTo{}) * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { constexpr auto res = explode_to_equation(DenTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), - (map_power(NumTo{}) * ... * map_power(NumsTo{})) / - (res.equation * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } } } @@ -1122,23 +1116,23 @@ template 1) { - if constexpr (num_from_compl == max) { + constexpr auto max_compl = max({num_from_compl, den_from_compl, den_to_compl}); + if constexpr (max_compl > 1) { + if constexpr (num_from_compl == max_compl) { constexpr auto res = explode_to_equation(NumFrom{}); return convertible_impl( (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); - } else if constexpr (den_from_compl == max) { + } else if constexpr (den_from_compl == max_compl) { constexpr auto res = explode_to_equation(DenFrom{}); return convertible_impl( (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else { constexpr auto res = explode_to_equation(DenTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / - (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - dimensionless / (res.equation * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + dimensionless / (res.equation * ... * map_power(DensTo{})))); } } } @@ -1162,23 +1156,23 @@ template 1) { - if constexpr (num_from_compl == max) { + constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl}); + if constexpr (max_compl > 1) { + if constexpr (num_from_compl == max_compl) { constexpr auto res = explode_to_equation(NumFrom{}); return convertible_impl( (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{}))); - } else if constexpr (den_from_compl == max) { + } else if constexpr (den_from_compl == max_compl) { constexpr auto res = explode_to_equation(DenFrom{}); return convertible_impl( (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{}))); } else { constexpr auto res = explode_to_equation(NumTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / - (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - (res.equation * ... * map_power(NumsTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})))); } } } @@ -1197,16 +1191,16 @@ template 1) { - if constexpr (num_from_compl == max) { + constexpr auto max_compl = max(num_from_compl, num_to_compl); + if constexpr (max_compl > 1) { + if constexpr (num_from_compl == max_compl) { constexpr auto res = explode_to_equation(NumFrom{}); return convertible_impl((res.equation * ... * map_power(NumsFrom{})), (map_power(NumTo{}) * ... * map_power(NumsTo{}))); } else { constexpr auto res = explode_to_equation(NumTo{}); - return std::min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), - (res.equation * ... * map_power(NumsTo{})))); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (res.equation * ... * map_power(NumsTo{})))); } } } @@ -1225,17 +1219,16 @@ template 1) { - if constexpr (den_from_compl == max) { + constexpr auto max_compl = max(den_from_compl, den_to_compl); + if constexpr (max_compl > 1) { + if constexpr (den_from_compl == max_compl) { constexpr auto res = explode_to_equation(DenFrom{}); return convertible_impl(dimensionless / (res.equation * ... * map_power(DensFrom{})), dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else { constexpr auto res = explode_to_equation(DenTo{}); - return std::min(res.result, - convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), - dimensionless / (res.equation * ... * map_power(DensTo{})))); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + dimensionless / (res.equation * ... * map_power(DensTo{})))); } } } @@ -1375,7 +1368,7 @@ template return convertible_impl(explode(from).quantity, to); else { constexpr auto res = explode(to); - return std::min(res.result, convertible_impl(from, res.quantity)); + return min(res.result, convertible_impl(from, res.quantity)); } } } else if constexpr (IntermediateDerivedQuantitySpec && IntermediateDerivedQuantitySpec) { @@ -1386,17 +1379,17 @@ template return convertible_impl(res.quantity, to); else if constexpr (requires { to._equation_; }) { constexpr auto eq = explode_to_equation(to); - return std::min(eq.result, convertible_impl(res.quantity, eq.equation)); + return min(eq.result, convertible_impl(res.quantity, eq.equation)); } else return are_ingredients_convertible(from, to); } else if constexpr (IntermediateDerivedQuantitySpec) { auto res = explode(to); if constexpr (NamedQuantitySpec>) - return std::min(res.result, convertible_impl(from, res.quantity)); + return min(res.result, convertible_impl(from, res.quantity)); else if constexpr (requires { from._equation_; }) - return std::min(res.result, convertible_impl(from._equation_, res.quantity)); + return min(res.result, convertible_impl(from._equation_, res.quantity)); else - return std::min(res.result, are_ingredients_convertible(from, to)); + return min(res.result, are_ingredients_convertible(from, to)); } return no; } diff --git a/test/unit_test/runtime/almost_equals.h b/test/unit_test/runtime/almost_equals.h index b3af6689..264182f3 100644 --- a/test/unit_test/runtime/almost_equals.h +++ b/test/unit_test/runtime/almost_equals.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace mp_units {