diff --git a/libcudacxx/include/cuda/__argument/argument.h b/libcudacxx/include/cuda/__argument/argument.h index fb514d22648..1e3c3dca247 100644 --- a/libcudacxx/include/cuda/__argument/argument.h +++ b/libcudacxx/include/cuda/__argument/argument.h @@ -26,7 +26,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -75,23 +78,12 @@ template using __element_type_of_t = typename __element_type_of<::cuda::std::remove_cvref_t<_Tp>>::type; // ===================================================================== -// __is_sequence_v / __is_single_value_v +// __is_sequence_v // ===================================================================== template inline constexpr bool __is_sequence_v = - !::cuda::std::is_same_v<::cuda::std::remove_cvref_t<_Tp>, __element_type_of_t<_Tp>>; - -template -inline constexpr bool __is_single_value_v = !__is_sequence_v<_Tp>; - -template -inline constexpr bool __is_iterable_v = false; - -template -inline constexpr bool __is_iterable_v<_Tp, - ::cuda::std::void_t().begin()), - decltype(::cuda::std::declval().end())>> = true; + ::cuda::std::is_array_v<::cuda::std::remove_cvref_t<_Tp>> || ::cuda::std::ranges::range<_Tp>; // ===================================================================== // __constant @@ -121,7 +113,9 @@ struct __constant_sequence using value_type = ::cuda::std::remove_cvref_t; using __element_type = __element_type_of_t; - static_assert(__is_sequence_v, "constant sequence arguments must have a distinct element type"); + static_assert(__is_sequence_v, "The value type of __constant_sequence must be a range or an array"); + static_assert(!::cuda::std::ranges::__empty::__fn{}(_Value), + "The value type of __constant_sequence must be a non-empty sequence"); [[nodiscard]] _CCCL_API static constexpr value_type value() noexcept { @@ -129,130 +123,6 @@ struct __constant_sequence } }; -// ===================================================================== -// __assert_in_range -// ===================================================================== - -template -_CCCL_API constexpr void __assert_in_range([[maybe_unused]] _From __val) noexcept -{ - if constexpr (::cuda::std::__cccl_is_cv_integer_v<_To> && ::cuda::std::__cccl_is_cv_integer_v<_From>) - { - _CCCL_ASSERT(::cuda::std::in_range<::cuda::std::remove_cv_t<_To>>(__val), - "runtime bound value overflows the element type"); - } -} - -template -[[nodiscard]] _CCCL_API constexpr _To __runtime_bound_cast(_From __val) noexcept -{ - __assert_in_range<_To>(__val); - return static_cast<_To>(__val); -} - -template -_CCCL_API constexpr bool __static_bound_in_range() noexcept -{ - using _RawTo = ::cuda::std::remove_cv_t<_To>; - using _RawFrom = ::cuda::std::remove_cv_t; - - if constexpr (::cuda::std::__cccl_is_integer_v<_RawTo> && ::cuda::std::__cccl_is_integer_v<_RawFrom>) - { - return ::cuda::std::in_range<_RawTo>(_Value); - } - else if constexpr (::cuda::std::is_arithmetic_v<_RawTo> && ::cuda::std::is_arithmetic_v<_RawFrom>) - { - return static_cast<_RawFrom>(static_cast<_RawTo>(_Value)) == _Value; - } - else - { - return true; - } -} - -template -inline constexpr bool __valid_static_bounds_v = true; - -template -inline constexpr bool __valid_static_bounds_v<_ElementType, __static_bounds<_Lowest, _Highest>> = - __static_bound_in_range<_ElementType, _Lowest>() && __static_bound_in_range<_ElementType, _Highest>(); - -template -_CCCL_API constexpr _ElementType __wrapper_static_lowest() noexcept -{ - if constexpr (::cuda::std::is_same_v<_StaticBounds, __no_bounds>) - { - return ::cuda::std::numeric_limits<_ElementType>::lowest(); - } - else - { - return static_cast<_ElementType>(_StaticBounds::lower()); - } -} - -template -_CCCL_API constexpr _ElementType __wrapper_static_highest() noexcept -{ - if constexpr (::cuda::std::is_same_v<_StaticBounds, __no_bounds>) - { - return (::cuda::std::numeric_limits<_ElementType>::max)(); - } - else - { - return static_cast<_ElementType>(_StaticBounds::upper()); - } -} - -template -_CCCL_API constexpr _ElementType __effective_lowest(__runtime_bounds<_ElementType> __runtime_bounds) noexcept -{ - auto __static_lowest = __wrapper_static_lowest<_ElementType, _StaticBounds>(); - return __static_lowest > __runtime_bounds.lower() ? __static_lowest : __runtime_bounds.lower(); -} - -template -_CCCL_API constexpr _ElementType __effective_highest(__runtime_bounds<_ElementType> __runtime_bounds) noexcept -{ - auto __static_highest = __wrapper_static_highest<_ElementType, _StaticBounds>(); - return __static_highest < __runtime_bounds.upper() ? __static_highest : __runtime_bounds.upper(); -} - -template -_CCCL_API constexpr bool __has_bounds_intersection(__runtime_bounds<_ElementType> __runtime_bounds) noexcept -{ - return __effective_lowest<_ElementType, _StaticBounds>(__runtime_bounds) - <= __effective_highest<_ElementType, _StaticBounds>(__runtime_bounds); -} - -template -_CCCL_API constexpr void __validate_bounds_intersection(__runtime_bounds<_ElementType> __runtime_bounds) noexcept -{ - static_assert(__valid_static_bounds_v<_ElementType, _StaticBounds>, - "static argument bounds cannot be represented by the element type"); - _CCCL_VERIFY((__has_bounds_intersection<_ElementType, _StaticBounds>(__runtime_bounds)), - "static and runtime argument bounds do not intersect"); -} - -template -_CCCL_API constexpr void __validate_static_element_bounds([[maybe_unused]] const _ElementType& __val) noexcept -{ - if constexpr (!::cuda::std::is_same_v<_StaticBounds, __no_bounds>) - { - _CCCL_ASSERT((__val >= __wrapper_static_lowest<_ElementType, _StaticBounds>()), - "immediate argument value is below static lowest bound"); - _CCCL_ASSERT((__val <= __wrapper_static_highest<_ElementType, _StaticBounds>()), - "immediate argument value is above static highest bound"); - } -} - -template -_CCCL_API constexpr void __validate_runtime_element_bounds( - [[maybe_unused]] const _ElementType& __val, [[maybe_unused]] __runtime_bounds<_ElementType> __runtime_bounds) noexcept -{ - _CCCL_ASSERT((__val >= __runtime_bounds.lower()), "immediate argument value is below runtime lower bound"); - _CCCL_ASSERT((__val <= __runtime_bounds.upper()), "immediate argument value is above runtime upper bound"); -} - // ===================================================================== // __immediate // ===================================================================== @@ -332,7 +202,7 @@ struct __immediate_sequence _CCCL_API constexpr void __validate_value() const noexcept { - if constexpr (__is_iterable_v<_Arg> && ::cuda::std::is_arithmetic_v<__element_type>) + if constexpr (__is_sequence_v<_Arg> && ::cuda::std::is_arithmetic_v<__element_type>) { for (const auto& __a : __arg_) { @@ -616,46 +486,6 @@ template return ::cuda::std::move(__arg.__arg_); } -template -_CCCL_API constexpr auto __constant_compute_lowest() noexcept -{ - return _Value; -} - -template -_CCCL_API constexpr auto __constant_compute_highest() noexcept -{ - return _Value; -} - -template -_CCCL_API constexpr auto __constant_sequence_compute_lowest() noexcept -{ - using _ElementType = __element_type_of_t<::cuda::std::remove_cvref_t>; - auto __first = _Value.begin(); - auto __last = _Value.end(); - - if (__first == __last) - { - return ::cuda::std::numeric_limits<_ElementType>::lowest(); - } - return static_cast<_ElementType>(*::cuda::std::min_element(__first, __last)); -} - -template -_CCCL_API constexpr auto __constant_sequence_compute_highest() noexcept -{ - using _ElementType = __element_type_of_t<::cuda::std::remove_cvref_t>; - auto __first = _Value.begin(); - auto __last = _Value.end(); - - if (__first == __last) - { - return (::cuda::std::numeric_limits<_ElementType>::max)(); - } - return static_cast<_ElementType>(*::cuda::std::max_element(__first, __last)); -} - // ===================================================================== // __traits // ===================================================================== @@ -671,7 +501,7 @@ struct __traits_impl using element_type = __element_type_of_t<_Tp>; static constexpr bool is_constant = false; static constexpr bool is_deferred = false; - static constexpr bool is_single_value = __is_single_value_v<_Tp>; + static constexpr bool is_single_value = !__is_sequence_v<_Tp>; static constexpr element_type lowest = ::cuda::std::numeric_limits::lowest(); static constexpr element_type highest = (::cuda::std::numeric_limits::max)(); }; @@ -684,8 +514,8 @@ struct __traits_impl<__constant<_Value>> static constexpr bool is_constant = true; static constexpr bool is_deferred = false; static constexpr bool is_single_value = true; - static constexpr element_type lowest = __constant_compute_lowest<_Value>(); - static constexpr element_type highest = __constant_compute_highest<_Value>(); + static constexpr element_type lowest = _Value; + static constexpr element_type highest = _Value; }; template @@ -712,8 +542,8 @@ struct __traits_impl<__constant_sequence<_Value>> static constexpr bool is_constant = true; static constexpr bool is_deferred = false; static constexpr bool is_single_value = false; - static constexpr element_type lowest = __constant_sequence_compute_lowest<_Value>(); - static constexpr element_type highest = __constant_sequence_compute_highest<_Value>(); + static constexpr element_type lowest = *::cuda::std::min_element(_Value.begin(), _Value.end()); + static constexpr element_type highest = *::cuda::std::max_element(_Value.begin(), _Value.end()); }; template @@ -781,13 +611,13 @@ _CCCL_REQUIRES((!__is_wrapper_v<::cuda::std::remove_cv_t<_Tp>>) ) template [[nodiscard]] _CCCL_API constexpr auto __lowest_(__constant<_Value>) noexcept { - return __constant_compute_lowest<_Value>(); + return _Value; } template [[nodiscard]] _CCCL_API constexpr auto __lowest_(__constant_sequence<_Value>) noexcept { - return __constant_sequence_compute_lowest<_Value>(); + return *::cuda::std::min_element(_Value.begin(), _Value.end()); } template @@ -831,13 +661,13 @@ _CCCL_REQUIRES((!__is_wrapper_v<::cuda::std::remove_cv_t<_Tp>>) ) template [[nodiscard]] _CCCL_API constexpr auto __highest_(__constant<_Value>) noexcept { - return __constant_compute_highest<_Value>(); + return _Value; } template [[nodiscard]] _CCCL_API constexpr auto __highest_(__constant_sequence<_Value>) noexcept { - return __constant_sequence_compute_highest<_Value>(); + return *::cuda::std::max_element(_Value.begin(), _Value.end()); } template diff --git a/libcudacxx/include/cuda/__argument/argument_bounds.h b/libcudacxx/include/cuda/__argument/argument_bounds.h index 11c46c74417..46dd22c370c 100644 --- a/libcudacxx/include/cuda/__argument/argument_bounds.h +++ b/libcudacxx/include/cuda/__argument/argument_bounds.h @@ -22,8 +22,11 @@ #endif // no system header #include +#include #include #include +#include +#include #include #include @@ -136,12 +139,135 @@ template } template -inline constexpr bool __is_static_bounds_cv_v = __is_static_bounds_v<::cuda::std::remove_cv_t<_Tp>>; +inline constexpr bool __is_static_bounds_cv_v = __is_static_bounds_v<::cuda::std::remove_cvref_t<_Tp>>; template -inline constexpr bool __is_runtime_bounds_cv_v = __is_runtime_bounds_v<::cuda::std::remove_cv_t<_Tp>>; +inline constexpr bool __is_runtime_bounds_cv_v = __is_runtime_bounds_v<::cuda::std::remove_cvref_t<_Tp>>; template inline constexpr bool __is_bounds_v = __is_static_bounds_cv_v<_Tp> || __is_runtime_bounds_cv_v<_Tp>; +// ===================================================================== +// __assert_in_range +// ===================================================================== + +template +_CCCL_API constexpr void __assert_in_range([[maybe_unused]] _From __val) noexcept +{ + if constexpr (::cuda::std::__cccl_is_integer_v<_To> && ::cuda::std::__cccl_is_integer_v<_From>) + { + _CCCL_ASSERT(::cuda::std::in_range<_To>(__val), "runtime bound value overflows the element type"); + } +} + +template +[[nodiscard]] _CCCL_API constexpr _To __runtime_bound_cast(_From __val) noexcept +{ + __assert_in_range<_To>(__val); + return static_cast<_To>(__val); +} + +template +_CCCL_API constexpr bool __static_bound_in_range() noexcept +{ + using _From = decltype(_Value); + + if constexpr (::cuda::std::__cccl_is_integer_v<_To> && ::cuda::std::__cccl_is_integer_v<_From>) + { + return ::cuda::std::in_range<_To>(_Value); + } + else if constexpr (::cuda::std::is_arithmetic_v<_To> && ::cuda::std::is_arithmetic_v<_From>) + { + return static_cast<_From>(static_cast<_To>(_Value)) == _Value; + } + else + { + return true; + } +} + +template +inline constexpr bool __valid_static_bounds_v = true; + +template +inline constexpr bool __valid_static_bounds_v<_ElementType, __static_bounds<_Lowest, _Highest>> = + ::cuda::__argument::__static_bound_in_range<_ElementType, _Lowest>() + && ::cuda::__argument::__static_bound_in_range<_ElementType, _Highest>(); + +template +_CCCL_API constexpr _ElementType __wrapper_static_lowest() noexcept +{ + if constexpr (::cuda::std::is_same_v<_StaticBounds, __no_bounds>) + { + return ::cuda::std::numeric_limits<_ElementType>::lowest(); + } + else + { + return static_cast<_ElementType>(_StaticBounds::lower()); + } +} + +template +_CCCL_API constexpr _ElementType __wrapper_static_highest() noexcept +{ + if constexpr (::cuda::std::is_same_v<_StaticBounds, __no_bounds>) + { + return (::cuda::std::numeric_limits<_ElementType>::max)(); + } + else + { + return static_cast<_ElementType>(_StaticBounds::upper()); + } +} + +template +_CCCL_API constexpr _ElementType __effective_lowest(__runtime_bounds<_ElementType> __runtime_bounds) noexcept +{ + auto __static_lowest = ::cuda::__argument::__wrapper_static_lowest<_ElementType, _StaticBounds>(); + return __static_lowest > __runtime_bounds.lower() ? __static_lowest : __runtime_bounds.lower(); +} + +template +_CCCL_API constexpr _ElementType __effective_highest(__runtime_bounds<_ElementType> __runtime_bounds) noexcept +{ + auto __static_highest = ::cuda::__argument::__wrapper_static_highest<_ElementType, _StaticBounds>(); + return __static_highest < __runtime_bounds.upper() ? __static_highest : __runtime_bounds.upper(); +} + +template +_CCCL_API constexpr bool __valid_argument_bounds(__runtime_bounds<_ElementType> __runtime_bounds) noexcept +{ + return ::cuda::__argument::__effective_lowest<_ElementType, _StaticBounds>(__runtime_bounds) + <= ::cuda::__argument::__effective_highest<_ElementType, _StaticBounds>(__runtime_bounds); +} + +template +_CCCL_API constexpr void __validate_bounds_intersection(__runtime_bounds<_ElementType> __runtime_bounds) noexcept +{ + static_assert(__valid_static_bounds_v<_ElementType, _StaticBounds>, + "static argument bounds cannot be represented by the element type"); + _CCCL_VERIFY((::cuda::__argument::__valid_argument_bounds<_ElementType, _StaticBounds>(__runtime_bounds)), + "static and runtime argument bounds do not intersect"); +} + +template +_CCCL_API constexpr void __validate_static_element_bounds([[maybe_unused]] const _ElementType& __val) noexcept +{ + if constexpr (!::cuda::std::is_same_v<_StaticBounds, __no_bounds>) + { + _CCCL_ASSERT((__val >= ::cuda::__argument::__wrapper_static_lowest<_ElementType, _StaticBounds>()), + "immediate argument value is below static lowest bound"); + _CCCL_ASSERT((__val <= ::cuda::__argument::__wrapper_static_highest<_ElementType, _StaticBounds>()), + "immediate argument value is above static highest bound"); + } +} + +template +_CCCL_API constexpr void __validate_runtime_element_bounds( + [[maybe_unused]] const _ElementType& __val, [[maybe_unused]] __runtime_bounds<_ElementType> __runtime_bounds) noexcept +{ + _CCCL_ASSERT((__val >= __runtime_bounds.lower()), "immediate argument value is below runtime lower bound"); + _CCCL_ASSERT((__val <= __runtime_bounds.upper()), "immediate argument value is above runtime upper bound"); +} + _CCCL_END_NAMESPACE_CUDA_ARGUMENT #include diff --git a/libcudacxx/test/libcudacxx/cuda/argument/argument_bounds.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/argument_bounds.pass.cpp index c03b685e821..d7f394a0d74 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/argument_bounds.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/argument_bounds.pass.cpp @@ -82,9 +82,9 @@ TEST_FUNC constexpr bool test() // Static and runtime bounds intersection { - static_assert(cuda::__argument::__has_bounds_intersection>( + static_assert(cuda::__argument::__valid_argument_bounds>( cuda::__argument::__runtime_bounds{50, 200})); - static_assert(!cuda::__argument::__has_bounds_intersection>( + static_assert(!cuda::__argument::__valid_argument_bounds>( cuda::__argument::__runtime_bounds{0, 50})); } diff --git a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp index cdcc6665747..36154ef2207 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp @@ -11,10 +11,15 @@ #include #include #include +#include +#include #include #include +#include #include +#include #include +#include #include "test_macros.h" @@ -50,32 +55,32 @@ TEST_FUNC void test() { // --- __is_sequence_v / __is_single_value_v --- + // builtin and class type are not sequences static_assert(!cuda::__argument::__is_sequence_v); static_assert(!cuda::__argument::__is_sequence_v); static_assert(!cuda::__argument::__is_sequence_v); - static_assert(cuda::__argument::__is_sequence_v); - static_assert(cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + + // iterators are not sequences and need to be wrapped into a range + static_assert(!cuda::__argument::__is_sequence_v); + static_assert(!cuda::__argument::__is_sequence_v>); + + // ranges and arrays are sequences + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); static_assert(cuda::__argument::__is_sequence_v>); static_assert(cuda::__argument::__is_sequence_v&>); static_assert(cuda::__argument::__is_sequence_v>); static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(!cuda::__argument::__is_single_value_v); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v&>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); // --- __element_type_of_t --- @@ -106,7 +111,7 @@ TEST_FUNC void test() // --- argument_traits: is_single_value --- static_assert(cuda::__argument::__traits::is_single_value); - static_assert(!cuda::__argument::__traits::is_single_value); + static_assert(cuda::__argument::__traits::is_single_value); static_assert(cuda::__argument::__traits>::is_single_value); static_assert(cuda::__argument::__traits>::is_single_value); static_assert( diff --git a/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp index eac5e71aa82..c9723304774 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp @@ -128,7 +128,7 @@ TEST_FUNC constexpr bool test() // __is_single_value_v on unwrapped types { static_assert( - cuda::__argument::__is_single_value_v>::value_type>); + !cuda::__argument::__is_sequence_v>::value_type>); static_assert( !cuda::__argument::__traits>>::is_single_value); } diff --git a/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp index 7d40183070b..85ccaf1c8a0 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp @@ -113,7 +113,7 @@ TEST_FUNC void test() // Single value: scalar is single, sequence is not { static_assert( - cuda::__argument::__is_single_value_v>::value_type>); + !cuda::__argument::__is_sequence_v>::value_type>); #if TEST_HAS_CLASS_NTTP static_assert(!cuda::__argument::__traits< cuda::__argument::__constant_sequence{1, 2, 3}>>::is_single_value);