13e20fa8bSPatrick Williams /*
23e20fa8bSPatrick Williams  * Copyright (c) 2023 NVIDIA Corporation
33e20fa8bSPatrick Williams  *
43e20fa8bSPatrick Williams  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
53e20fa8bSPatrick Williams  * (the "License"); you may not use this file except in compliance with
63e20fa8bSPatrick Williams  * the License. You may obtain a copy of the License at
73e20fa8bSPatrick Williams  *
83e20fa8bSPatrick Williams  *   https://llvm.org/LICENSE.txt
93e20fa8bSPatrick Williams  *
103e20fa8bSPatrick Williams  * Unless required by applicable law or agreed to in writing, software
113e20fa8bSPatrick Williams  * distributed under the License is distributed on an "AS IS" BASIS,
123e20fa8bSPatrick Williams  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e20fa8bSPatrick Williams  * See the License for the specific language governing permissions and
143e20fa8bSPatrick Williams  * limitations under the License.
153e20fa8bSPatrick Williams  */
163e20fa8bSPatrick Williams #pragma once
173e20fa8bSPatrick Williams 
185cee9157SPatrick Williams #if __cpp_concepts < 201907L
195cee9157SPatrick Williams #error This library requires support for C++20 concepts
205cee9157SPatrick Williams #endif
215cee9157SPatrick Williams 
223e20fa8bSPatrick Williams #include "__config.hpp"
233e20fa8bSPatrick Williams #include "__type_traits.hpp"
243e20fa8bSPatrick Williams 
255cee9157SPatrick Williams #include <version>
265cee9157SPatrick Williams 
275cee9157SPatrick Williams // Perhaps the stdlib lacks support for concepts though:
285cee9157SPatrick Williams #if __has_include(<concepts>) && __cpp_lib_concepts >= 202002
295cee9157SPatrick Williams #define STDEXEC_HAS_STD_CONCEPTS_HEADER() 1
305cee9157SPatrick Williams #else
315cee9157SPatrick Williams #define STDEXEC_HAS_STD_CONCEPTS_HEADER() 0
325cee9157SPatrick Williams #endif
335cee9157SPatrick Williams 
345cee9157SPatrick Williams #if STDEXEC_HAS_STD_CONCEPTS_HEADER()
355cee9157SPatrick Williams #include <concepts>
365cee9157SPatrick Williams #else
375cee9157SPatrick Williams #include <type_traits>
385cee9157SPatrick Williams #endif
395cee9157SPatrick Williams 
403e20fa8bSPatrick Williams namespace stdexec
413e20fa8bSPatrick Williams {
423e20fa8bSPatrick Williams //////////////////////////////////////////////////////////////////////////////////////////////////
433e20fa8bSPatrick Williams template <class _Fun, class... _As>
443e20fa8bSPatrick Williams concept __callable =                                             //
453e20fa8bSPatrick Williams     requires(_Fun&& __fun, _As&&... __as) {                      //
466e675883SPatrick Williams         static_cast<_Fun&&>(__fun)(static_cast<_As&&>(__as)...); //
473e20fa8bSPatrick Williams     };
483e20fa8bSPatrick Williams template <class _Fun, class... _As>
493e20fa8bSPatrick Williams concept __nothrow_callable =    //
503e20fa8bSPatrick Williams     __callable<_Fun, _As...> && //
513e20fa8bSPatrick Williams     requires(_Fun&& __fun, _As&&... __as) {
52*06f265f6SPatrick Williams         { static_cast<_Fun&&>(__fun)(static_cast<_As&&>(__as)...) } noexcept;
533e20fa8bSPatrick Williams     };
543e20fa8bSPatrick Williams 
553e20fa8bSPatrick Williams //////////////////////////////////////////////////////////////////////////////////////////////////
563e20fa8bSPatrick Williams template <class...>
573e20fa8bSPatrick Williams struct __types;
583e20fa8bSPatrick Williams 
593e20fa8bSPatrick Williams template <class... _Ts>
603e20fa8bSPatrick Williams concept __typename = requires { typename __types<_Ts...>; };
613e20fa8bSPatrick Williams 
623e20fa8bSPatrick Williams //////////////////////////////////////////////////////////////////////////////////////////////////
633e20fa8bSPatrick Williams template <class _Ap, class _Bp>
645cee9157SPatrick Williams concept __same_as = STDEXEC_IS_SAME(_Ap, _Bp);
653e20fa8bSPatrick Williams 
663e20fa8bSPatrick Williams // Handy concepts
673e20fa8bSPatrick Williams template <class _Ty, class _Up>
683e20fa8bSPatrick Williams concept __decays_to = __same_as<__decay_t<_Ty>, _Up>;
693e20fa8bSPatrick Williams 
703e20fa8bSPatrick Williams template <class _Ty, class _Up>
713e20fa8bSPatrick Williams concept __not_decays_to = !__decays_to<_Ty, _Up>;
723e20fa8bSPatrick Williams 
733e20fa8bSPatrick Williams template <bool _TrueOrFalse>
743e20fa8bSPatrick Williams concept __satisfies = _TrueOrFalse;
753e20fa8bSPatrick Williams 
763e20fa8bSPatrick Williams template <class...>
773e20fa8bSPatrick Williams concept __true = true;
783e20fa8bSPatrick Williams 
793e20fa8bSPatrick Williams template <class _Cp>
803e20fa8bSPatrick Williams concept __class = __true<int _Cp::*> && (!__same_as<const _Cp, _Cp>);
813e20fa8bSPatrick Williams 
823e20fa8bSPatrick Williams template <class _Ty, class... _As>
833e20fa8bSPatrick Williams concept __one_of = (__same_as<_Ty, _As> || ...);
843e20fa8bSPatrick Williams 
853e20fa8bSPatrick Williams template <class _Ty, class... _Us>
863e20fa8bSPatrick Williams concept __all_of = (__same_as<_Ty, _Us> && ...);
873e20fa8bSPatrick Williams 
883e20fa8bSPatrick Williams template <class _Ty, class... _Us>
893e20fa8bSPatrick Williams concept __none_of = ((!__same_as<_Ty, _Us>) && ...);
903e20fa8bSPatrick Williams 
913e20fa8bSPatrick Williams template <class, template <class...> class>
923e20fa8bSPatrick Williams constexpr bool __is_instance_of_ = false;
933e20fa8bSPatrick Williams template <class... _As, template <class...> class _Ty>
943e20fa8bSPatrick Williams constexpr bool __is_instance_of_<_Ty<_As...>, _Ty> = true;
953e20fa8bSPatrick Williams 
963e20fa8bSPatrick Williams template <class _Ay, template <class...> class _Ty>
973e20fa8bSPatrick Williams concept __is_instance_of = __is_instance_of_<_Ay, _Ty>;
983e20fa8bSPatrick Williams 
993e20fa8bSPatrick Williams template <class _Ay, template <class...> class _Ty>
1003e20fa8bSPatrick Williams concept __is_not_instance_of = !__is_instance_of<_Ay, _Ty>;
1015cee9157SPatrick Williams } // namespace stdexec
1023e20fa8bSPatrick Williams 
1035cee9157SPatrick Williams namespace stdexec::__std_concepts
1045cee9157SPatrick Williams {
1055cee9157SPatrick Williams // Make sure we're using a same_as concept that doesn't instantiate std::is_same
1065cee9157SPatrick Williams template <class _Ap, class _Bp>
1075cee9157SPatrick Williams concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>;
1085cee9157SPatrick Williams 
1095cee9157SPatrick Williams #if STDEXEC_HAS_STD_CONCEPTS_HEADER()
1105cee9157SPatrick Williams 
1115cee9157SPatrick Williams using std::convertible_to;
1125cee9157SPatrick Williams using std::derived_from;
1135cee9157SPatrick Williams using std::equality_comparable;
1145cee9157SPatrick Williams using std::integral;
1155cee9157SPatrick Williams 
1165cee9157SPatrick Williams #else
1175cee9157SPatrick Williams 
1185cee9157SPatrick Williams template <class T>
1195cee9157SPatrick Williams concept integral = std::is_integral_v<T>;
1205cee9157SPatrick Williams 
1215cee9157SPatrick Williams template <class _Ap, class _Bp>
1225cee9157SPatrick Williams concept derived_from =              //
1235cee9157SPatrick Williams     STDEXEC_IS_BASE_OF(_Bp, _Ap) && //
1245cee9157SPatrick Williams     STDEXEC_IS_CONVERTIBLE_TO(const volatile _Ap*, const volatile _Bp*);
1255cee9157SPatrick Williams 
1265cee9157SPatrick Williams template <class _From, class _To>
1275cee9157SPatrick Williams concept convertible_to =                     //
1285cee9157SPatrick Williams     STDEXEC_IS_CONVERTIBLE_TO(_From, _To) && //
1295cee9157SPatrick Williams     requires(_From (&__fun)()) { static_cast<_To>(__fun()); };
1305cee9157SPatrick Williams 
1315cee9157SPatrick Williams template <class _Ty>
1325cee9157SPatrick Williams concept equality_comparable = //
1335cee9157SPatrick Williams     requires(__cref_t<_Ty> __t) {
134*06f265f6SPatrick Williams         { __t == __t } -> convertible_to<bool>;
135*06f265f6SPatrick Williams         { __t != __t } -> convertible_to<bool>;
1365cee9157SPatrick Williams     };
1375cee9157SPatrick Williams #endif
1385cee9157SPatrick Williams } // namespace stdexec::__std_concepts
1395cee9157SPatrick Williams 
1405cee9157SPatrick Williams namespace stdexec
1415cee9157SPatrick Williams {
1425cee9157SPatrick Williams using namespace __std_concepts;
1435cee9157SPatrick Williams 
1445cee9157SPatrick Williams // Avoid using libstdc++'s object concepts because they instantiate a
1455cee9157SPatrick Williams // lot of templates.
1465cee9157SPatrick Williams #if STDEXEC_HAS_BUILTIN(__is_nothrow_destructible) || STDEXEC_MSVC()
1475cee9157SPatrick Williams template <class _Ty>
1485cee9157SPatrick Williams concept destructible = __is_nothrow_destructible(_Ty);
1495cee9157SPatrick Williams #else
1505cee9157SPatrick Williams template <class _Ty>
1515cee9157SPatrick Williams inline constexpr bool __destructible_ = //
1525cee9157SPatrick Williams     requires(_Ty && (&__fn)() noexcept) {
153*06f265f6SPatrick Williams         { __fn().~_Ty() } noexcept;
1545cee9157SPatrick Williams     };
1555cee9157SPatrick Williams template <class _Ty>
1565cee9157SPatrick Williams inline constexpr bool __destructible_<_Ty&> = true;
1575cee9157SPatrick Williams template <class _Ty>
1585cee9157SPatrick Williams inline constexpr bool __destructible_<_Ty&&> = true;
1595cee9157SPatrick Williams template <class _Ty, std::size_t _Np>
1605cee9157SPatrick Williams inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>;
1615cee9157SPatrick Williams 
1625cee9157SPatrick Williams template <class T>
1635cee9157SPatrick Williams concept destructible = __destructible_<T>;
1645cee9157SPatrick Williams #endif
1655cee9157SPatrick Williams 
1665cee9157SPatrick Williams template <class _Ty, class... _As>
1675cee9157SPatrick Williams concept constructible_from = //
1685cee9157SPatrick Williams     destructible<_Ty> &&     //
1695cee9157SPatrick Williams     STDEXEC_IS_CONSTRUCTIBLE(_Ty, _As...);
1705cee9157SPatrick Williams 
1715cee9157SPatrick Williams template <class _Ty>
1725cee9157SPatrick Williams concept default_initializable = //
1735cee9157SPatrick Williams     constructible_from<_Ty> &&  //
1745cee9157SPatrick Williams     requires { _Ty{}; } &&      //
1755cee9157SPatrick Williams     requires { ::new _Ty; };
1765cee9157SPatrick Williams 
1775cee9157SPatrick Williams template <class _Ty>
1785cee9157SPatrick Williams concept move_constructible = //
1795cee9157SPatrick Williams     constructible_from<_Ty, _Ty>;
1805cee9157SPatrick Williams 
1815cee9157SPatrick Williams template <class _Ty>
1825cee9157SPatrick Williams concept copy_constructible = //
1835cee9157SPatrick Williams     move_constructible<_Ty>  //
1845cee9157SPatrick Williams     && constructible_from<_Ty, const _Ty&>;
1855cee9157SPatrick Williams 
1865cee9157SPatrick Williams template <class _LHS, class _RHS>
1875cee9157SPatrick Williams concept assignable_from =   //
1885cee9157SPatrick Williams     same_as<_LHS, _LHS&> && //
1895cee9157SPatrick Williams     // std::common_reference_with<
1905cee9157SPatrick Williams     //   const std::remove_reference_t<_LHS>&,
1915cee9157SPatrick Williams     //   const std::remove_reference_t<_RHS>&> &&
1925cee9157SPatrick Williams     requires(_LHS __lhs, _RHS&& __rhs) {
193*06f265f6SPatrick Williams         { __lhs = static_cast<_RHS&&>(__rhs) } -> same_as<_LHS>;
1945cee9157SPatrick Williams     };
1955cee9157SPatrick Williams 
1965cee9157SPatrick Williams namespace __swap
1975cee9157SPatrick Williams {
1985cee9157SPatrick Williams using std::swap;
1995cee9157SPatrick Williams 
2005cee9157SPatrick Williams template <class _Ty, class _Uy>
2015cee9157SPatrick Williams concept swappable_with =             //
2025cee9157SPatrick Williams     requires(_Ty&& __t, _Uy&& __u) { //
2035cee9157SPatrick Williams         swap(static_cast<_Ty&&>(__t), static_cast<_Uy&&>(__u));
2045cee9157SPatrick Williams     };
2055cee9157SPatrick Williams 
2065cee9157SPatrick Williams inline constexpr const auto __fn =                               //
2075cee9157SPatrick Williams     []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) //
2085cee9157SPatrick Williams     noexcept(noexcept(swap(static_cast<_Ty&&>(__t), static_cast<_Uy&&>(__u)))) {
2095cee9157SPatrick Williams         swap(static_cast<_Ty&&>(__t), static_cast<_Uy&&>(__u));
2105cee9157SPatrick Williams     };
2115cee9157SPatrick Williams } // namespace __swap
2125cee9157SPatrick Williams 
2135cee9157SPatrick Williams using __swap::swappable_with;
2145cee9157SPatrick Williams inline constexpr const auto& swap = __swap::__fn;
2155cee9157SPatrick Williams 
2165cee9157SPatrick Williams template <class _Ty>
2175cee9157SPatrick Williams concept swappable = //
2185cee9157SPatrick Williams     requires(_Ty& a, _Ty& b) { swap(a, b); };
2195cee9157SPatrick Williams 
2205cee9157SPatrick Williams template <class _Ty>
2215cee9157SPatrick Williams concept movable =                 //
2225cee9157SPatrick Williams     std::is_object_v<_Ty> &&      //
2235cee9157SPatrick Williams     move_constructible<_Ty> &&    //
2245cee9157SPatrick Williams     assignable_from<_Ty&, _Ty> && //
2255cee9157SPatrick Williams     swappable<_Ty>;
2265cee9157SPatrick Williams 
2275cee9157SPatrick Williams template <class _Ty>
2285cee9157SPatrick Williams concept copyable =                       //
2295cee9157SPatrick Williams     copy_constructible<_Ty> &&           //
2305cee9157SPatrick Williams     movable<_Ty> &&                      //
2315cee9157SPatrick Williams     assignable_from<_Ty&, _Ty&> &&       //
2325cee9157SPatrick Williams     assignable_from<_Ty&, const _Ty&> && //
2335cee9157SPatrick Williams     assignable_from<_Ty&, const _Ty>;
2345cee9157SPatrick Williams 
2355cee9157SPatrick Williams template <class _Ty>
2365cee9157SPatrick Williams concept semiregular = //
2375cee9157SPatrick Williams     copyable<_Ty> &&  //
2385cee9157SPatrick Williams     default_initializable<_Ty>;
2395cee9157SPatrick Williams 
2405cee9157SPatrick Williams template <class _Ty>
2415cee9157SPatrick Williams concept regular =       //
2425cee9157SPatrick Williams     semiregular<_Ty> && //
2435cee9157SPatrick Williams     equality_comparable<_Ty>;
2445cee9157SPatrick Williams 
2455cee9157SPatrick Williams // Not exactly right, but close.
2465cee9157SPatrick Williams template <class _Ty>
2475cee9157SPatrick Williams concept __boolean_testable_ = convertible_to<_Ty, bool>;
2485cee9157SPatrick Williams 
2495cee9157SPatrick Williams template <class T, class U>
2505cee9157SPatrick Williams concept __partially_ordered_with = //
2515cee9157SPatrick Williams     requires(__cref_t<T> t, __cref_t<U> u) {
252*06f265f6SPatrick Williams         { t < u } -> __boolean_testable_;
253*06f265f6SPatrick Williams         { t > u } -> __boolean_testable_;
254*06f265f6SPatrick Williams         { t <= u } -> __boolean_testable_;
255*06f265f6SPatrick Williams         { t >= u } -> __boolean_testable_;
256*06f265f6SPatrick Williams         { u < t } -> __boolean_testable_;
257*06f265f6SPatrick Williams         { u > t } -> __boolean_testable_;
258*06f265f6SPatrick Williams         { u <= t } -> __boolean_testable_;
259*06f265f6SPatrick Williams         { u >= t } -> __boolean_testable_;
2605cee9157SPatrick Williams     };
2615cee9157SPatrick Williams 
2625cee9157SPatrick Williams template <class _Ty>
2635cee9157SPatrick Williams concept totally_ordered =       //
2645cee9157SPatrick Williams     equality_comparable<_Ty> && //
2655cee9157SPatrick Williams     __partially_ordered_with<_Ty, _Ty>;
2665cee9157SPatrick Williams 
2675cee9157SPatrick Williams template <class _Ty>
2685cee9157SPatrick Williams concept __movable_value =                 //
2695cee9157SPatrick Williams     move_constructible<__decay_t<_Ty>> && //
2705cee9157SPatrick Williams     constructible_from<__decay_t<_Ty>, _Ty>;
2715cee9157SPatrick Williams 
2725cee9157SPatrick Williams template <class _Ty>
2735cee9157SPatrick Williams concept __nothrow_movable_value = //
2745cee9157SPatrick Williams     __movable_value<_Ty> &&       //
2755cee9157SPatrick Williams     requires(_Ty&& __t) {
276*06f265f6SPatrick Williams         { __decay_t<_Ty>{__decay_t<_Ty>{static_cast<_Ty&&>(__t)}} } noexcept;
2775cee9157SPatrick Williams     };
2785cee9157SPatrick Williams 
2795cee9157SPatrick Williams template <class _Ty, class... _As>
2805cee9157SPatrick Williams concept __nothrow_constructible_from =
2815cee9157SPatrick Williams     constructible_from<_Ty, _As...> &&
2825cee9157SPatrick Williams     STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(_Ty, _As...);
2835cee9157SPatrick Williams 
2845cee9157SPatrick Williams template <class _Ty>
2855cee9157SPatrick Williams concept __nothrow_move_constructible = __nothrow_constructible_from<_Ty, _Ty>;
2865cee9157SPatrick Williams 
2875cee9157SPatrick Williams template <class _Ty>
2885cee9157SPatrick Williams concept __nothrow_copy_constructible =
2895cee9157SPatrick Williams     __nothrow_constructible_from<_Ty, const _Ty&>;
2905cee9157SPatrick Williams 
2915cee9157SPatrick Williams template <class... _Ts>
2925cee9157SPatrick Williams concept __decay_copyable = (constructible_from<__decay_t<_Ts>, _Ts> && ...);
2935cee9157SPatrick Williams 
2945cee9157SPatrick Williams template <class... _Ts>
2955cee9157SPatrick Williams concept __nothrow_decay_copyable =
2965cee9157SPatrick Williams     (__nothrow_constructible_from<__decay_t<_Ts>, _Ts> && ...);
2975cee9157SPatrick Williams 
2985cee9157SPatrick Williams template <class _Ty, class _Up>
2995cee9157SPatrick Williams concept __decays_to_derived_from = derived_from<__decay_t<_Ty>, _Up>;
3003e20fa8bSPatrick Williams } // namespace stdexec
301