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 #error This library requires the use of C++20. 20 #endif 21 22 #if __has_include(<version>) 23 #include <version> 24 #else 25 #include <ciso646> // For stdlib feature-test macros when <version> is not available 26 #endif 27 28 #include <cassert> 29 #include <version> 30 31 #define STDEXEC_STRINGIZE(_ARG) #_ARG 32 33 #define STDEXEC_CAT_(_XP, ...) _XP##__VA_ARGS__ 34 #define STDEXEC_CAT(_XP, ...) STDEXEC_CAT_(_XP, __VA_ARGS__) 35 36 #define STDEXEC_EXPAND(...) __VA_ARGS__ 37 #define STDEXEC_EVAL(_MACRO, ...) _MACRO(__VA_ARGS__) 38 #define STDEXEC_EAT(...) 39 40 #define STDEXEC_NOT(_XP) STDEXEC_CAT(STDEXEC_NOT_, _XP) 41 #define STDEXEC_NOT_0 1 42 #define STDEXEC_NOT_1 0 43 44 #define STDEXEC_IIF_0(_YP, ...) __VA_ARGS__ 45 #define STDEXEC_IIF_1(_YP, ...) _YP 46 #define STDEXEC_IIF(_XP, _YP, ...) \ 47 STDEXEC_EVAL(STDEXEC_CAT(STDEXEC_IIF_, _XP), _YP, __VA_ARGS__) 48 49 #define STDEXEC_COUNT(...) \ 50 STDEXEC_EXPAND(STDEXEC_COUNT_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)) 51 #define STDEXEC_COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _NP, ...) _NP 52 53 #define STDEXEC_CHECK(...) STDEXEC_EXPAND(STDEXEC_CHECK_(__VA_ARGS__, 0, )) 54 #define STDEXEC_CHECK_(_XP, _NP, ...) _NP 55 #define STDEXEC_PROBE(...) STDEXEC_PROBE_(__VA_ARGS__, 1) 56 #define STDEXEC_PROBE_(_XP, _NP, ...) _XP, _NP, 57 58 //////////////////////////////////////////////////////////////////////////////// 59 // STDEXEC_FOR_EACH 60 // Inspired by "Recursive macros with C++20 __VA_OPT__", by David Mazières 61 // https://www.scs.stanford.edu/~dm/blog/va-opt.html 62 #define STDEXEC_EXPAND_R(...) \ 63 STDEXEC_EXPAND_R1( \ 64 STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(__VA_ARGS__)))) \ 65 /**/ 66 #define STDEXEC_EXPAND_R1(...) \ 67 STDEXEC_EXPAND_R2( \ 68 STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(__VA_ARGS__)))) \ 69 /**/ 70 #define STDEXEC_EXPAND_R2(...) \ 71 STDEXEC_EXPAND_R3( \ 72 STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(__VA_ARGS__)))) \ 73 /**/ 74 #define STDEXEC_EXPAND_R3(...) \ 75 STDEXEC_EXPAND( \ 76 STDEXEC_EXPAND(STDEXEC_EXPAND(STDEXEC_EXPAND(__VA_ARGS__)))) \ 77 /**/ 78 79 #define STDEXEC_PARENS () 80 #define STDEXEC_FOR_EACH(_MACRO, ...) \ 81 __VA_OPT__(STDEXEC_EXPAND_R(STDEXEC_FOR_EACH_HELPER(_MACRO, __VA_ARGS__))) \ 82 /**/ 83 #define STDEXEC_FOR_EACH_HELPER(_MACRO, _A1, ...) \ 84 _MACRO(_A1) \ 85 __VA_OPT__(STDEXEC_FOR_EACH_AGAIN STDEXEC_PARENS(_MACRO, __VA_ARGS__)) /**/ 86 #define STDEXEC_FOR_EACH_AGAIN() STDEXEC_FOR_EACH_HELPER 87 //////////////////////////////////////////////////////////////////////////////////////////////////// 88 89 // If tail is non-empty, expand to the tail. Otherwise, expand to the head 90 #define STDEXEC_HEAD_OR_TAIL(_XP, ...) \ 91 STDEXEC_EXPAND __VA_OPT__((__VA_ARGS__)STDEXEC_EAT)(_XP) 92 93 // If tail is non-empty, expand to nothing. Otherwise, expand to the head 94 #define STDEXEC_HEAD_OR_NULL(_XP, ...) \ 95 STDEXEC_EXPAND __VA_OPT__(() STDEXEC_EAT)(_XP) 96 97 // When used with no arguments, these macros expand to 1 if the current 98 // compiler corresponds to the macro name; 0, otherwise. When used with 99 // arguments, they expand to the arguments if if the current compiler 100 // corresponds to the macro name; nothing, otherwise. 101 #if defined(__NVCC__) 102 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 103 #elif defined(__NVCOMPILER) 104 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 105 #elif defined(__EDG__) 106 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 107 #elif defined(__clang__) 108 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 109 #if defined(_MSC_VER) 110 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 111 #endif 112 #elif defined(__GNUC__) 113 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 114 #elif defined(_MSC_VER) 115 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 116 #endif 117 118 #ifndef STDEXEC_NVCC 119 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 120 #endif 121 #ifndef STDEXEC_NVHPC 122 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 123 #endif 124 #ifndef STDEXEC_EDG 125 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 126 #endif 127 #ifndef STDEXEC_CLANG 128 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 129 #endif 130 #ifndef STDEXEC_CLANG_CL 131 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 132 #endif 133 #ifndef STDEXEC_GCC 134 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 135 #endif 136 #ifndef STDEXEC_MSVC 137 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 138 #endif 139 140 //////////////////////////////////////////////////////////////////////////////////////////////////// 141 #ifdef __CUDACC__ 142 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 143 #else 144 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 145 #endif 146 147 //////////////////////////////////////////////////////////////////////////////////////////////////// 148 // For portably declaring attributes on functions and types 149 // Usage: 150 // 151 // STDEXEC_ATTRIBUTE((attr1, attr2, ...)) 152 // void foo() { ... } 153 #define STDEXEC_ATTRIBUTE(_XP) \ 154 STDEXEC_FOR_EACH(STDEXEC_ATTR, STDEXEC_EXPAND _XP) 155 #define STDEXEC_ATTR(_ATTR) \ 156 STDEXEC_CAT(STDEXEC_ATTR_WHICH_, \ 157 STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_ATTR_, _ATTR))) \ 158 (_ATTR) 159 160 // unknown attributes are treated like C++-style attributes 161 #define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]] 162 163 // custom handling for specific attribute types 164 #ifdef __CUDACC__ 165 #define STDEXEC_ATTR_WHICH_1(_ATTR) __host__ 166 #else 167 #define STDEXEC_ATTR_WHICH_1(_ATTR) 168 #endif 169 #define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1) 170 #define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1) 171 172 #ifdef __CUDACC__ 173 #define STDEXEC_ATTR_WHICH_2(_ATTR) __device__ 174 #else 175 #define STDEXEC_ATTR_WHICH_2(_ATTR) 176 #endif 177 #define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2) 178 #define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2) 179 180 #if STDEXEC_NVHPC() 181 // NVBUG #4067067: NVHPC does not fully support [[no_unique_address]] 182 #define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/ 183 #elif STDEXEC_MSVC() 184 // MSVCBUG 185 // https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874 186 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]] 187 #elif STDEXEC_CLANG_CL() 188 // clang-cl does not support: https://reviews.llvm.org/D110485 189 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]] 190 #else 191 #define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]] 192 #endif 193 #define STDEXEC_ATTR_no_unique_address STDEXEC_PROBE(~, 3) 194 195 #if STDEXEC_MSVC() 196 #define STDEXEC_ATTR_WHICH_4(_ATTR) __forceinline 197 #elif STDEXEC_CLANG() 198 #define STDEXEC_ATTR_WHICH_4(_ATTR) \ 199 __attribute__((__always_inline__, __artificial__, __nodebug__)) inline 200 #elif defined(__GNUC__) 201 #define STDEXEC_ATTR_WHICH_4(_ATTR) \ 202 __attribute__((__always_inline__, __artificial__)) inline 203 #else 204 #define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/ 205 #endif 206 #define STDEXEC_ATTR_always_inline STDEXEC_PROBE(~, 4) 207 208 //////////////////////////////////////////////////////////////////////////////////////////////////// 209 // warning push/pop portability macros 210 #if STDEXEC_NVCC() 211 #define STDEXEC_PRAGMA_PUSH() _Pragma("nv_diagnostic push") 212 #define STDEXEC_PRAGMA_POP() _Pragma("nv_diagnostic pop") 213 #define STDEXEC_PRAGMA_IGNORE_EDG(...) \ 214 _Pragma(STDEXEC_STRINGIZE(nv_diag_suppress __VA_ARGS__)) 215 #elif STDEXEC_NVHPC() || STDEXEC_EDG() 216 #define STDEXEC_PRAGMA_PUSH() \ 217 _Pragma("diagnostic push") STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_number) 218 #define STDEXEC_PRAGMA_POP() _Pragma("diagnostic pop") 219 #define STDEXEC_PRAGMA_IGNORE_EDG(...) \ 220 _Pragma(STDEXEC_STRINGIZE(diag_suppress __VA_ARGS__)) 221 #elif STDEXEC_CLANG() || STDEXEC_GCC() 222 #define STDEXEC_PRAGMA_PUSH() \ 223 _Pragma("GCC diagnostic push") STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas") \ 224 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-pragmas") \ 225 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option") \ 226 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-attributes") \ 227 STDEXEC_PRAGMA_IGNORE_GNU("-Wattributes") 228 #define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop") 229 #define STDEXEC_PRAGMA_IGNORE_GNU(...) \ 230 _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __VA_ARGS__)) 231 #else 232 #define STDEXEC_PRAGMA_PUSH() 233 #define STDEXEC_PRAGMA_POP() 234 #endif 235 236 #ifndef STDEXEC_PRAGMA_IGNORE_GNU 237 #define STDEXEC_PRAGMA_IGNORE_GNU(...) 238 #endif 239 #ifndef STDEXEC_PRAGMA_IGNORE_EDG 240 #define STDEXEC_PRAGMA_IGNORE_EDG(...) 241 #endif 242 243 #if !STDEXEC_MSVC() && defined(__has_builtin) 244 #define STDEXEC_HAS_BUILTIN __has_builtin 245 #else 246 #define STDEXEC_HAS_BUILTIN(...) 0 247 #endif 248 249 #if !STDEXEC_MSVC() && defined(__has_feature) 250 #define STDEXEC_HAS_FEATURE __has_feature 251 #else 252 #define STDEXEC_HAS_FEATURE(...) 0 253 #endif 254 255 #if STDEXEC_HAS_BUILTIN(__is_trivially_copyable) || STDEXEC_MSVC() 256 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__) 257 #else 258 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) \ 259 std::is_trivially_copyable_v<__VA_ARGS__> 260 #endif 261 262 #if STDEXEC_HAS_BUILTIN(__is_base_of) || (_MSC_VER >= 1914) 263 #define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__) 264 #else 265 #define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__> 266 #endif 267 268 #if STDEXEC_HAS_BUILTIN(__is_convertible_to) || STDEXEC_MSVC() 269 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible_to(__VA_ARGS__) 270 #elif STDEXEC_HAS_BUILTIN(__is_convertible) 271 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible(__VA_ARGS__) 272 #else 273 #define STDEXEC_IS_CONVERTIBLE_TO(...) std::is_convertible_v<__VA_ARGS__> 274 #endif 275 276 #if STDEXEC_HAS_BUILTIN(__is_const) 277 #define STDEXEC_IS_CONST(...) __is_const(__VA_ARGS__) 278 #else 279 #define STDEXEC_IS_CONST(...) stdexec::__is_const<__VA_ARGS__> 280 #endif 281 282 #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L 283 #define STDEXEC_UNREACHABLE() std::unreachable() 284 #elif STDEXEC_HAS_BUILTIN(__builtin_unreachable) 285 #define STDEXEC_UNREACHABLE() __builtin_unreachable() 286 #elif STDEXEC_MSVC() 287 #define STDEXEC_UNREACHABLE(...) __assume(false) 288 #else 289 #define STDEXEC_UNREACHABLE(...) std::terminate() 290 #endif 291 292 // Before gcc-12, gcc really didn't like tuples or variants of immovable types 293 #if STDEXEC_GCC() && (__GNUC__ < 12) 294 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) 295 #else 296 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete 297 #endif 298 299 // BUG (gcc PR93711): copy elision fails when initializing a 300 // [[no_unique_address]] field from a function returning an object 301 // of class type by value 302 #if STDEXEC_GCC() 303 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS 304 #else 305 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS \ 306 STDEXEC_ATTRIBUTE((no_unique_address)) 307 #endif 308 309 #if STDEXEC_NVHPC() 310 #include <nv/target> 311 #define STDEXEC_TERMINATE() \ 312 NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (__trap();)) void() 313 #elif STDEXEC_CLANG() && STDEXEC_CUDA() && defined(__CUDA_ARCH__) 314 #define STDEXEC_TERMINATE() \ 315 __trap(); \ 316 __builtin_unreachable() 317 #else 318 #define STDEXEC_TERMINATE() std::terminate() 319 #endif 320 321 #if STDEXEC_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) 322 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 323 #else 324 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 325 #endif 326 327 // Before clang-16, clang did not like libstdc++'s ranges implementation 328 #if __has_include(<ranges>) && \ 329 (defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L) && \ 330 (!STDEXEC_CLANG() || __clang_major__ >= 16 || defined(_LIBCPP_VERSION)) 331 #define STDEXEC_HAS_STD_RANGES() 1 332 #else 333 #define STDEXEC_HAS_STD_RANGES() 0 334 #endif 335 336 #if __has_include(<memory_resource>) && \ 337 (defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L) 338 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 1 339 #else 340 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 0 341 #endif 342 343 #ifdef STDEXEC_ASSERT 344 #error \ 345 "Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead." 346 #endif 347 348 #define STDEXEC_ASSERT(_XP) \ 349 do \ 350 { \ 351 static_assert(noexcept(_XP)); \ 352 STDEXEC_ASSERT_FN(_XP); \ 353 } while (false) 354 355 #ifndef STDEXEC_ASSERT_FN 356 #define STDEXEC_ASSERT_FN assert 357 #endif 358 359 #define STDEXEC_AUTO_RETURN(...) \ 360 noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) \ 361 { \ 362 return __VA_ARGS__; \ 363 } 364 365 // GCC 13 implements lexical friendship, but it is incomplete. See 366 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018 367 #if STDEXEC_CLANG() // || (STDEXEC_GCC() && __GNUC__ >= 13) 368 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1 369 #else 370 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0 371 #endif 372 373 #if defined(__cpp_explicit_this_parameter) && \ 374 (__cpp_explicit_this_parameter >= 202110) 375 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__) 376 #else 377 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__) 378 #endif 379 380 #if STDEXEC_EXPLICIT_THIS() 381 #define STDEXEC_DEFINE_EXPLICIT_THIS_MEMFN(...) __VA_ARGS__ 382 #define STDEXEC_CALL_EXPLICIT_THIS_MEMFN(_OBJ, _NAME) (_OBJ)._NAME( STDEXEC_CALL_EXPLICIT_THIS_MEMFN_DETAIL 383 #define STDEXEC_CALL_EXPLICIT_THIS_MEMFN_DETAIL(...) __VA_ARGS__ ) 384 #else 385 #define STDEXEC_DEFINE_EXPLICIT_THIS_MEMFN(...) static __VA_ARGS__(STDEXEC_FUN_ARGS 386 #define STDEXEC_CALL_EXPLICIT_THIS_MEMFN(_OBJ, _NAME) (_OBJ)._NAME((_OBJ) STDEXEC_CALL_EXPLICIT_THIS_MEMFN_DETAIL 387 #define STDEXEC_CALL_EXPLICIT_THIS_MEMFN_DETAIL(...) __VA_OPT__(, ) __VA_ARGS__) 388 #define STDEXEC_EAT_THIS_DETAIL_this 389 #define STDEXEC_FUN_ARGS(...) STDEXEC_CAT(STDEXEC_EAT_THIS_DETAIL_, __VA_ARGS__)) 390 #endif 391 392 // Configure extra type checking 393 #define STDEXEC_TYPE_CHECKING_ZERO() 0 394 #define STDEXEC_TYPE_CHECKING_ONE() 1 395 #define STDEXEC_TYPE_CHECKING_TWO() 2 396 397 #define STDEXEC_PROBE_TYPE_CHECKING_ STDEXEC_TYPE_CHECKING_ONE 398 #define STDEXEC_PROBE_TYPE_CHECKING_0 STDEXEC_TYPE_CHECKING_ZERO 399 #define STDEXEC_PROBE_TYPE_CHECKING_1 STDEXEC_TYPE_CHECKING_ONE 400 #define STDEXEC_PROBE_TYPE_CHECKING_STDEXEC_ENABLE_EXTRA_TYPE_CHECKING \ 401 STDEXEC_TYPE_CHECKING_TWO 402 403 #define STDEXEC_TYPE_CHECKING_WHICH3(...) \ 404 STDEXEC_PROBE_TYPE_CHECKING_##__VA_ARGS__ 405 #define STDEXEC_TYPE_CHECKING_WHICH2(...) \ 406 STDEXEC_TYPE_CHECKING_WHICH3(__VA_ARGS__) 407 #define STDEXEC_TYPE_CHECKING_WHICH \ 408 STDEXEC_TYPE_CHECKING_WHICH2(STDEXEC_ENABLE_EXTRA_TYPE_CHECKING) 409 410 #ifndef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 411 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0 412 #elif STDEXEC_TYPE_CHECKING_WHICH() == 2 413 // do nothing 414 #elif STDEXEC_TYPE_CHECKING_WHICH() == 0 415 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 416 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0 417 #else 418 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 419 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 1 420 #endif 421 422 namespace stdexec 423 {} 424