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