GCC Code Coverage Report


Directory: ./
File: libs/capy/include/boost/capy/type_traits.hpp
Date: 2026-01-23 10:17:56
Exec Total Coverage
Lines: 0 2 0.0%
Functions: 0 0 -%
Branches: 0 0 -%

Line Branch Exec Source
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
24 /** Concept for types that support the tuple protocol.
25
26 A type satisfies `has_tuple_protocol` if `std::tuple_size<T>`
27 is a complete type with a `value` member.
28
29 @tparam T The type to check.
30 */
31 template<typename T>
32 concept has_tuple_protocol = requires {
33 std::tuple_size<std::remove_cvref_t<T>>::value;
34 };
35
36 namespace detail {
37
38 template<typename T, std::size_t... Is>
39 auto decomposed_types_impl(std::index_sequence<Is...>)
40 -> std::tuple<std::tuple_element_t<Is, std::remove_cvref_t<T>>...>;
41
42 template<typename T>
43 requires has_tuple_protocol<T>
44 using decomposed_types_t = decltype(
45 decomposed_types_impl<T>(
46 std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<T>>>{}
47 )
48 );
49
50 template<typename T>
51 auto get_awaiter(T&& t)
52 {
53 if constexpr (requires { std::forward<T>(t).operator co_await(); })
54 {
55 return std::forward<T>(t).operator co_await();
56 }
57 else if constexpr (requires { operator co_await(std::forward<T>(t)); })
58 {
59 return operator co_await(std::forward<T>(t));
60 }
61 else
62 {
63 return std::forward<T>(t);
64 }
65 }
66
67 template<typename A>
68 using awaitable_return_t = decltype(
69 get_awaiter(std::declval<A>()).await_resume()
70 );
71
72 } // namespace detail
73
74 /** Concept for types that decompose to a specific typelist.
75
76 A type satisfies `decomposes_to` if it supports structured bindings
77 via the tuple protocol and its element types match the specified
78 typelist exactly.
79
80 @tparam T The type to check.
81 @tparam Types The expected element types after decomposition.
82
83 @par Requirements
84 @li `T` must satisfy the tuple protocol (`std::tuple_size`,
85 `std::tuple_element`)
86 @li The number of elements must equal `sizeof...(Types)`
87 @li Each element type must match the corresponding type in `Types`
88
89 @par Example
90 @code
91 static_assert(decomposes_to<std::pair<int, double>, int, double>);
92 static_assert(decomposes_to<std::tuple<int, float, char>, int, float, char>);
93 static_assert(decomposes_to<std::array<int, 3>, int, int, int>);
94
95 // Constrain a function template
96 template<typename T>
97 requires decomposes_to<T, system::error_code, std::size_t>
98 void process_result(T&& result)
99 {
100 auto [ec, n] = std::forward<T>(result);
101 // ...
102 }
103 @endcode
104
105 @note Plain aggregates without the tuple protocol are not supported.
106 Use `std::pair`, `std::tuple`, `std::array`, or add the tuple
107 protocol to your type.
108 */
109 template<typename T, typename... Types>
110 concept decomposes_to =
111 has_tuple_protocol<T> &&
112 std::same_as<
113 detail::decomposed_types_t<T>,
114 std::tuple<Types...>
115 >;
116
117 /** Concept for awaitables whose return type decomposes to a specific typelist.
118
119 A type satisfies `awaitable_decomposes_to` if it is an awaitable
120 (has `await_resume`) and its return type satisfies @ref decomposes_to
121 with the specified typelist.
122
123 @tparam A The awaitable type.
124 @tparam Types The expected element types after decomposition.
125
126 @par Requirements
127 @li `A` must be an awaitable (directly or via `operator co_await`)
128 @li The return type of `await_resume()` must satisfy @ref decomposes_to
129 with `Types...`
130
131 @par Example
132 @code
133 // Constrain a function to accept only awaitables that return
134 // a decomposable result of (error_code, size_t)
135 template<typename A>
136 requires awaitable_decomposes_to<A, system::error_code, std::size_t>
137 task<void> process(A&& op)
138 {
139 auto [ec, n] = co_await std::forward<A>(op);
140 if (ec)
141 co_return;
142 // process n bytes...
143 }
144 @endcode
145
146 @see decomposes_to
147 */
148 template<typename A, typename... Types>
149 concept awaitable_decomposes_to = requires {
150 typename detail::awaitable_return_t<A>;
151 } && decomposes_to<detail::awaitable_return_t<A>, Types...>;
152
153 } // namespace capy
154 } // namespace boost
155
156 #endif
157