xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__concepts.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
1 /*
2  * Copyright (c) 2023 NVIDIA Corporation
3  *
4  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5  * (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  *
8  *   https://llvm.org/LICENSE.txt
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #if __cpp_concepts < 2019'07L
19 #  error This library requires support for C++20 concepts
20 #endif
21 
22 #include "__config.hpp"
23 #include "__type_traits.hpp"
24 
25 #include <version>
26 
27 // Perhaps the stdlib lacks support for concepts though:
28 #if __has_include(<concepts>) && __cpp_lib_concepts >= 2020'02L
29 #  define STDEXEC_HAS_STD_CONCEPTS_HEADER() 1
30 #else
31 #  define STDEXEC_HAS_STD_CONCEPTS_HEADER() 0
32 #endif
33 
34 #if STDEXEC_HAS_STD_CONCEPTS_HEADER()
35 #  include <concepts>
36 #else
37 #  include <type_traits>
38 #endif
39 
40 namespace stdexec {
41   //////////////////////////////////////////////////////////////////////////////////////////////////
42   template <class _Fun, class... _As>
43   concept __callable = requires(_Fun&& __fun, _As&&... __as) {
44     static_cast<_Fun &&>(__fun)(static_cast<_As &&>(__as)...);
45   };
46   template <class _Fun, class... _As>
47   concept __nothrow_callable = __callable<_Fun, _As...> && requires(_Fun&& __fun, _As&&... __as) {
48     { static_cast<_Fun &&>(__fun)(static_cast<_As &&>(__as)...) } noexcept;
49   };
50 
51   //////////////////////////////////////////////////////////////////////////////////////////////////
52   template <class...>
53   struct __types;
54 
55   template <class... _Ts>
56   concept __typename = requires {
57     typename __types<_Ts...>; // NOLINT
58   };
59 
60   //////////////////////////////////////////////////////////////////////////////////////////////////
61   template <class _Ap, class _Bp>
62   concept __same_as = STDEXEC_IS_SAME(_Ap, _Bp);
63 
64   // Handy concepts
65   template <class _Ty, class _Up>
66   concept __decays_to = __same_as<__decay_t<_Ty>, _Up>;
67 
68   template <class _Ty, class _Up>
69   concept __not_decays_to = !__decays_to<_Ty, _Up>;
70 
71   template <bool _TrueOrFalse>
72   concept __satisfies = _TrueOrFalse;
73 
74   template <class...>
75   concept __true = true;
76 
77   template <class _Cp>
78   concept __class = __true<int _Cp::*> && (!__same_as<const _Cp, _Cp>);
79 
80   template <class _Ty, class... _As>
81   concept __one_of = (__same_as<_Ty, _As> || ...);
82 
83   template <class _Ty, class... _Us>
84   concept __all_of = (__same_as<_Ty, _Us> && ...);
85 
86   template <class _Ty, class... _Us>
87   concept __none_of = ((!__same_as<_Ty, _Us>) && ...);
88 
89   template <class, template <class...> class>
90   constexpr bool __is_instance_of_ = false;
91   template <class... _As, template <class...> class _Ty>
92   constexpr bool __is_instance_of_<_Ty<_As...>, _Ty> = true;
93 
94   template <class _Ay, template <class...> class _Ty>
95   concept __is_instance_of = __is_instance_of_<_Ay, _Ty>;
96 
97   template <class _Ay, template <class...> class _Ty>
98   concept __is_not_instance_of = !__is_instance_of<_Ay, _Ty>;
99 } // namespace stdexec
100 
101 namespace stdexec::__std_concepts {
102   // Make sure we're using a same_as concept that doesn't instantiate std::is_same
103   template <class _Ap, class _Bp>
104   concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>;
105 
106 #if STDEXEC_HAS_STD_CONCEPTS_HEADER()
107 
108   using std::integral;
109   using std::derived_from;
110   using std::convertible_to;
111   using std::equality_comparable;
112 
113 #else
114 
115   template <class T>
116   concept integral = std::is_integral_v<T>;
117 
118   template <class _Ap, class _Bp>
119   concept derived_from = STDEXEC_IS_BASE_OF(_Bp, _Ap)
120                       && STDEXEC_IS_CONVERTIBLE_TO(const volatile _Ap*, const volatile _Bp*);
121 
122   template <class _From, class _To>
123   concept convertible_to = STDEXEC_IS_CONVERTIBLE_TO(_From, _To)
124                         && requires(_From (&__fun)()) { static_cast<_To>(__fun()); };
125 
126   template <class _Ty>
127   concept equality_comparable = requires(__cref_t<_Ty> __t) {
128     { __t == __t } -> convertible_to<bool>;
129     { __t != __t } -> convertible_to<bool>;
130   };
131 #endif
132 } // namespace stdexec::__std_concepts
133 
134 namespace stdexec {
135   using namespace __std_concepts;
136 
137   // Avoid using libstdc++'s object concepts because they instantiate a
138   // lot of templates.
139 #if STDEXEC_HAS_BUILTIN(__is_nothrow_destructible) || STDEXEC_MSVC()
140   template <class _Ty>
141   concept destructible = __is_nothrow_destructible(_Ty);
142 #else
143   template <class _Ty>
144   inline constexpr bool __destructible_ = requires(_Ty && (&__fn)() noexcept) {
145     { __fn().~_Ty() } noexcept;
146   };
147   template <class _Ty>
148   inline constexpr bool __destructible_<_Ty&> = true;
149   template <class _Ty>
150   inline constexpr bool __destructible_<_Ty&&> = true;
151   template <class _Ty, std::size_t _Np>
152   inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>;
153 
154   template <class T>
155   concept destructible = __destructible_<T>;
156 #endif
157 
158   template <class _Ty, class... _As>
159   concept constructible_from = destructible<_Ty> && STDEXEC_IS_CONSTRUCTIBLE(_Ty, _As...);
160 
161   template <class _Ty>
162   concept default_initializable = constructible_from<_Ty> && requires { _Ty{}; }
163                                && requires { ::new _Ty; };
164 
165   template <class _Ty>
166   concept move_constructible = constructible_from<_Ty, _Ty>;
167 
168   template <class _Ty>
169   concept copy_constructible = move_constructible<_Ty> && constructible_from<_Ty, _Ty const &>;
170 
171   template <class _LHS, class _RHS>
172   concept assignable_from = same_as<_LHS, _LHS&> &&
173                             // std::common_reference_with<
174                             //   const std::remove_reference_t<_LHS>&,
175                             //   const std::remove_reference_t<_RHS>&> &&
176                             requires(_LHS __lhs, _RHS&& __rhs) {
177                               { __lhs = static_cast<_RHS &&>(__rhs) } -> same_as<_LHS>;
178                             };
179 
180   namespace __swap {
181     using std::swap;
182 
183     template <class _Ty, class _Uy>
184     concept swappable_with = requires(_Ty&& __t, _Uy&& __u) {
185       swap(static_cast<_Ty &&>(__t), static_cast<_Uy &&>(__u));
186     };
187 
188     inline constexpr auto const __fn =
189       []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) noexcept(
190         noexcept(swap(static_cast<_Ty&&>(__t), static_cast<_Uy&&>(__u)))) {
191         swap(static_cast<_Ty&&>(__t), static_cast<_Uy&&>(__u));
192       };
193   } // namespace __swap
194 
195   using __swap::swappable_with;
196   inline constexpr auto const & swap = __swap::__fn;
197 
198   template <class _Ty>
199   concept swappable = requires(_Ty& a, _Ty& b) { swap(a, b); };
200 
201   template <class _Ty>
202   concept movable = std::is_object_v<_Ty> && move_constructible<_Ty> && assignable_from<_Ty&, _Ty>
203                  && swappable<_Ty>;
204 
205   template <class _Ty>
206   concept copyable = copy_constructible<_Ty> && movable<_Ty> && assignable_from<_Ty&, _Ty&>
207                   && assignable_from<_Ty&, const _Ty&> && assignable_from<_Ty&, const _Ty>;
208 
209   template <class _Ty>
210   concept semiregular = copyable<_Ty> && default_initializable<_Ty>;
211 
212   template <class _Ty>
213   concept regular = semiregular<_Ty> && equality_comparable<_Ty>;
214 
215   // Not exactly right, but close.
216   template <class _Ty>
217   concept __boolean_testable_ = convertible_to<_Ty, bool>;
218 
219   template <class T, class U>
220   concept __partially_ordered_with = requires(__cref_t<T> t, __cref_t<U> u) {
221     { t < u } -> __boolean_testable_;
222     { t > u } -> __boolean_testable_;
223     { t <= u } -> __boolean_testable_;
224     { t >= u } -> __boolean_testable_;
225     { u < t } -> __boolean_testable_;
226     { u > t } -> __boolean_testable_;
227     { u <= t } -> __boolean_testable_;
228     { u >= t } -> __boolean_testable_;
229   };
230 
231   template <class _Ty>
232   concept totally_ordered = equality_comparable<_Ty> && __partially_ordered_with<_Ty, _Ty>;
233 
234   template <class _Ty>
235   concept __movable_value = move_constructible<__decay_t<_Ty>>
236                          && constructible_from<__decay_t<_Ty>, _Ty>;
237 
238   template <class _Ty>
239   concept __nothrow_movable_value = __movable_value<_Ty> && requires(_Ty&& __t) {
240     { __decay_t<_Ty>{__decay_t<_Ty>{static_cast<_Ty &&>(__t)}} } noexcept;
241   };
242 
243   template <class _Ty, class... _As>
244   concept __nothrow_constructible_from = constructible_from<_Ty, _As...>
245                                       && STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(_Ty, _As...);
246 
247   template <class _Ty>
248   concept __nothrow_move_constructible = __nothrow_constructible_from<_Ty, _Ty>;
249 
250   template <class _Ty>
251   concept __nothrow_copy_constructible = __nothrow_constructible_from<_Ty, const _Ty&>;
252 
253   template <class... _Ts>
254   concept __decay_copyable = (constructible_from<__decay_t<_Ts>, _Ts> && ...);
255 
256   template <class... _Ts>
257   using __decay_copyable_t = __mbool<__decay_copyable<_Ts...>>;
258 
259   template <class... _Ts>
260   concept __nothrow_decay_copyable = (__nothrow_constructible_from<__decay_t<_Ts>, _Ts> && ...);
261 
262   template <class... _Ts>
263   using __nothrow_decay_copyable_t = __mbool<__nothrow_decay_copyable<_Ts...>>;
264 
265   template <class _Ty, class _Up>
266   concept __decays_to_derived_from = derived_from<__decay_t<_Ty>, _Up>;
267 } // namespace stdexec
268