1 /* 2 * Copyright (c) 2022 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 __cplusplus < 202002L 19 #if defined(_MSC_VER) && !defined(__clang__) 20 # error This library requires the use of C++20. Use /Zc:__cplusplus to enable __cplusplus conformance. 21 #else 22 #error This library requires the use of C++20. 23 #endif 24 #endif 25 26 #if defined(_MSC_VER) && !defined(__clang__) && \ 27 (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) 28 # error This library requires the use of the new conforming preprocessor enabled by /Zc:preprocessor. 29 #endif 30 31 #if __has_include(<version>) 32 #include <version> 33 #else 34 #include <ciso646> // For stdlib feature-test macros when <version> is not available 35 #endif 36 37 #include <cassert> 38 #include <type_traits> 39 40 #define STDEXEC_STRINGIZE(_ARG) #_ARG 41 42 #define STDEXEC_CAT_(_XP, ...) _XP##__VA_ARGS__ 43 #define STDEXEC_CAT(_XP, ...) STDEXEC_CAT_(_XP, __VA_ARGS__) 44 45 #define STDEXEC_EXPAND(...) __VA_ARGS__ 46 #define STDEXEC_EVAL(_MACRO, ...) _MACRO(__VA_ARGS__) 47 #define STDEXEC_EAT(...) 48 49 #define STDEXEC_IIF(_XP, _YP, ...) \ 50 STDEXEC_IIF_EVAL(STDEXEC_CAT(STDEXEC_IIF_, _XP), _YP, __VA_ARGS__) 51 #define STDEXEC_IIF_0(_YP, ...) __VA_ARGS__ 52 #define STDEXEC_IIF_1(_YP, ...) _YP 53 #define STDEXEC_IIF_EVAL(_MACRO, ...) _MACRO(__VA_ARGS__) 54 55 #define STDEXEC_COMPL(_B) STDEXEC_COMPL_CAT(STDEXEC_COMPL_, _B) 56 #define STDEXEC_COMPL_0 1 57 #define STDEXEC_COMPL_1 0 58 #define STDEXEC_COMPL_CAT(_XP, ...) _XP##__VA_ARGS__ 59 60 #define STDEXEC_COUNT(...) \ 61 STDEXEC_EXPAND(STDEXEC_COUNT_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)) 62 #define STDEXEC_COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _NP, ...) _NP 63 64 #define STDEXEC_CHECK(...) STDEXEC_EXPAND(STDEXEC_CHECK_(__VA_ARGS__, 0, )) 65 #define STDEXEC_CHECK_(_XP, _NP, ...) _NP 66 #define STDEXEC_PROBE(...) STDEXEC_PROBE_(__VA_ARGS__, 1) 67 #define STDEXEC_PROBE_(_XP, _NP, ...) _XP, _NP, 68 69 #define STDEXEC_NOT(_XP) STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_NOT_, _XP)) 70 #define STDEXEC_NOT_0 STDEXEC_PROBE(~, 1) 71 72 #define STDEXEC_BOOL(_XP) STDEXEC_COMPL(STDEXEC_NOT(_XP)) 73 #define STDEXEC_IF(_XP, _YP, ...) \ 74 STDEXEC_IIF(STDEXEC_BOOL(_XP), _YP, __VA_ARGS__) 75 76 #define STDEXEC_WHEN(_XP, ...) \ 77 STDEXEC_IF(_XP, STDEXEC_EXPAND, STDEXEC_EAT)(__VA_ARGS__) 78 79 //////////////////////////////////////////////////////////////////////////////// 80 // STDEXEC_FOR_EACH 81 // Inspired by "Recursive macros with C++20 __VA_OPT__", by David Mazières 82 // https://www.scs.stanford.edu/~dm/blog/va-opt.html 83 #define STDEXEC_EXPAND_R(...) \ 84 STDEXEC_EXPAND_R1( \ 85 STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(__VA_ARGS__)))) \ 86 /**/ 87 #define STDEXEC_EXPAND_R1(...) \ 88 STDEXEC_EXPAND_R2( \ 89 STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(__VA_ARGS__)))) \ 90 /**/ 91 #define STDEXEC_EXPAND_R2(...) \ 92 STDEXEC_EXPAND_R3( \ 93 STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(__VA_ARGS__)))) \ 94 /**/ 95 #define STDEXEC_EXPAND_R3(...) \ 96 STDEXEC_EXPAND( \ 97 STDEXEC_EXPAND(STDEXEC_EXPAND(STDEXEC_EXPAND(__VA_ARGS__)))) \ 98 /**/ 99 100 #define STDEXEC_PARENS () 101 #define STDEXEC_FOR_EACH(_MACRO, ...) \ 102 __VA_OPT__(STDEXEC_EXPAND_R(STDEXEC_FOR_EACH_HELPER(_MACRO, __VA_ARGS__))) \ 103 /**/ 104 #define STDEXEC_FOR_EACH_HELPER(_MACRO, _A1, ...) \ 105 _MACRO(_A1) \ 106 __VA_OPT__(STDEXEC_FOR_EACH_AGAIN STDEXEC_PARENS(_MACRO, __VA_ARGS__)) /**/ 107 #define STDEXEC_FOR_EACH_AGAIN() STDEXEC_FOR_EACH_HELPER 108 //////////////////////////////////////////////////////////////////////////////////////////////////// 109 110 #define STDEXEC_FRONT(...) __VA_OPT__(STDEXEC_FRONT_HELPER(__VA_ARGS__)) 111 #define STDEXEC_FRONT_HELPER(_A1, ...) _A1 112 #define STDEXEC_BACK(...) \ 113 __VA_OPT__(STDEXEC_EXPAND_R(STDEXEC_BACK_HELPER(__VA_ARGS__))) 114 #define STDEXEC_BACK_HELPER(_A1, ...) \ 115 STDEXEC_FRONT(__VA_OPT__(, ) _A1, ) \ 116 __VA_OPT__(STDEXEC_BACK_AGAIN STDEXEC_PARENS(__VA_ARGS__)) 117 #define STDEXEC_BACK_AGAIN() STDEXEC_BACK_HELPER 118 119 // If tail is non-empty, expand to the tail. Otherwise, expand to the head 120 #define STDEXEC_HEAD_OR_TAIL(_XP, ...) \ 121 STDEXEC_EXPAND __VA_OPT__((__VA_ARGS__)STDEXEC_EAT)(_XP) 122 123 // If tail is non-empty, expand to nothing. Otherwise, expand to the head 124 #define STDEXEC_HEAD_OR_NULL(_XP, ...) \ 125 STDEXEC_EXPAND __VA_OPT__(() STDEXEC_EAT)(_XP) 126 127 // When used with no arguments, these macros expand to 1 if the current 128 // compiler corresponds to the macro name; 0, otherwise. When used with 129 // arguments, they expand to the arguments if if the current compiler 130 // corresponds to the macro name; nothing, otherwise. 131 #if defined(__NVCC__) 132 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 133 #elif defined(__NVCOMPILER) 134 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 135 #elif defined(__EDG__) 136 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 137 #elif defined(__clang__) 138 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 139 #if defined(_MSC_VER) 140 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 141 #endif 142 #if defined(__apple_build_version__) 143 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 144 #endif 145 #elif defined(__GNUC__) 146 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 147 #elif defined(_MSC_VER) 148 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 149 #endif 150 151 #ifndef STDEXEC_NVCC 152 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 153 #endif 154 #ifndef STDEXEC_NVHPC 155 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 156 #endif 157 #ifndef STDEXEC_EDG 158 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 159 #endif 160 #ifndef STDEXEC_CLANG 161 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 162 #endif 163 #ifndef STDEXEC_CLANG_CL 164 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 165 #endif 166 #ifndef STDEXEC_APPLE_CLANG 167 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 168 #endif 169 #ifndef STDEXEC_GCC 170 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 171 #endif 172 #ifndef STDEXEC_MSVC 173 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 174 #endif 175 176 #if STDEXEC_NVHPC() 177 #define STDEXEC_NVHPC_VERSION() \ 178 (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__) 179 #endif 180 181 //////////////////////////////////////////////////////////////////////////////////////////////////// 182 #ifdef __CUDACC__ 183 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 184 #else 185 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 186 #endif 187 188 //////////////////////////////////////////////////////////////////////////////////////////////////// 189 #if __cpp_impl_coroutine >= 201902 && __cpp_lib_coroutine >= 201902 190 #include <coroutine> 191 #define STDEXEC_STD_NO_COROUTINES() 0 192 namespace __coro = std; 193 #elif defined(__cpp_coroutines) && __has_include(<experimental/coroutine>) 194 #include <experimental/coroutine> 195 #define STDEXEC_STD_NO_COROUTINES() 0 196 namespace __coro = std::experimental; 197 #else 198 #define STDEXEC_STD_NO_COROUTINES() 1 199 #endif 200 201 //////////////////////////////////////////////////////////////////////////////////////////////////// 202 // For portably declaring attributes on functions and types 203 // Usage: 204 // 205 // STDEXEC_ATTRIBUTE((attr1, attr2, ...)) 206 // void foo() { ... } 207 #define STDEXEC_ATTRIBUTE(_XP) \ 208 STDEXEC_FOR_EACH(STDEXEC_ATTR, STDEXEC_EXPAND _XP) 209 #define STDEXEC_ATTR(_ATTR) \ 210 STDEXEC_CAT(STDEXEC_ATTR_WHICH_, \ 211 STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_ATTR_, _ATTR))) \ 212 (_ATTR) 213 214 // unknown attributes are treated like C++-style attributes 215 #define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]] 216 217 // custom handling for specific attribute types 218 #ifdef __CUDACC__ 219 #define STDEXEC_ATTR_WHICH_1(_ATTR) __host__ 220 #else 221 #define STDEXEC_ATTR_WHICH_1(_ATTR) 222 #endif 223 #define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1) 224 #define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1) 225 226 #ifdef __CUDACC__ 227 #define STDEXEC_ATTR_WHICH_2(_ATTR) __device__ 228 #else 229 #define STDEXEC_ATTR_WHICH_2(_ATTR) 230 #endif 231 #define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2) 232 #define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2) 233 234 #if STDEXEC_NVHPC() 235 // NVBUG #4067067: NVHPC does not fully support [[no_unique_address]] 236 #define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/ 237 #elif STDEXEC_MSVC() 238 // MSVCBUG 239 // https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874 240 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]] 241 #elif STDEXEC_CLANG_CL() 242 // clang-cl does not support: https://reviews.llvm.org/D110485 243 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]] 244 #else 245 #define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]] 246 #endif 247 #define STDEXEC_ATTR_no_unique_address STDEXEC_PROBE(~, 3) 248 249 #if STDEXEC_MSVC() 250 #define STDEXEC_ATTR_WHICH_4(_ATTR) __forceinline 251 #elif STDEXEC_CLANG() 252 #define STDEXEC_ATTR_WHICH_4(_ATTR) \ 253 __attribute__((__always_inline__, __artificial__, __nodebug__)) inline 254 #elif defined(__GNUC__) 255 #define STDEXEC_ATTR_WHICH_4(_ATTR) \ 256 __attribute__((__always_inline__, __artificial__)) inline 257 #else 258 #define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/ 259 #endif 260 #define STDEXEC_ATTR_always_inline STDEXEC_PROBE(~, 4) 261 262 #if STDEXEC_CLANG() || STDEXEC_GCC() 263 #define STDEXEC_ATTR_WHICH_5(_ATTR) __attribute__((__weak__)) 264 #else 265 #define STDEXEC_ATTR_WHICH_5(_ATTR) /*nothing*/ 266 #endif 267 #define STDEXEC_ATTR_weak STDEXEC_PROBE(~, 5) 268 #define STDEXEC_ATTR___weak__ STDEXEC_PROBE(~, 5) 269 270 //////////////////////////////////////////////////////////////////////////////////////////////////// 271 // warning push/pop portability macros 272 #if STDEXEC_NVCC() 273 #define STDEXEC_PRAGMA_PUSH() _Pragma("nv_diagnostic push") 274 #define STDEXEC_PRAGMA_POP() _Pragma("nv_diagnostic pop") 275 #define STDEXEC_PRAGMA_IGNORE_EDG(...) \ 276 _Pragma(STDEXEC_STRINGIZE(nv_diag_suppress __VA_ARGS__)) 277 #elif STDEXEC_NVHPC() || STDEXEC_EDG() 278 #define STDEXEC_PRAGMA_PUSH() \ 279 _Pragma("diagnostic push") STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_number) 280 #define STDEXEC_PRAGMA_POP() _Pragma("diagnostic pop") 281 #define STDEXEC_PRAGMA_IGNORE_EDG(...) \ 282 _Pragma(STDEXEC_STRINGIZE(diag_suppress __VA_ARGS__)) 283 #elif STDEXEC_CLANG() || STDEXEC_GCC() 284 #define STDEXEC_PRAGMA_PUSH() \ 285 _Pragma("GCC diagnostic push") STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas") \ 286 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-pragmas") \ 287 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option") \ 288 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-attributes") \ 289 STDEXEC_PRAGMA_IGNORE_GNU("-Wattributes") 290 #define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop") 291 #define STDEXEC_PRAGMA_IGNORE_GNU(...) \ 292 _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __VA_ARGS__)) 293 #elif STDEXEC_MSVC() 294 #define STDEXEC_PRAGMA_PUSH() __pragma(warning(push)) 295 #define STDEXEC_PRAGMA_POP() __pragma(warning(pop)) 296 #define STDEXEC_PRAGMA_IGNORE_MSVC(...) __pragma(warning(disable : __VA_ARGS__)) 297 #else 298 #define STDEXEC_PRAGMA_PUSH() 299 #define STDEXEC_PRAGMA_POP() 300 #endif 301 302 #ifndef STDEXEC_PRAGMA_IGNORE_GNU 303 #define STDEXEC_PRAGMA_IGNORE_GNU(...) 304 #endif 305 #ifndef STDEXEC_PRAGMA_IGNORE_EDG 306 #define STDEXEC_PRAGMA_IGNORE_EDG(...) 307 #endif 308 #ifndef STDEXEC_PRAGMA_IGNORE_MSVC 309 #define STDEXEC_PRAGMA_IGNORE_MSVC(...) 310 #endif 311 312 #if !STDEXEC_MSVC() && defined(__has_builtin) 313 #define STDEXEC_HAS_BUILTIN __has_builtin 314 #else 315 #define STDEXEC_HAS_BUILTIN(...) 0 316 #endif 317 318 #if !STDEXEC_MSVC() && defined(__has_feature) 319 #define STDEXEC_HAS_FEATURE __has_feature 320 #else 321 #define STDEXEC_HAS_FEATURE(...) 0 322 #endif 323 324 #if STDEXEC_HAS_BUILTIN(__is_trivially_copyable) || STDEXEC_MSVC() 325 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__) 326 #else 327 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) \ 328 std::is_trivially_copyable_v<__VA_ARGS__> 329 #endif 330 331 #if STDEXEC_HAS_BUILTIN(__is_base_of) || (_MSC_VER >= 1914) 332 #define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__) 333 #else 334 #define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__> 335 #endif 336 337 #if STDEXEC_HAS_BUILTIN(__is_convertible_to) || STDEXEC_MSVC() 338 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible_to(__VA_ARGS__) 339 #elif STDEXEC_HAS_BUILTIN(__is_convertible) 340 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible(__VA_ARGS__) 341 #else 342 #define STDEXEC_IS_CONVERTIBLE_TO(...) std::is_convertible_v<__VA_ARGS__> 343 #endif 344 345 #if STDEXEC_HAS_BUILTIN(__is_const) 346 #define STDEXEC_IS_CONST(...) __is_const(__VA_ARGS__) 347 #else 348 #define STDEXEC_IS_CONST(...) stdexec::__is_const_<__VA_ARGS__> 349 #endif 350 351 #if STDEXEC_HAS_BUILTIN(__is_same) 352 #define STDEXEC_IS_SAME(...) __is_same(__VA_ARGS__) 353 #elif STDEXEC_HAS_BUILTIN(__is_same_as) 354 #define STDEXEC_IS_SAME(...) __is_same_as(__VA_ARGS__) 355 #elif STDEXEC_MSVC() 356 // msvc replaces std::is_same_v with a compile-time constant 357 #define STDEXEC_IS_SAME(...) std::is_same_v<__VA_ARGS__> 358 #else 359 #define STDEXEC_IS_SAME(...) stdexec::__same_as_v<__VA_ARGS__> 360 #endif 361 362 #if STDEXEC_HAS_BUILTIN(__is_constructible) || STDEXEC_MSVC() 363 #define STDEXEC_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__) 364 #else 365 #define STDEXEC_IS_CONSTRUCTIBLE(...) std::is_constructible_v<__VA_ARGS__> 366 #endif 367 368 #if STDEXEC_HAS_BUILTIN(__is_nothrow_constructible) || STDEXEC_MSVC() 369 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...) \ 370 __is_nothrow_constructible(__VA_ARGS__) 371 #else 372 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...) \ 373 std::is_nothrow_constructible_v<__VA_ARGS__> 374 #endif 375 376 #if STDEXEC_HAS_BUILTIN(__is_trivially_constructible) || STDEXEC_MSVC() 377 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...) \ 378 __is_trivially_constructible(__VA_ARGS__) 379 #else 380 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...) \ 381 std::is_trivially_constructible_v<__VA_ARGS__> 382 #endif 383 384 #if STDEXEC_HAS_BUILTIN(__is_empty) || STDEXEC_MSVC() 385 #define STDEXEC_IS_EMPTY(...) __is_empty(__VA_ARGS__) 386 #else 387 #define STDEXEC_IS_EMPTY(...) std::is_empty_v<__VA_ARGS__> 388 #endif 389 390 #if STDEXEC_HAS_BUILTIN(__remove_reference) 391 namespace stdexec 392 { 393 template <class Ty> 394 using _remove_reference_t = __remove_reference(Ty); 395 } // namespace stdexec 396 397 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__> 398 #elif STDEXEC_HAS_BUILTIN(__remove_reference_t) 399 namespace stdexec 400 { 401 template <class Ty> 402 using _remove_reference_t = __remove_reference_t(Ty); 403 } // namespace stdexec 404 405 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__> 406 #else 407 #define STDEXEC_REMOVE_REFERENCE(...) ::std::remove_reference_t<__VA_ARGS__> 408 #endif 409 410 namespace stdexec 411 { 412 template <class _Ap, class _Bp> 413 inline constexpr bool __same_as_v = false; 414 415 template <class _Ap> 416 inline constexpr bool __same_as_v<_Ap, _Ap> = true; 417 } // namespace stdexec 418 419 #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L 420 #define STDEXEC_UNREACHABLE() std::unreachable() 421 #elif STDEXEC_HAS_BUILTIN(__builtin_unreachable) 422 #define STDEXEC_UNREACHABLE() __builtin_unreachable() 423 #elif STDEXEC_MSVC() 424 #define STDEXEC_UNREACHABLE(...) __assume(false) 425 #else 426 #define STDEXEC_UNREACHABLE(...) std::terminate() 427 #endif 428 429 // Before gcc-12, gcc really didn't like tuples or variants of immovable types 430 #if STDEXEC_GCC() && (__GNUC__ < 12) 431 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) 432 #else 433 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete 434 #endif 435 436 // BUG (gcc PR93711): copy elision fails when initializing a 437 // [[no_unique_address]] field from a function returning an object 438 // of class type by value 439 #if STDEXEC_GCC() 440 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS 441 #else 442 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS \ 443 STDEXEC_ATTRIBUTE((no_unique_address)) 444 #endif 445 446 #if STDEXEC_NVHPC() 447 #include <nv/target> 448 #define STDEXEC_TERMINATE() \ 449 NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (__trap();)) void() 450 #elif STDEXEC_CLANG() && STDEXEC_CUDA() && defined(__CUDA_ARCH__) 451 #define STDEXEC_TERMINATE() \ 452 __trap(); \ 453 __builtin_unreachable() 454 #else 455 #define STDEXEC_TERMINATE() std::terminate() 456 #endif 457 458 #if STDEXEC_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) 459 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 460 #else 461 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 462 #endif 463 464 // Before clang-16, clang did not like libstdc++'s ranges implementation 465 #if __has_include(<ranges>) && \ 466 (defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L) && \ 467 (!STDEXEC_CLANG() || __clang_major__ >= 16 || defined(_LIBCPP_VERSION)) 468 #define STDEXEC_HAS_STD_RANGES() 1 469 #else 470 #define STDEXEC_HAS_STD_RANGES() 0 471 #endif 472 473 #if __has_include(<memory_resource>) && \ 474 (defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L) 475 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 1 476 #else 477 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 0 478 #endif 479 480 #ifdef STDEXEC_ASSERT 481 #error \ 482 "Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead." 483 #endif 484 485 #define STDEXEC_ASSERT(_XP) \ 486 do \ 487 { \ 488 static_assert(noexcept(_XP)); \ 489 STDEXEC_ASSERT_FN(_XP); \ 490 } while (false) 491 492 #ifndef STDEXEC_ASSERT_FN 493 #define STDEXEC_ASSERT_FN assert 494 #endif 495 496 #define STDEXEC_AUTO_RETURN(...) \ 497 noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) \ 498 { \ 499 return __VA_ARGS__; \ 500 } 501 502 // GCC 13 implements lexical friendship, but it is incomplete. See 503 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018 504 #if STDEXEC_CLANG() // || (STDEXEC_GCC() && __GNUC__ >= 13) 505 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1 506 #else 507 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0 508 #endif 509 510 #if defined(__cpp_explicit_this_parameter) && \ 511 (__cpp_explicit_this_parameter >= 202110) 512 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 513 #else 514 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 515 #endif 516 517 // Configure extra type checking 518 #define STDEXEC_TYPE_CHECKING_ZERO() 0 519 #define STDEXEC_TYPE_CHECKING_ONE() 1 520 #define STDEXEC_TYPE_CHECKING_TWO() 2 521 522 #define STDEXEC_PROBE_TYPE_CHECKING_ STDEXEC_TYPE_CHECKING_ONE 523 #define STDEXEC_PROBE_TYPE_CHECKING_0 STDEXEC_TYPE_CHECKING_ZERO 524 #define STDEXEC_PROBE_TYPE_CHECKING_1 STDEXEC_TYPE_CHECKING_ONE 525 #define STDEXEC_PROBE_TYPE_CHECKING_STDEXEC_ENABLE_EXTRA_TYPE_CHECKING \ 526 STDEXEC_TYPE_CHECKING_TWO 527 528 #define STDEXEC_TYPE_CHECKING_WHICH3(...) \ 529 STDEXEC_PROBE_TYPE_CHECKING_##__VA_ARGS__ 530 #define STDEXEC_TYPE_CHECKING_WHICH2(...) \ 531 STDEXEC_TYPE_CHECKING_WHICH3(__VA_ARGS__) 532 #define STDEXEC_TYPE_CHECKING_WHICH \ 533 STDEXEC_TYPE_CHECKING_WHICH2(STDEXEC_ENABLE_EXTRA_TYPE_CHECKING) 534 535 #ifndef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 536 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0 537 #elif STDEXEC_TYPE_CHECKING_WHICH() == 2 538 // do nothing 539 #elif STDEXEC_TYPE_CHECKING_WHICH() == 0 540 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 541 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0 542 #else 543 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 544 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 1 545 #endif 546 547 namespace stdexec 548 {} 549