//===----------------------------------------------------------------------===// // // 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) 2024 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// // UNSUPPORTED: msvc-19.16 // template // requires is_class_v && same_as> // class view_interface; #include #include #include #include "test_iterators.h" #include "test_macros.h" #if TEST_STD_VER > 2017 template concept ValidViewInterfaceType = requires { typename cuda::std::ranges::view_interface; }; #else template constexpr bool ValidViewInterfaceType = false; template constexpr bool ValidViewInterfaceType>> = true; #endif struct Empty {}; static_assert(!ValidViewInterfaceType); static_assert(!ValidViewInterfaceType); static_assert(!ValidViewInterfaceType); static_assert(!ValidViewInterfaceType); static_assert(!ValidViewInterfaceType); static_assert(ValidViewInterfaceType); using InputIter = cpp20_input_iterator; struct InputRange : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr InputIter begin() const { return InputIter(buff); } __host__ __device__ constexpr InputIter end() const { return InputIter(buff + 8); } }; struct NotSizedSentinel { using value_type = int; using difference_type = cuda::std::ptrdiff_t; using iterator_concept = cuda::std::forward_iterator_tag; explicit NotSizedSentinel() = default; __host__ __device__ explicit NotSizedSentinel(int*); __host__ __device__ int& operator*() const; __host__ __device__ NotSizedSentinel& operator++(); __host__ __device__ NotSizedSentinel operator++(int); __host__ __device__ bool operator==(NotSizedSentinel const&) const; #if TEST_STD_VER < 2020 __host__ __device__ bool operator!=(NotSizedSentinel const&) const; #endif }; static_assert(cuda::std::forward_iterator); using ForwardIter = forward_iterator; // So that we conform to sized_sentinel_for. __host__ __device__ constexpr cuda::std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) { return base(x) - base(y); } struct ForwardRange : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } __host__ __device__ constexpr ForwardIter end() const { return ForwardIter(const_cast(buff) + 8); } }; static_assert(cuda::std::ranges::view); struct MoveOnlyForwardRange : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; MoveOnlyForwardRange(MoveOnlyForwardRange const&) = delete; MoveOnlyForwardRange(MoveOnlyForwardRange&&) = default; MoveOnlyForwardRange& operator=(MoveOnlyForwardRange&&) = default; MoveOnlyForwardRange() = default; __host__ __device__ constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } __host__ __device__ constexpr ForwardIter end() const { return ForwardIter(const_cast(buff) + 8); } }; static_assert(cuda::std::ranges::view); struct MI : cuda::std::ranges::view_interface , cuda::std::ranges::view_interface {}; static_assert(!cuda::std::ranges::view); struct EmptyIsTrue : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } __host__ __device__ constexpr ForwardIter end() const { return ForwardIter(const_cast(buff) + 8); } __host__ __device__ constexpr bool empty() const { return true; } }; static_assert(cuda::std::ranges::view); struct SizeIsTen : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } __host__ __device__ constexpr ForwardIter end() const { return ForwardIter(const_cast(buff) + 8); } __host__ __device__ constexpr size_t size() const { return 10; } }; static_assert(cuda::std::ranges::view); using RAIter = random_access_iterator; struct RARange : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr RAIter begin() const { return RAIter(const_cast(buff)); } __host__ __device__ constexpr RAIter end() const { return RAIter(const_cast(buff) + 8); } }; static_assert(cuda::std::ranges::view); using ContIter = contiguous_iterator; struct ContRange : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ContIter begin() const { return ContIter(buff); } __host__ __device__ constexpr ContIter end() const { return ContIter(buff + 8); } }; static_assert(cuda::std::ranges::view); struct DataIsNull : cuda::std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ContIter begin() const { return ContIter(buff); } __host__ __device__ constexpr ContIter end() const { return ContIter(buff + 8); } __host__ __device__ constexpr const int* data() const { return nullptr; } }; static_assert(cuda::std::ranges::view); struct BoolConvertibleComparison : cuda::std::ranges::view_interface { struct ResultType { bool value; __host__ __device__ constexpr operator bool() const { return value; } }; struct SentinelType { int* base_; explicit SentinelType() = default; __host__ __device__ constexpr explicit SentinelType(int* base) : base_(base) {} __host__ __device__ friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) == sent.base_}; } __host__ __device__ friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) == sent.base_}; } __host__ __device__ friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) != sent.base_}; } __host__ __device__ friend constexpr ResultType operator!=(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) != sent.base_}; } }; int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; __host__ __device__ constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } __host__ __device__ constexpr SentinelType end() const { return SentinelType(const_cast(buff) + 8); } }; static_assert(cuda::std::ranges::view); #if TEST_STD_VER > 2017 template concept EmptyInvocable = requires(T const& obj) { obj.empty(); }; template concept BoolOpInvocable = requires(T const& obj) { bool(obj); }; #else template constexpr bool EmptyInvocable = false; template constexpr bool EmptyInvocable().empty())>> = true; template constexpr bool BoolOpInvocable = false; template constexpr bool BoolOpInvocable()))>> = true; #endif __host__ __device__ constexpr bool testEmpty() { static_assert(!EmptyInvocable); static_assert(EmptyInvocable); static_assert(!BoolOpInvocable); static_assert(BoolOpInvocable); ForwardRange forwardRange; assert(!forwardRange.empty()); assert(!static_cast(forwardRange).empty()); assert(forwardRange); assert(static_cast(forwardRange)); assert(!cuda::std::ranges::empty(forwardRange)); assert(!cuda::std::ranges::empty(static_cast(forwardRange))); EmptyIsTrue emptyTrue{}; assert(emptyTrue.empty()); assert(static_cast(emptyTrue).empty()); assert(!emptyTrue.cuda::std::ranges::view_interface::empty()); assert(!emptyTrue); assert(!static_cast(emptyTrue)); assert(!emptyTrue.cuda::std::ranges::view_interface::operator bool()); assert(cuda::std::ranges::empty(emptyTrue)); assert(cuda::std::ranges::empty(static_cast(emptyTrue))); // Try calling empty on an rvalue. MoveOnlyForwardRange moveOnly{}; assert(!cuda::std::move(moveOnly).empty()); BoolConvertibleComparison boolConv{}; // old GCC seems to fall over the noexcept clauses here #if !TEST_COMPILER(GCC, <, 9) && !TEST_COMPILER(MSVC) static_assert(!noexcept(boolConv.empty())); #endif // !TEST_COMPILER(GCC, <, 9) && !TEST_COMPILER(MSVC) assert(!boolConv.empty()); assert(!static_cast(boolConv).empty()); assert(boolConv); assert(static_cast(boolConv)); assert(!cuda::std::ranges::empty(boolConv)); assert(!cuda::std::ranges::empty(static_cast(boolConv))); return true; } #if TESTS_STD_VER > 17 template concept DataInvocable = requires(T const& obj) { obj.data(); }; #else template constexpr bool DataInvocable = false; template constexpr bool DataInvocable().data())>> = true; #endif __host__ __device__ constexpr bool testData() { static_assert(!DataInvocable); static_assert(DataInvocable); ContRange contiguous{}; assert(contiguous.data() == contiguous.buff); assert(static_cast(contiguous).data() == contiguous.buff); assert(cuda::std::ranges::data(contiguous) == contiguous.buff); assert(cuda::std::ranges::data(static_cast(contiguous)) == contiguous.buff); DataIsNull dataNull{}; assert(dataNull.data() == nullptr); assert(static_cast(dataNull).data() == nullptr); assert(dataNull.cuda::std::ranges::view_interface::data() == dataNull.buff); assert(cuda::std::ranges::data(dataNull) == nullptr); assert(cuda::std::ranges::data(static_cast(dataNull)) == nullptr); return true; } #if TEST_STD_VER > 2017 template concept SizeInvocable = requires(T const& obj) { obj.size(); }; #else template constexpr bool SizeInvocable = false; template constexpr bool SizeInvocable().size())>> = true; #endif __host__ __device__ constexpr bool testSize() { static_assert(!SizeInvocable); static_assert(!SizeInvocable); static_assert(SizeInvocable); // Test the test. static_assert(cuda::std::same_as() - cuda::std::declval()), cuda::std::ptrdiff_t>); using UnsignedSize = cuda::std::make_unsigned_t; using SignedSize = cuda::std::common_type_t>; ForwardRange forwardRange{}; assert(forwardRange.size() == 8); assert(static_cast(forwardRange).size() == 8); assert(cuda::std::ranges::size(forwardRange) == 8); static_assert( cuda::std::same_as())), UnsignedSize>); static_assert(cuda::std::same_as())), SignedSize>); assert(cuda::std::ranges::size(static_cast(forwardRange)) == 8); static_assert( cuda::std::same_as())), UnsignedSize>); static_assert( cuda::std::same_as())), SignedSize>); SizeIsTen sizeTen{}; assert(sizeTen.size() == 10); assert(static_cast(sizeTen).size() == 10); assert(sizeTen.cuda::std::ranges::view_interface::size() == 8); assert(cuda::std::ranges::size(sizeTen) == 10); assert(cuda::std::ranges::size(static_cast(sizeTen)) == 10); return true; } #if TEST_STD_VER > 2017 template concept SubscriptInvocable = requires(T const& obj, size_t n) { obj[n]; }; #else template constexpr bool SubscriptInvocable = false; template constexpr bool SubscriptInvocable()[cuda::std::declval()])>> = true; #endif __host__ __device__ constexpr bool testSubscript() { static_assert(!SubscriptInvocable); static_assert(SubscriptInvocable); RARange randomAccess{}; assert(randomAccess[2] == 2); assert(static_cast(randomAccess)[2] == 2); randomAccess[2] = 3; assert(randomAccess[2] == 3); return true; } #if TEST_STD_VER > 2017 template concept FrontInvocable = requires(T const& obj) { obj.front(); }; template concept BackInvocable = requires(T const& obj) { obj.back(); }; #else template constexpr bool FrontInvocable = false; template constexpr bool FrontInvocable().front())>> = true; template constexpr bool BackInvocable = false; template constexpr bool BackInvocable().back())>> = true; #endif __host__ __device__ constexpr bool testFrontBack() { static_assert(!FrontInvocable); static_assert(FrontInvocable); static_assert(!BackInvocable); static_assert(BackInvocable); ForwardRange forwardRange{}; assert(forwardRange.front() == 0); assert(static_cast(forwardRange).front() == 0); forwardRange.front() = 2; assert(forwardRange.front() == 2); RARange randomAccess{}; assert(randomAccess.front() == 0); assert(static_cast(randomAccess).front() == 0); randomAccess.front() = 2; assert(randomAccess.front() == 2); assert(randomAccess.back() == 7); assert(static_cast(randomAccess).back() == 7); randomAccess.back() = 2; assert(randomAccess.back() == 2); return true; } struct V1 : cuda::std::ranges::view_interface {}; struct V2 : cuda::std::ranges::view_interface { V1 base_; }; static_assert(sizeof(V2) == sizeof(V1)); int main(int, char**) { testEmpty(); static_assert(testEmpty()); testData(); static_assert(testData()); testSize(); static_assert(testSize()); testSubscript(); static_assert(testSubscript()); testFrontBack(); static_assert(testFrontBack()); return 0; }