Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 121 additions & 42 deletions libcudacxx/include/cuda/__argument/argument.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <cuda/std/__utility/declval.h>
#include <cuda/std/__utility/forward.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/array>
#include <cuda/std/cstddef>
#include <cuda/std/limits>

Expand Down Expand Up @@ -111,16 +112,79 @@ class constant
};

//! @brief Wraps a compile-time constant argument sequence.
template <auto _Value>
template <class T, T... Vs>
class __constant_sequence
{
public:
using value_type = ::cuda::std::remove_cvref_t<decltype(_Value)>;
using __element_type = __element_type_of_t<value_type>;

static_assert(__is_sequence_v<value_type>, "The value type of __constant_sequence must be a sequence");
using __element_type = ::cuda::std::remove_cvref_t<T>;
using value_type = ::cuda::std::array<__element_type, sizeof...(Vs)>;
static constexpr ::cuda::std::size_t size = sizeof...(Vs);
};

template <class T>
struct __is_builtin_array : ::cuda::std::false_type
{};

template <class T, ::cuda::std::size_t N>
struct __is_builtin_array<T[N]> : ::cuda::std::true_type

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: is_bounded_array_v

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced

{};

template <class T>
struct __is_cuda_array : ::cuda::std::false_type

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: Internal traits should never go through structs, but use inline variables. We also have this already defined __is_cuda_std_array_v

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced

{};

template <class T, ::cuda::std::size_t N>
struct __is_cuda_array<::cuda::std::array<T, N>> : ::cuda::std::true_type
{};

template <class T>
struct __array_extent;

template <class T, ::cuda::std::size_t N>
struct __array_extent<T[N]> : ::cuda::std::integral_constant<::cuda::std::size_t, N>{};

template <class T, ::cuda::std::size_t N>
struct __array_extent<::cuda::std::array<T, N>> : ::cuda::std::integral_constant<::cuda::std::size_t, N>{};

template <class>
inline constexpr bool __always_false_v = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: All this already exists and we should just reuse the existing traits

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review.
I replaced them with the existing traits.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use cuda::std::__always_false_v instead.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


template <const auto& Arr, ::cuda::std::size_t... Is>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template parameters must be made __ugly as well

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

constexpr auto make_constant_sequence_impl(::cuda::std::index_sequence<Is...>)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
{
using raw_array = ::cuda::std::remove_const_t<::cuda::std::remove_reference_t<decltype(Arr)>>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
using raw_array = ::cuda::std::remove_const_t<::cuda::std::remove_reference_t<decltype(Arr)>>;
using __raw_array = ::cuda::std::remove_cvref_t<decltype(Arr)>;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion applied.


if constexpr (__is_builtin_array<raw_array>::value)
{
using T = ::cuda::std::remove_cv_t<::cuda::std::remove_extent_t<raw_array>>;
return __constant_sequence<T, Arr[Is]...>{};
}
else if constexpr (__is_cuda_array<raw_array>::value)
{
using T = typename raw_array::value_type;
return __constant_sequence<T, Arr[Is]...>{};
}
else
{
static_assert(__always_false_v<raw_array>, "unsupported array type");
}
}

//! @brief Makes a compile-time constant argument sequence.
//! In C++17, Arr must have static storage duration.
template <const auto& Arr>
constexpr auto make_constant_sequence()
{
using raw_array = ::cuda::std::remove_cv_t<::cuda::std::remove_reference_t<decltype(Arr)>>;

static_assert(__is_builtin_array<raw_array>::value || __is_cuda_array<raw_array>::value,
"make_constant_sequence requires a cuda::std::array or non-empty C-style array");

constexpr ::cuda::std::size_t N = __array_extent<raw_array>::value;

return make_constant_sequence_impl<Arr>(::cuda::std::make_index_sequence<N>{});
}

// __assert_in_range
// =====================================================================

Expand Down Expand Up @@ -621,8 +685,8 @@ template <class _Arg, class _StaticBounds>
inline constexpr bool __is_wrapper_v<immediate<_Arg, _StaticBounds>> = true;
template <auto _Value, class _Tp>
inline constexpr bool __is_wrapper_v<constant<_Value, _Tp>> = true;
template <auto _Value>
inline constexpr bool __is_wrapper_v<__constant_sequence<_Value>> = true;
template <class T, T... Vs>
inline constexpr bool __is_wrapper_v<__constant_sequence<T, Vs...>> = true;
template <class _Arg, class _StaticBounds>
inline constexpr bool __is_wrapper_v<__immediate_sequence<_Arg, _StaticBounds>> = true;
template <class _Arg, class _StaticBounds>
Expand Down Expand Up @@ -662,11 +726,11 @@ __unwrap(const constant<_Value, _Tp>&) noexcept
return constant<_Value, _Tp>::__get_value();
}

template <auto _Value>
[[nodiscard]] _CCCL_API constexpr ::cuda::std::remove_cvref_t<decltype(_Value)>
__unwrap(const __constant_sequence<_Value>&) noexcept
//! Unwraps a compile-time constant argument sequence into a canonical cuda::std::array value.
template <class T, T... Vs>
[[nodiscard]] _CCCL_API constexpr auto __unwrap(const __constant_sequence<T, Vs...>&) noexcept
{
return _Value;
return ::cuda::std::array<T, sizeof...(Vs)>{Vs...};
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

template <class _Arg, class _StaticBounds>
Expand Down Expand Up @@ -735,32 +799,48 @@ _CCCL_API constexpr auto __constant_compute_highest() noexcept
return constant<_Value, _Tp>::__get_value();
}

template <auto _Value>
_CCCL_API constexpr auto __constant_sequence_compute_lowest() noexcept
template <class T, T... Vs>
_CCCL_API constexpr T __constant_sequence_compute_lowest() noexcept
{
using _ElementType = __element_type_of_t<::cuda::std::remove_cvref_t<decltype(_Value)>>;
auto __first = _Value.begin();
auto __last = _Value.end();

if (__first == __last)
if constexpr (sizeof...(Vs) == 0)
{
return ::cuda::std::numeric_limits<_ElementType>::lowest();
return ::cuda::std::numeric_limits<T>::lowest();
}
else
{
constexpr T values[] = {Vs...};
T __min = values[0];
for (T __v : values)
{
if (__v < __min)
{
__min = __v;
}
}
return __min;
}
return static_cast<_ElementType>(*::cuda::std::min_element(__first, __last));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no longer min_element?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review!

I think at one point during development I wasn't able to use it and replaced it here.
I found a way to use it again here making the code simpler.

Applied the same for the max computation too.

}

template <auto _Value>
_CCCL_API constexpr auto __constant_sequence_compute_highest() noexcept
template <class T, T... Vs>
_CCCL_API constexpr T __constant_sequence_compute_highest() noexcept
{
using _ElementType = __element_type_of_t<::cuda::std::remove_cvref_t<decltype(_Value)>>;
auto __first = _Value.begin();
auto __last = _Value.end();

if (__first == __last)
if constexpr (sizeof...(Vs) == 0)
{
return (::cuda::std::numeric_limits<_ElementType>::max)();
return ::cuda::std::numeric_limits<T>::max();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
else
{
constexpr T values[] = {Vs...};
T __max = values[0];
for (T __v : values)
{
if (__v > __max)
{
__max = __v;
}
}
return __max;
}
return static_cast<_ElementType>(*::cuda::std::max_element(__first, __last));
}

// =====================================================================
Expand Down Expand Up @@ -811,17 +891,16 @@ struct __traits_impl<immediate<_Arg, _StaticBounds>>
static constexpr element_type highest = __wrapper_static_highest<element_type, _StaticBounds>();
};

template <auto _Value>
struct __traits_impl<__constant_sequence<_Value>>
template <class T, T... Vs>
struct __traits_impl<__constant_sequence<T, Vs...>>
{
using value_type = ::cuda::std::remove_cvref_t<decltype(_Value)>;
using element_type = __element_type_of_t<value_type>;
static_assert(__is_sequence_v<value_type>, "The value type of __constant_sequence must be a sequence");
using element_type = ::cuda::std::remove_cvref_t<T>;
using value_type = ::cuda::std::array<element_type, sizeof...(Vs)>;
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 = __constant_sequence_compute_lowest<T, Vs...>();
static constexpr element_type highest = __constant_sequence_compute_highest<T, Vs...>();
};

template <class _Arg, class _StaticBounds>
Expand Down Expand Up @@ -896,10 +975,10 @@ template <auto _Value, class _Tp>
return __constant_compute_lowest<_Value, _Tp>();
}

template <auto _Value>
[[nodiscard]] _CCCL_API constexpr auto __lowest_(__constant_sequence<_Value>) noexcept
template <class T, T... Vs>
[[nodiscard]] _CCCL_API constexpr auto __lowest_(__constant_sequence<T, Vs...>) noexcept
{
return __constant_sequence_compute_lowest<_Value>();
return __constant_sequence_compute_lowest<T, Vs...>();
}

template <class _Arg, class _StaticBounds>
Expand Down Expand Up @@ -949,10 +1028,10 @@ template <auto _Value, class _Tp>
return __constant_compute_highest<_Value, _Tp>();
}

template <auto _Value>
[[nodiscard]] _CCCL_API constexpr auto __highest_(__constant_sequence<_Value>) noexcept
template <class T, T... Vs>
[[nodiscard]] _CCCL_API constexpr auto __highest_(__constant_sequence<T, Vs...>) noexcept
{
return __constant_sequence_compute_highest<_Value>();
return __constant_sequence_compute_highest<T, Vs...>();
}

template <class _Arg, class _StaticBounds>
Expand Down
54 changes: 28 additions & 26 deletions libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,13 @@ TEST_FUNC void test()
static_assert(!cuda::args::__traits<cuda::args::immediate<int>>::is_deferred);
static_assert(!cuda::args::__traits<cuda::args::__immediate_sequence<cuda::std::span<int>>>::is_deferred);
static_assert(!cuda::args::__traits<cuda::args::constant<42>>::is_deferred);
#if TEST_HAS_CLASS_NTTP
static_assert(!cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{1, 2, 3}>>::is_deferred);
#endif // TEST_HAS_CLASS_NTTP

static_assert(!cuda::args::__traits<cuda::args::__constant_sequence<int, 1, 2, 3>>::is_deferred);
static constexpr int carr[] = {1, 2, 3};
static constexpr ::cuda::std::array<int, 3> cudaarr = {1, 2, 3};
static_assert(!cuda::args::__traits<decltype(cuda::args::make_constant_sequence<carr>())>::is_deferred);
static_assert(!cuda::args::__traits<decltype(cuda::args::make_constant_sequence<cudaarr>())>::is_deferred);

static_assert(cuda::args::__traits<cuda::args::deferred<cuda::std::span<int, 1>>>::is_deferred);
static_assert(cuda::args::__traits<cuda::args::deferred_sequence<cuda::std::span<int>>>::is_deferred);

Expand All @@ -118,10 +122,11 @@ TEST_FUNC void test()
static_assert(cuda::args::__traits<cuda::args::immediate<cuda::counting_iterator<int>>>::is_single_value);
static_assert(!cuda::args::__traits<cuda::args::__immediate_sequence<cuda::std::span<int>>>::is_single_value);
static_assert(cuda::args::__traits<cuda::args::constant<42>>::is_single_value);
#if TEST_HAS_CLASS_NTTP
static_assert(
!cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{1, 2, 3}>>::is_single_value);
#endif // TEST_HAS_CLASS_NTTP

static_assert(!cuda::args::__traits<cuda::args::__constant_sequence<int, 1, 2, 3>>::is_single_value);
static_assert(!cuda::args::__traits<decltype(cuda::args::make_constant_sequence<carr>())>::is_single_value);
static_assert(!cuda::args::__traits<decltype(cuda::args::make_constant_sequence<cudaarr>())>::is_single_value);

static_assert(cuda::args::__traits<cuda::args::deferred<int*>>::is_single_value);
static_assert(!cuda::args::__traits<cuda::args::deferred_sequence<cuda::std::span<int>>>::is_single_value);

Expand All @@ -134,11 +139,15 @@ TEST_FUNC void test()
cuda::std::span<int>>);
static_assert(cuda::std::is_same_v<cuda::args::__traits<cuda::args::constant<42>>::value_type, int>);
static_assert(cuda::std::is_same_v<cuda::args::__traits<cuda::args::constant<10, float>>::value_type, float>);
#if TEST_HAS_CLASS_NTTP
static_assert(cuda::std::is_same_v<
cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{1, 2, 3}>>::value_type,
cuda::std::array<int, 3>>);
#endif // TEST_HAS_CLASS_NTTP

static_assert(cuda::std::is_same_v<cuda::args::__traits<cuda::args::__constant_sequence<int, 1, 2, 3>>::value_type,
cuda::std::array<int, 3>>);
static_assert(
cuda::std::is_same_v<cuda::args::__traits<decltype(cuda::args::make_constant_sequence<carr>())>::value_type,
cuda::std::array<int, 3>>);
static_assert(
cuda::std::is_same_v<cuda::args::__traits<decltype(cuda::args::make_constant_sequence<cudaarr>())>::value_type,
cuda::std::array<int, 3>>);

// --- argument_traits: lowest / highest ---

Expand All @@ -155,27 +164,20 @@ TEST_FUNC void test()
== 8);
static_assert(cuda::args::__traits<cuda::args::constant<10, float>>::lowest == 10.0f);
static_assert(cuda::args::__traits<cuda::args::constant<10, float>>::highest == 10.0f);
#if TEST_HAS_CLASS_NTTP
static_assert(cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{3, 1, 2}>>::lowest == 1);
static_assert(cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{3, 1, 2}>>::highest == 3);
#endif // TEST_HAS_CLASS_NTTP

static_assert(cuda::args::__traits<cuda::args::__constant_sequence<int, 1, 2, 3>>::lowest == 1);
static_assert(cuda::args::__traits<cuda::args::__constant_sequence<int, 1, 2, 3>>::highest == 3);
static_assert(cuda::args::__traits<decltype(cuda::args::make_constant_sequence<carr>())>::lowest == 1);
static_assert(cuda::args::__traits<decltype(cuda::args::make_constant_sequence<carr>())>::highest == 3);
static_assert(cuda::args::__traits<decltype(cuda::args::make_constant_sequence<cudaarr>())>::lowest == 1);
static_assert(cuda::args::__traits<decltype(cuda::args::make_constant_sequence<cudaarr>())>::highest == 3);

// --- Free function bounds on plain values ---

static_assert(cuda::args::__lowest_(42) == cuda::std::numeric_limits<int>::lowest());
static_assert(cuda::args::__highest_(42) == (cuda::std::numeric_limits<int>::max)());
static_assert(cuda::args::__lowest_(1.0f) == cuda::std::numeric_limits<float>::lowest());
static_assert(cuda::args::__highest_(1.0f) == (cuda::std::numeric_limits<float>::max)());

// --- Scalar and sequence wrappers expose distinct single-value traits ---

static_assert(cuda::args::__traits<cuda::args::constant<42>>::is_single_value);
static_assert(cuda::args::__traits<cuda::args::immediate<int>>::is_single_value);
static_assert(!cuda::args::__traits<cuda::args::__immediate_sequence<cuda::std::span<int>>>::is_single_value);
#if TEST_HAS_CLASS_NTTP
static_assert(
!cuda::args::__traits<cuda::args::__constant_sequence<cuda::std::array<int, 3>{1, 2, 3}>>::is_single_value);
#endif // TEST_HAS_CLASS_NTTP
}

int main(int, char**)
Expand Down
Loading
Loading