//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // SPDX-FileCopyrightText: Copyright (c) 2023-24 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// // cuda::std::ranges::data #include #include #include #include "test_iterators.h" #include "test_macros.h" using RangeDataT = decltype(cuda::std::ranges::data); using RangeCDataT = decltype(cuda::std::ranges::cdata); TEST_GLOBAL_VARIABLE int globalBuff[2] = {}; struct Incomplete; #if !TEST_COMPILER(MSVC, <, 19, 23) // old MSVC has a bug where it doesn't properly handle rvalue arrays static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); #endif // !TEST_COMPILER(MSVC, <, 19, 23) static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); struct DataMember { int x; __host__ __device__ constexpr const int* data() const { return &x; } }; static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct D { __host__ __device__ char*& data(); __host__ __device__ short*& data() const; }; struct NC { __host__ __device__ char* begin() const; __host__ __device__ char* end() const; __host__ __device__ int* data(); }; __host__ __device__ constexpr bool testReturnTypes() { { int* x[2] = {}; unused(x); static_assert(cuda::std::is_same_v); static_assert(cuda::std::is_same_v); } { int x[2][2] = {}; unused(x); static_assert(cuda::std::is_same_v); static_assert(cuda::std::is_same_v); } { static_assert(cuda::std::is_same_v())), char*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), short*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), short*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), short*>); static_assert(!cuda::std::is_invocable_v, ""); } { static_assert(!cuda::std::ranges::contiguous_range, ""); static_assert(cuda::std::ranges::contiguous_range, ""); static_assert(cuda::std::is_same_v())), int*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), char*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), char*>); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_same_v())), char*>); static_assert(!cuda::std::is_invocable_v, ""); } return true; } struct VoidDataMember { __host__ __device__ void* data() const; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct Empty {}; struct EmptyDataMember { __host__ __device__ Empty data() const; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct PtrConvertibleDataMember { struct Ptr { __host__ __device__ operator int*() const; }; __host__ __device__ Ptr data() const; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct NonConstDataMember { int x; __host__ __device__ constexpr int* data() { return &x; } }; struct EnabledBorrowingDataMember { __host__ __device__ constexpr const int* data() { return &globalBuff[0]; } }; namespace cuda { namespace std { namespace ranges { template <> _CCCL_INLINE_VAR constexpr bool enable_borrowed_range = true; } } // namespace std } // namespace cuda struct DataMemberAndBegin { int x; __host__ __device__ constexpr const int* data() const { return &x; } __host__ __device__ const int* begin() const; }; __host__ __device__ constexpr bool testDataMember() { DataMember a{}; assert(cuda::std::ranges::data(a) == &a.x); assert(cuda::std::ranges::cdata(a) == &a.x); NonConstDataMember b{}; assert(cuda::std::ranges::data(b) == &b.x); static_assert(!cuda::std::is_invocable_v, ""); EnabledBorrowingDataMember c{}; assert(cuda::std::ranges::data(cuda::std::move(c)) == &globalBuff[0]); static_assert(!cuda::std::is_invocable_v, ""); DataMemberAndBegin d{}; assert(cuda::std::ranges::data(d) == &d.x); assert(cuda::std::ranges::cdata(d) == &d.x); return true; } using ContiguousIter = contiguous_iterator; struct BeginMemberContiguousIterator { int buff[8]; __host__ __device__ constexpr ContiguousIter begin() const { return ContiguousIter(buff); } }; static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct BeginMemberRandomAccess { int buff[8]; __host__ __device__ random_access_iterator begin() const; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct BeginFriendContiguousIterator { int buff[8]; __host__ __device__ friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator& iter) { return ContiguousIter(iter.buff); } }; static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct BeginFriendRandomAccess { __host__ __device__ friend random_access_iterator begin(const BeginFriendRandomAccess iter); }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct BeginMemberRvalue { int buff[8]; __host__ __device__ ContiguousIter begin() &&; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); struct BeginMemberBorrowingEnabled { __host__ __device__ constexpr contiguous_iterator begin() { return contiguous_iterator{&globalBuff[1]}; } }; namespace cuda { namespace std { namespace ranges { template <> _CCCL_INLINE_VAR constexpr bool enable_borrowed_range = true; } } // namespace std } // namespace cuda static_assert(cuda::std::is_invocable_v, ""); static_assert(cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); __host__ __device__ constexpr bool testViaRangesBegin() { int arr[2] = {}; assert(cuda::std::ranges::data(arr) == arr + 0); assert(cuda::std::ranges::cdata(arr) == arr + 0); BeginMemberContiguousIterator a{}; assert(cuda::std::ranges::data(a) == a.buff); assert(cuda::std::ranges::cdata(a) == a.buff); const BeginFriendContiguousIterator b{}; assert(cuda::std::ranges::data(b) == b.buff); assert(cuda::std::ranges::cdata(b) == b.buff); BeginMemberBorrowingEnabled c{}; assert(cuda::std::ranges::data(cuda::std::move(c)) == &globalBuff[1]); static_assert(!cuda::std::is_invocable_v, ""); return true; } #if TEST_STD_VER >= 2020 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!cuda::std::is_invocable_v*>, ""); static_assert(!cuda::std::is_invocable_v*&>, ""); static_assert(!cuda::std::is_invocable_v*>, ""); static_assert(!cuda::std::is_invocable_v*&>, ""); #endif // TEST_STD_VER >= 2020 struct RandomButNotContiguous { __host__ __device__ random_access_iterator begin() const; __host__ __device__ random_access_iterator end() const; }; static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); static_assert(!cuda::std::is_invocable_v, ""); int main(int, char**) { static_assert(testReturnTypes(), ""); testDataMember(); static_assert(testDataMember(), ""); testViaRangesBegin(); static_assert(testViaRangesBegin(), ""); return 0; }