LCOV - code coverage report
Current view: top level - boost/capy - type_traits.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 2 0
Test Date: 2026-01-24 00:02:10 Functions: 0.0 % 12 0

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       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_TYPE_TRAITS_HPP
      11              : #define BOOST_CAPY_TYPE_TRAITS_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : 
      15              : #include <concepts>
      16              : #include <cstddef>
      17              : #include <tuple>
      18              : #include <type_traits>
      19              : #include <utility>
      20              : 
      21              : namespace boost {
      22              : namespace capy {
      23              : namespace detail {
      24              : 
      25              : struct any_type
      26              : {
      27              :     template <typename T>
      28              :     constexpr operator T() const noexcept;
      29              : };
      30              : 
      31              : template <typename T, std::size_t N>
      32              : concept is_tuple_n = requires {
      33              :     std::tuple_size<std::remove_cvref_t<T>>::value;
      34              : } && std::tuple_size<std::remove_cvref_t<T>>::value == N;
      35              : 
      36              : // clang-format off
      37              : template <typename T>
      38              : concept is_decomposable_1 =
      39              :     (std::is_aggregate_v<std::remove_cvref_t<T>> &&
      40              :         requires { std::remove_cvref_t<T>{ any_type{} }; } &&
      41              :         !requires { std::remove_cvref_t<T>{ any_type{}, any_type{} }; }
      42              :     ) || is_tuple_n<T, 1>;
      43              : 
      44              : template <typename T>
      45              : concept is_decomposable_2 = 
      46              :     (std::is_aggregate_v<std::remove_cvref_t<T>> &&
      47              :         requires { std::remove_cvref_t<T>{ any_type{}, any_type{} }; } &&
      48              :         !requires { std::remove_cvref_t<T>{ any_type{}, any_type{}, any_type{} }; }
      49              :     ) || is_tuple_n<T, 2>;
      50              : 
      51              : template <typename T>
      52              : concept is_decomposable_3 = 
      53              :     (std::is_aggregate_v<std::remove_cvref_t<T>> &&
      54              :         requires { std::remove_cvref_t<T>{ any_type{}, any_type{}, any_type{} }; } &&
      55              :         !requires { std::remove_cvref_t<T>{ any_type{}, any_type{}, any_type{}, any_type{} }; }
      56              :     ) || is_tuple_n<T, 3>;
      57              : 
      58              : template <typename T>
      59              : concept is_decomposable_4 = 
      60              :     (std::is_aggregate_v<std::remove_cvref_t<T>> &&
      61              :         requires { std::remove_cvref_t<T>{ any_type{}, any_type{}, any_type{}, any_type{} }; } &&
      62              :         !requires { std::remove_cvref_t<T>{ any_type{}, any_type{}, any_type{}, any_type{}, any_type{} }; }
      63              :     ) || is_tuple_n<T, 4>;
      64              : 
      65              : // clang-format on
      66              : 
      67              : template <is_decomposable_1 T>
      68              : auto decomposed_types(T&& t)
      69              : {
      70              :     auto [v0] = t;
      71              :     return std::make_tuple(v0);
      72              : }
      73              : 
      74              : template <is_decomposable_2 T>
      75              : auto decomposed_types(T&& t)
      76              : {
      77              :     auto [v0, v1] = t;
      78              :     return std::make_tuple(v0, v1);
      79              : }
      80              : 
      81              : template <is_decomposable_3 T>
      82              : auto decomposed_types(T&& t)
      83              : {
      84              :     auto [v0, v1, v2] = t;
      85              :     return std::make_tuple(v0, v1, v2);
      86              : }
      87              : 
      88              : template <is_decomposable_4 T>
      89              : auto decomposed_types(T&& t)
      90              : {
      91              :     auto [v0, v1, v2, v3] = t;
      92              :     return std::make_tuple(v0, v1, v2, v3);
      93              : }
      94              : 
      95              : template <class T>
      96              : std::tuple<> decomposed_types(T&&)
      97              : {
      98              :     return {};
      99              : }
     100              : 
     101              : template<typename T>
     102            0 : auto get_awaiter(T&& t)
     103              : {
     104              :     if constexpr (requires { std::forward<T>(t).operator co_await(); })
     105              :     {
     106              :         return std::forward<T>(t).operator co_await();
     107              :     }
     108              :     else if constexpr (requires { operator co_await(std::forward<T>(t)); })
     109              :     {
     110              :         return operator co_await(std::forward<T>(t));
     111              :     }
     112              :     else
     113              :     {
     114            0 :         return std::forward<T>(t);
     115              :     }
     116              : }
     117              : 
     118              : template<typename A>
     119              : using awaitable_return_t = decltype(
     120              :     get_awaiter(std::declval<A>()).await_resume()
     121              : );
     122              : 
     123              : template <typename T, typename... Types>
     124              : concept decomposes_to = requires(T&& t) {
     125              :     { decomposed_types(std::forward<T>(t)) } -> std::same_as<std::tuple<Types...>>;
     126              : };
     127              : 
     128              : } // namespace detail
     129              : 
     130              : /** Concept for awaitables whose return type decomposes to a specific typelist.
     131              : 
     132              :     A type satisfies `awaitable_decomposes_to` if it is an awaitable
     133              :     (has `await_resume`) and its return type decomposes to the
     134              :     specified typelist.
     135              : 
     136              :     @tparam A The awaitable type.
     137              :     @tparam Types The expected element types after decomposition.
     138              : 
     139              :     @par Requirements
     140              :     @li `A` must be an awaitable (directly or via `operator co_await`)
     141              :     @li The return type of `await_resume()` must decompose to `Types...`
     142              : 
     143              :     @par Example
     144              :     @code
     145              :     // Constrain a function to accept only awaitables that return
     146              :     // a decomposable result of (error_code, size_t)
     147              :     template<typename A>
     148              :         requires awaitable_decomposes_to<A, system::error_code, std::size_t>
     149              :     task<void> process(A&& op)
     150              :     {
     151              :         auto [ec, n] = co_await std::forward<A>(op);
     152              :         if (ec)
     153              :             co_return;
     154              :         // process n bytes...
     155              :     }
     156              :     @endcode
     157              : */
     158              : template<typename A, typename... Types>
     159              : concept awaitable_decomposes_to = requires {
     160              :     typename detail::awaitable_return_t<A>;
     161              : } && detail::decomposes_to<detail::awaitable_return_t<A>, Types...>;
     162              : 
     163              : } // namespace capy
     164              : } // namespace boost
     165              : 
     166              : #endif
        

Generated by: LCOV version 2.3