Skip to content

Commit

Permalink
fix: std::tuple is not freestanding on gcc-14 with C++23
Browse files Browse the repository at this point in the history
  • Loading branch information
mpusz committed Dec 28, 2024
1 parent 74988f6 commit dd6f29b
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 22 deletions.
12 changes: 12 additions & 0 deletions src/core/include/mp-units/ext/algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ constexpr ForwardIt max_element(ForwardIt first, ForwardIt last)
return largest;
}

template<class ForwardIt, class Compare>
constexpr ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp)
{
if (first == last) return last;

ForwardIt largest = first;
while (++first != last)
if (comp(*largest, *first)) largest = first;

return largest;
}

template<class T>
constexpr T max(std::initializer_list<T> ilist)
{
Expand Down
49 changes: 27 additions & 22 deletions src/core/include/mp-units/framework/quantity_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -867,31 +867,39 @@ template<TypeList From, TypeList To>
return detail::try_extract_common_base(type_list<>{}, from, type_list<>{}, to);
}

struct get_max_complexity_result_base {
int complexity;
int index;
};

template<typename... Elems>
[[nodiscard]] consteval std::tuple<int, int> get_max_complexity(type_list<Elems...>)
[[nodiscard]] consteval get_max_complexity_result_base get_max_complexity(type_list<Elems...>)
{
if constexpr (sizeof...(Elems) == 0)
return {-1, -1};
else {
const std::initializer_list<int> list{detail::get_complexity_impl(Elems{})...};
const auto it = max_element(list.begin(), list.end());
return {*it, it - list.begin()};
const auto it = detail::max_element(list.begin(), list.end());
return {*it, static_cast<int>(it - list.begin())};
}
}

enum class ingredient_type : std::int8_t { numerator_from, denominator_from, numerator_to, denominator_to };

struct get_max_complexity_result : get_max_complexity_result_base {
ingredient_type type;
};

template<TypeList NumFrom, TypeList DenFrom, TypeList NumTo, TypeList DenTo>
[[nodiscard]] consteval std::tuple<int, std::size_t, ingredient_type> get_max_complexity(NumFrom num_from,
DenFrom den_from, NumTo num_to,
DenTo den_to)
[[nodiscard]] consteval get_max_complexity_result get_max_complexity(NumFrom num_from, DenFrom den_from, NumTo num_to,
DenTo den_to)
{
const std::initializer_list<std::tuple<int, int>> list{
const std::initializer_list<get_max_complexity_result_base> list{
detail::get_max_complexity(num_from), detail::get_max_complexity(den_from), detail::get_max_complexity(num_to),
detail::get_max_complexity(den_to)};
const auto it =
max_element(list.begin(), list.end(), [](auto lhs, auto rhs) { return std::get<0>(lhs) < std::get<0>(rhs); });
return std::tuple_cat(*it, std::tuple{static_cast<ingredient_type>(it - list.begin())});
detail::max_element(list.begin(), list.end(), [](auto lhs, auto rhs) { return lhs.complexity < rhs.complexity; });
return {*it, static_cast<ingredient_type>(it - list.begin())};
}

template<QuantitySpec Equation, TypeList Num, TypeList Den>
Expand Down Expand Up @@ -945,49 +953,46 @@ template<TypeList NumFrom, TypeList DenFrom, TypeList NumTo, TypeList DenTo>
} else {
// otherwise, get the ingredient with the highest complexity
constexpr auto max_compl_res = detail::get_max_complexity(NumFrom{}, DenFrom{}, NumTo{}, DenTo{});
constexpr int max_compl = std::get<0>(max_compl_res);
constexpr std::size_t idx = std::get<1>(max_compl_res);
constexpr ingredient_type type = std::get<2>(max_compl_res);

constexpr auto list = [&] {
if constexpr (type == ingredient_type::numerator_from)
if constexpr (max_compl_res.type == ingredient_type::numerator_from)
return NumFrom{};
else if constexpr (type == ingredient_type::denominator_from)
else if constexpr (max_compl_res.type == ingredient_type::denominator_from)
return DenFrom{};
else if constexpr (type == ingredient_type::numerator_to)
else if constexpr (max_compl_res.type == ingredient_type::numerator_to)
return NumTo{};
else
return DenTo{};
}();
using extracted = type_list_extract<MP_UNITS_NONCONST_TYPE(list), idx>;
using extracted = type_list_extract<MP_UNITS_NONCONST_TYPE(list), static_cast<std::size_t>(max_compl_res.index)>;

// before exploding check if the ingredient is convertible with dimensionless
if constexpr (type == ingredient_type::numerator_from && num_to_size + den_to_size == 0) {
if constexpr (max_compl_res.type == ingredient_type::numerator_from && num_to_size + den_to_size == 0) {
constexpr specs_convertible_result res =
detail::convertible(detail::get_factor(typename extracted::element{}), dimensionless);
if constexpr (res != specs_convertible_result::no)
return detail::min(res,
detail::are_ingredients_convertible(typename extracted::rest{}, den_from, num_to, den_to));
} else if constexpr (type == ingredient_type::numerator_to && num_from_size + den_from_size == 0) {
} else if constexpr (max_compl_res.type == ingredient_type::numerator_to && num_from_size + den_from_size == 0) {
constexpr specs_convertible_result res =
detail::convertible(dimensionless, detail::get_factor(typename extracted::element{}));
if constexpr (res != specs_convertible_result::no)
return detail::min(
res, detail::are_ingredients_convertible(num_from, den_from, typename extracted::rest{}, den_to));
}

if constexpr (max_compl > 0) {
if constexpr (max_compl_res.complexity > 0) {
// explode the ingredient to the underlying equation
constexpr auto explode_res = detail::explode(typename extracted::element{});
if constexpr (type == ingredient_type::numerator_from) {
if constexpr (max_compl_res.type == ingredient_type::numerator_from) {
const auto [num, den] =
detail::merge_with_equation(explode_res.equation, typename extracted::rest{}, den_from);
return detail::are_ingredients_convertible(num, den, num_to, den_to);
} else if constexpr (type == ingredient_type::denominator_from) {
} else if constexpr (max_compl_res.type == ingredient_type::denominator_from) {
const auto [num, den] =
detail::merge_with_equation(dimensionless / explode_res.equation, num_from, typename extracted::rest{});
return detail::min(explode_res.result, detail::are_ingredients_convertible(num, den, num_to, den_to));
} else if constexpr (type == ingredient_type::numerator_to) {
} else if constexpr (max_compl_res.type == ingredient_type::numerator_to) {
const auto [num, den] = detail::merge_with_equation(explode_res.equation, typename extracted::rest{}, den_to);
return detail::min(explode_res.result, detail::are_ingredients_convertible(num_from, den_from, num, den));
} else {
Expand Down

0 comments on commit dd6f29b

Please sign in to comment.