//===----------------------------------------------------------------------===// // // 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. // //===----------------------------------------------------------------------===// // Modifications Copyright (c) 2025 Advanced Micro Devices, Inc. // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // UNSUPPORTED: msvc-19.16 // cuda::std::ranges::empty #include #include #include #include "test_iterators.h" #include "test_macros.h" using RangeEmptyT = decltype(cuda::std::ranges::empty); 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 Incomplete; static_assert(!cuda::std::is_invocable_v); static_assert(!cuda::std::is_invocable_v); static_assert(!cuda::std::is_invocable_v); #if !defined(TEST_COMPILER_NVRTC) && !defined(TEST_COMPILER_HIPRTC) extern Incomplete array_of_incomplete[42]; static_assert(!cuda::std::ranges::empty(array_of_incomplete)); static_assert(!cuda::std::ranges::empty(cuda::std::move(array_of_incomplete))); extern const Incomplete const_array_of_incomplete[42]; static_assert(!cuda::std::ranges::empty(const_array_of_incomplete)); static_assert(!cuda::std::ranges::empty(static_cast(array_of_incomplete))); #endif // TEST_COMPILER(NVRTC) struct InputRangeWithoutSize { __host__ __device__ cpp17_input_iterator begin() const; __host__ __device__ cpp17_input_iterator end() const; }; static_assert(!cuda::std::is_invocable_v); struct NonConstEmpty { __host__ __device__ bool empty(); }; static_assert(!cuda::std::is_invocable_v); struct HasMemberAndFunction { __host__ __device__ constexpr bool empty() const { return true; } // We should never do ADL lookup for cuda::std::ranges::empty. __host__ __device__ friend bool empty(const HasMemberAndFunction&) { return false; } }; struct BadReturnType { __host__ __device__ BadReturnType empty() { return {}; } }; static_assert(!cuda::std::is_invocable_v); struct BoolConvertible { __host__ __device__ constexpr explicit operator bool() noexcept(false) { return true; } }; struct BoolConvertibleReturnType { __host__ __device__ constexpr BoolConvertible empty() noexcept { return {}; } }; // old GCC seems to fall over the chaining of the noexcept clauses here #if !TEST_COMPILER(GCC, <, 9) && !TEST_COMPILER(MSVC) static_assert(!noexcept(cuda::std::ranges::empty(BoolConvertibleReturnType()))); #endif // !TEST_COMPILER(GCC, <, 9) && !TEST_COMPILER(MSVC) struct InputIterators { __host__ __device__ cpp17_input_iterator begin() const; __host__ __device__ cpp17_input_iterator end() const; }; static_assert(cuda::std::is_same_v); static_assert(!cuda::std::is_invocable_v); __host__ __device__ constexpr bool testEmptyMember() { HasMemberAndFunction a{}; assert(cuda::std::ranges::empty(a)); BoolConvertibleReturnType b{}; assert(cuda::std::ranges::empty(b)); return true; } struct SizeMember { size_t size_; __host__ __device__ constexpr size_t size() const { return size_; } }; struct SizeFunction { size_t size_; __host__ __device__ friend constexpr size_t size(SizeFunction sf) { return sf.size_; } }; struct BeginEndSizedSentinel { __host__ __device__ constexpr int* begin() const { return nullptr; } __host__ __device__ constexpr auto end() const { return sized_sentinel(nullptr); } }; static_assert(cuda::std::ranges::forward_range); static_assert(cuda::std::ranges::sized_range); __host__ __device__ constexpr bool testUsingRangesSize() { SizeMember a{1}; assert(!cuda::std::ranges::empty(a)); SizeMember b{0}; assert(cuda::std::ranges::empty(b)); SizeFunction c{1}; assert(!cuda::std::ranges::empty(c)); SizeFunction d{0}; assert(cuda::std::ranges::empty(d)); BeginEndSizedSentinel e{}; assert(cuda::std::ranges::empty(e)); return true; } struct BeginEndNotSizedSentinel { __host__ __device__ constexpr int* begin() const { return nullptr; } __host__ __device__ constexpr auto end() const { return sentinel_wrapper(nullptr); } }; static_assert(cuda::std::ranges::forward_range); static_assert(!cuda::std::ranges::sized_range); // size is disabled here, so we have to compare begin and end. struct DisabledSizeRangeWithBeginEnd { __host__ __device__ constexpr int* begin() const { return nullptr; } __host__ __device__ constexpr auto end() const { return sentinel_wrapper(nullptr); } __host__ __device__ size_t size() const; }; template <> inline constexpr bool cuda::std::ranges::disable_sized_range = true; static_assert(cuda::std::ranges::contiguous_range); static_assert(!cuda::std::ranges::sized_range); struct BeginEndAndEmpty { __host__ __device__ constexpr int* begin() const { return nullptr; } __host__ __device__ constexpr auto end() const { return sentinel_wrapper(nullptr); } __host__ __device__ constexpr bool empty() { return false; } }; struct EvilBeginEnd { __host__ __device__ bool empty() &&; __host__ __device__ constexpr int* begin() & { return nullptr; } __host__ __device__ constexpr int* end() & { return nullptr; } }; __host__ __device__ constexpr bool testBeginEqualsEnd() { BeginEndNotSizedSentinel a{}; assert(cuda::std::ranges::empty(a)); DisabledSizeRangeWithBeginEnd d{}; assert(cuda::std::ranges::empty(d)); BeginEndAndEmpty e{}; assert(!cuda::std::ranges::empty(e)); // e.empty() const BeginEndAndEmpty ce{}; assert(cuda::std::ranges::empty(ce)); // e.begin() == e.end() assert(cuda::std::ranges::empty(EvilBeginEnd())); return true; } #if TEST_STD_VER > 2017 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!cuda::std::is_invocable_v*>); static_assert(!cuda::std::is_invocable_v*&>); #endif int main(int, char**) { testEmptyMember(); static_assert(testEmptyMember()); testUsingRangesSize(); static_assert(testUsingRangesSize()); testBeginEqualsEnd(); static_assert(testBeginEqualsEnd()); return 0; }