100.00% Lines (17/17) 100.00% Functions (5/5)
TLA Baseline Branch
Line Hits Code Line Hits Code
  1 + //
  2 + // Copyright (c) 2026 Steve Gerbino
  3 + //
  4 + // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5 + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6 + //
  7 + // Official repository: https://github.com/cppalliance/capy
  8 + //
  9 +
  10 + #ifndef BOOST_CAPY_DETAIL_RESULTS_COMBINATORS_HPP
  11 + #define BOOST_CAPY_DETAIL_RESULTS_COMBINATORS_HPP
  12 +
  13 + #include <boost/capy/concept/context_awaitable.hpp>
  14 + #include <boost/capy/results.hpp>
  15 +
  16 + #include <system_error>
  17 + #include <tuple>
  18 + #include <type_traits>
  19 + #include <utility>
  20 +
  21 + namespace boost {
  22 + namespace capy {
  23 + namespace detail {
  24 +
  25 + /// True when every awaitable in the pack returns a `results`.
  26 + template<typename... As>
  27 + concept all_results_awaitables =
  28 + (is_results_v<awaitable_result_t<As>> && ...);
  29 +
  30 + /// True when the `results`-aware when_all overload should be used.
  31 + template<typename... As>
  32 + concept when_all_results_eligible =
  33 + (sizeof...(As) > 0)
  34 + && all_results_awaitables<As...>;
  35 +
  36 + /// True when the `results`-aware when_any overload should be used.
  37 + template<typename... As>
  38 + concept when_any_results_eligible =
  39 + (sizeof...(As) > 0)
  40 + && all_results_awaitables<As...>;
  41 +
  42 + /// Map a `results` specialization to its contributed payload type.
  43 + ///
  44 + /// results<T> -> T (unwrap single)
  45 + /// results<Ts...> -> tuple<Ts...> (zero, two, or more)
  46 + template<typename Result>
  47 + struct results_payload;
  48 +
  49 + template<typename T>
  50 + struct results_payload<results<T>>
  51 + {
  52 + using type = T;
  53 + };
  54 +
  55 + template<typename... Ts>
  56 + struct results_payload<results<Ts...>>
  57 + {
  58 + using type = std::tuple<Ts...>;
  59 + };
  60 +
  61 + template<typename Result>
  62 + using results_payload_t =
  63 + typename results_payload<Result>::type;
  64 +
  65 + /// Extract the payload value(s) from a `results`,
  66 + /// matching the type produced by results_payload_t.
  67 + template<typename T>
  68 + T
HITGNC   69 + 107 extract_results_payload(results<T>&& r)
  70 + {
HITGNC   71 + 107 return std::get<1>(std::move(r));
  72 + }
  73 +
  74 + template<typename... Ts>
  75 + std::tuple<Ts...>
HITGNC   76 + 55 extract_results_payload(results<Ts...>&& r)
  77 + {
HITGNC   78 + 61 return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
HITGNC   79 + 55 return std::tuple<Ts...>(std::get<Is + 1>(std::move(r))...);
HITGNC   80 + 56 }(std::index_sequence_for<Ts...>{});
  81 + }
  82 +
  83 + /// Reconstruct a success `results` from a payload extracted by when_any.
  84 + template<typename Result>
  85 + struct results_from_payload;
  86 +
  87 + template<typename T>
  88 + struct results_from_payload<results<T>>
  89 + {
  90 + static results<T> apply(T t)
  91 + {
  92 + return results<T>{std::error_code(), std::move(t)};
  93 + }
  94 + };
  95 +
  96 + template<typename... Ts>
  97 + struct results_from_payload<results<Ts...>>
  98 + {
  99 + static results<Ts...> apply(std::tuple<Ts...> t)
  100 + {
  101 + return std::tuple_cat(
  102 + std::tuple<std::error_code>(), std::move(t));
  103 + }
  104 + };
  105 +
  106 + /// Build the outer `results` for when_all from a tuple of child `results`.
  107 + template<typename ResultType, typename Tuple, std::size_t... Is>
  108 + ResultType
HITGNC   109 + 50 build_when_all_results_impl(Tuple&& results, std::index_sequence<Is...>)
  110 + {
HITGNC   111 + 50 std::error_code ec;
HITGNC   112 + 109 (void)((std::get<0>(std::get<Is>(results)) && !ec
HITGNC   113 + 23 ? (ec = std::get<0>(std::get<Is>(results)), true)
HITGNC   114 + 36 : false) || ...);
  115 +
HITGNC   116 + 141 return ResultType{ec, extract_results_payload(
HITGNC   117 + 147 std::move(std::get<Is>(results)))...};
HITGNC   118 + 20 }
  119 +
  120 + template<typename ResultType, typename... Results>
  121 + ResultType
HITGNC   122 + 50 build_when_all_results(std::tuple<Results...>&& results)
  123 + {
  124 + return build_when_all_results_impl<ResultType>(
HITGNC   125 + 50 std::move(results),
HITGNC   126 + 50 std::index_sequence_for<Results...>{});
  127 + }
  128 +
  129 + } // namespace detail
  130 + } // namespace capy
  131 + } // namespace boost
  132 +
  133 + #endif