From 2a0fed9e6bab21c9b11ea8402fc6f538708a7e9e Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 26 Feb 2024 20:07:40 +0100 Subject: [PATCH] Implement `ranges::elements_view` --- .../std/__iterator/unreachable_sentinel.h | 16 +- .../include/cuda/std/__ranges/elements_view.h | 627 ++++++++++++++++++ .../cuda/std/detail/libcxx/include/ranges | 22 + .../range.elements/adaptor.pass.cpp | 236 +++++++ .../range.elements/base.pass.cpp | 103 +++ .../range.elements/begin.pass.cpp | 131 ++++ .../range.elements/borrowed.compile.pass.cpp | 53 ++ .../range.elements/ctor.default.pass.cpp | 51 ++ .../range.elements/ctor.view.pass.cpp | 49 ++ .../range.elements/end.pass.cpp | 167 +++++ .../iterator/arithmetic.pass.cpp | 154 +++++ .../range.elements/iterator/base.pass.cpp | 133 ++++ .../range.elements/iterator/compare.pass.cpp | 172 +++++ .../iterator/ctor.base.pass.cpp | 69 ++ .../iterator/ctor.default.pass.cpp | 77 +++ .../iterator/ctor.other.pass.cpp | 96 +++ .../iterator/decrement.pass.cpp | 112 ++++ .../range.elements/iterator/deref.pass.cpp | 113 ++++ .../iterator/increment.pass.cpp | 86 +++ .../iterator/member_types.compile.pass.cpp | 110 +++ .../iterator/subscript.pass.cpp | 86 +++ .../range.concept.compile.pass.cpp | 95 +++ .../range.elements/sentinel/base.pass.cpp | 66 ++ .../sentinel/ctor.base.pass.cpp | 85 +++ .../sentinel/ctor.convert.pass.cpp | 177 +++++ .../sentinel/ctor.default.pass.cpp | 80 +++ .../range.elements/sentinel/equality.pass.cpp | 272 ++++++++ .../range.elements/sentinel/minus.pass.cpp | 310 +++++++++ .../range.elements/size.pass.cpp | 122 ++++ .../range.adaptors/range.elements/types.h | 156 +++++ 30 files changed, 4018 insertions(+), 8 deletions(-) create mode 100644 libcudacxx/include/cuda/std/__ranges/elements_view.h create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/base.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/begin.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/borrowed.compile.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/end.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/arithmetic.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/compare.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.default.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/decrement.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/deref.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/member_types.compile.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/subscript.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.default.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/equality.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/minus.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/size.pass.cpp create mode 100644 libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/types.h diff --git a/libcudacxx/include/cuda/std/__iterator/unreachable_sentinel.h b/libcudacxx/include/cuda/std/__iterator/unreachable_sentinel.h index 0543e33ad14..e1f7c645af8 100644 --- a/libcudacxx/include/cuda/std/__iterator/unreachable_sentinel.h +++ b/libcudacxx/include/cuda/std/__iterator/unreachable_sentinel.h @@ -4,7 +4,7 @@ // 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 NVIDIA CORPORATION & AFFILIATES. +// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. // SPDX-FileCopyrightText: Copyright (c) 2023 Microsoft Corporation. // //===----------------------------------------------------------------------===// @@ -24,15 +24,15 @@ #include -#if _CCCL_STD_VER > 2014 +#if _CCCL_STD_VER >= 2017 _LIBCUDACXX_BEGIN_NAMESPACE_STD _LIBCUDACXX_BEGIN_NAMESPACE_RANGES_ABI // MSVC requires an interesting workaround for a /permissive- bug -// We cannot simply define unreachable_sentinel_t with it friendfunctions, -// but we must derive from a base class in a different namespace so that they -// are only ever found through ADL +// We cannot simply define unreachable_sentinel_t with its friend functions, +// but we must derive from a base class in a different namespace so that they are +// only ever found through ADL struct unreachable_sentinel_t # ifdef _CCCL_COMPILER_MSVC @@ -49,7 +49,7 @@ struct __unreachable_base { return false; } -# if _CCCL_STD_VER < 2020 +# if _CCCL_STD_VER <= 2017 _LIBCUDACXX_TEMPLATE(class _Iter) _LIBCUDACXX_REQUIRES(weakly_incrementable<_Iter>) _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY _CCCL_NODISCARD_FRIEND constexpr bool @@ -71,7 +71,7 @@ struct __unreachable_base { return true; } -# endif // _CCCL_STD_VER < 2020 +# endif // _CCCL_STD_VER <= 2017 }; # ifdef _CCCL_COMPILER_MSVC @@ -85,6 +85,6 @@ _LIBCUDACXX_END_NAMESPACE_RANGES_ABI _LIBCUDACXX_CPO_ACCESSIBILITY unreachable_sentinel_t unreachable_sentinel{}; _LIBCUDACXX_END_NAMESPACE_STD -#endif // _CCCL_STD_VER > 2014 +#endif // _CCCL_STD_VER >= 2017 #endif // _LIBCUDACXX___ITERATOR_UNREACHABLE_SENTINEL_H diff --git a/libcudacxx/include/cuda/std/__ranges/elements_view.h b/libcudacxx/include/cuda/std/__ranges/elements_view.h new file mode 100644 index 00000000000..442598b4041 --- /dev/null +++ b/libcudacxx/include/cuda/std/__ranges/elements_view.h @@ -0,0 +1,627 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCUDACXX___RANGES_ELEMENTS_VIEW_H +#define _LIBCUDACXX___RANGES_ELEMENTS_VIEW_H + +#include + +#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) +# pragma GCC system_header +#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) +# pragma clang system_header +#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) +# pragma system_header +#endif // no system header + +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +# include +#endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _CCCL_STD_VER >= 2017 && !defined(_CCCL_COMPILER_MSVC_2017) + +// MSVC complains about [[msvc::no_unique_address]] prior to C++20 as a vendor extension +_CCCL_DIAG_PUSH +_CCCL_DIAG_SUPPRESS_MSVC(4848) + +_LIBCUDACXX_BEGIN_NAMESPACE_RANGES +_LIBCUDACXX_BEGIN_NAMESPACE_RANGES_ABI + +template +class __elements_view_iterator; + +template +class __elements_view_sentinel; + +# if _CCCL_STD_VER >= 2020 +template +concept __has_tuple_element = __tuple_like<_Tp>::value && (_Np < tuple_size_v<_Tp>); +# else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +_LIBCUDACXX_CONCEPT_FRAGMENT( + __has_tuple_element_, requires()(requires(__tuple_like<_Tp>::value), requires(_Np::value < tuple_size<_Tp>::value))); + +template +_LIBCUDACXX_CONCEPT __has_tuple_element = + _LIBCUDACXX_FRAGMENT(__has_tuple_element_, _Tp, integral_constant); +# endif // _CCCL_STD_VER <= 2017 + +template +_LIBCUDACXX_INLINE_VAR constexpr bool __returnable_element = is_reference_v<_Tp>; + +template +_LIBCUDACXX_INLINE_VAR constexpr bool + __returnable_element<_Tp, _Np, enable_if_t>>> = true; + +# if _CCCL_STD_VER >= 2020 +template + requires view<_View> && __has_tuple_element, _Np> + && __has_tuple_element>, _Np> + && __returnable_element, _Np> +# else // ^^^ C++20 ^^^ / vvv C++17 vvv +template , int> = 0, + enable_if_t, int> = 0, + enable_if_t<__has_tuple_element, _Np>, int> = 0, + enable_if_t<__has_tuple_element>, _Np>, int> = 0, + enable_if_t<__returnable_element, _Np>, int> = 0> +# endif // _CCCL_STD_VER <= 2017 +class elements_view : public view_interface> +{ +private: + template + using __iterator = __elements_view_iterator<_View, _Np, _Const>; + + template + using __sentinel = __elements_view_sentinel<_View, _Np, _Const>; + + _CCCL_NO_UNIQUE_ADDRESS _View __base_ = _View(); + +public: +# if _CCCL_STD_VER >= 2020 + elements_view() + requires default_initializable<_View> + = default; +# else // ^^^ C++20 ^^^ / vvv C++17 vvv + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(default_initializable<_View2>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr elements_view() noexcept( + is_nothrow_default_constructible_v<_View2>) + : view_interface>() + {} +# endif // _CCCL_STD_VER <= 2017 + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr explicit elements_view(_View __base) noexcept( + is_nothrow_move_constructible_v<_View>) + : view_interface>() + , __base_(_CUDA_VSTD::move(__base)) + {} + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(copy_constructible<_View2>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr _View base() const& + { + return __base_; + } + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr _View base() && + { + return _CUDA_VSTD::move(__base_); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES((!__simple_view<_View2>) ) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto begin() + { + return __iterator(_CUDA_VRANGES::begin(__base_)); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(range) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto begin() const + { + return __iterator(_CUDA_VRANGES::begin(__base_)); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES((!__simple_view<_View2>) ) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto end() + { + if constexpr (common_range<_View>) + { + return __iterator{_CUDA_VRANGES::end(__base_)}; + } + else + { + return __sentinel{_CUDA_VRANGES::end(__base_)}; + } + _LIBCUDACXX_UNREACHABLE(); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(range) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto end() const + { + if constexpr (common_range<_View>) + { + return __iterator{_CUDA_VRANGES::end(__base_)}; + } + else + { + return __sentinel{_CUDA_VRANGES::end(__base_)}; + } + _LIBCUDACXX_UNREACHABLE(); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(sized_range<_View2>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto size() + { + return _CUDA_VRANGES::size(__base_); + } + + _LIBCUDACXX_TEMPLATE(class _View2 = _View) + _LIBCUDACXX_REQUIRES(sized_range) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto size() const + { + return _CUDA_VRANGES::size(__base_); + } +}; + +template +struct __elements_view_iterator_category_base +{}; + +template +struct __elements_view_iterator_category_base<_Base, _Np, enable_if_t>> +{ + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto __get_iterator_category() noexcept + { + using _Result = decltype(_CUDA_VSTD::get<_Np>(*_CUDA_VSTD::declval>())); + using _Cat = typename iterator_traits>::iterator_category; + + if constexpr (!is_lvalue_reference_v<_Result>) + { + return input_iterator_tag{}; + } + else if constexpr (derived_from<_Cat, random_access_iterator_tag>) + { + return random_access_iterator_tag{}; + } + else + { + return _Cat{}; + } + _LIBCUDACXX_UNREACHABLE(); + } + + using iterator_category = decltype(__get_iterator_category()); +}; + +template +class __elements_view_iterator : public __elements_view_iterator_category_base<__maybe_const<_Const, _View>, _Np> +{ + template + friend class __elements_view_iterator; + + template + friend class __elements_view_sentinel; + + using _Base = __maybe_const<_Const, _View>; + template + using _Base2 = __maybe_const<_OtherConst, _View>; + + iterator_t<_Base> __current_ = iterator_t<_Base>(); + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) + __get_element(const iterator_t<_Base>& __i) + { + if constexpr (is_reference_v>) + { + return _CUDA_VSTD::get<_Np>(*__i); + } + else + { + using _Element = remove_cv_t>>; +# if defined(_CCCL_COMPILER_MSVC) // MSVC does not copy with the static_cast + return _Element(_CUDA_VSTD::get<_Np>(*__i)); +# else // ^^^ _CCCL_COMPILER_MSVC ^^^ / vvv !_CCCL_COMPILER_MSVC vvv + return static_cast<_Element>(_CUDA_VSTD::get<_Np>(*__i)); +# endif // !_CCCL_COMPILER_MSVC + } + _LIBCUDACXX_UNREACHABLE(); + } + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto __get_iterator_concept() noexcept + { + if constexpr (random_access_range<_Base>) + { + return random_access_iterator_tag{}; + } + else if constexpr (bidirectional_range<_Base>) + { + return bidirectional_iterator_tag{}; + } + else if constexpr (forward_range<_Base>) + { + return forward_iterator_tag{}; + } + else + { + return input_iterator_tag{}; + } + _LIBCUDACXX_UNREACHABLE(); + } + +public: + using iterator_concept = decltype(__get_iterator_concept()); + using value_type = remove_cvref_t>>; + using difference_type = range_difference_t<_Base>; + +# if _CCCL_STD_VER >= 2020 + __elements_view_iterator() + requires default_initializable> + = default; +# else // ^^^ C++20 ^^^ / vvv C++17 vvv + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(default_initializable>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator() noexcept( + is_nothrow_default_constructible_v>>) + {} +# endif // _CCCL_STD_VER <= 2017 + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr explicit __elements_view_iterator( + iterator_t<_Base> __current) noexcept(is_nothrow_move_constructible_v>) + : __current_(_CUDA_VSTD::move(__current)) + {} + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(_Const2 _LIBCUDACXX_AND convertible_to, iterator_t<_Base>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator( + __elements_view_iterator<_View, _Np, !_Const2> __i) + : __current_(_CUDA_VSTD::move(__i.__current_)) + {} + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr const iterator_t<_Base>& base() const& noexcept + { + return __current_; + } + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr iterator_t<_Base> base() && + { + return _CUDA_VSTD::move(__current_); + } + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr decltype(auto) operator*() const + { + return __get_element(__current_); + } + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator& operator++() + { + ++__current_; + return *this; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES((!forward_range<_Base2<_Const2>>) ) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr void operator++(int) + { + ++__current_; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(forward_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator operator++(int) + { + auto temp = *this; + ++__current_; + return temp; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(bidirectional_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator& operator--() + { + --__current_; + return *this; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(bidirectional_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator operator--(int) + { + auto temp = *this; + --__current_; + return temp; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(random_access_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator& + operator+=(difference_type __n) + { + __current_ += __n; + return *this; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(random_access_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_iterator& + operator-=(difference_type __n) + { + __current_ -= __n; + return *this; + } + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(random_access_range<_Base2<_Const2>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr decltype(auto) operator[](difference_type __n) const + { + return __get_element(__current_ + __n); + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator==(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(equality_comparable>>) + { + return __x.__current_ == __y.__current_; + } +# if _CCCL_STD_VER <= 2017 + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator!=(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(equality_comparable>>) + { + return __x.__current_ != __y.__current_; + } +# endif // _CCCL_STD_VER <= 2017 + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator<(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(random_access_range<_Base2<_Const2>>) + { + return __x.__current_ < __y.__current_; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator>(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(random_access_range<_Base2<_Const2>>) + { + return __y < __x; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator<=(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(random_access_range<_Base2<_Const2>>) + { + return !(__y < __x); + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator>=(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(random_access_range<_Base2<_Const2>>) + { + return !(__x < __y); + } + +# ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY friend constexpr auto + operator<=>(const __elements_view_iterator& __x, const __elements_view_iterator& __y) + requires random_access_range<_Base> && three_way_comparable> + { + return __x.__current_ <=> __y.__current_; + } +# endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator+(const __elements_view_iterator& __x, difference_type __y) + _LIBCUDACXX_TRAILING_REQUIRES(__elements_view_iterator)(random_access_range<_Base2<_Const2>>) + { + return __elements_view_iterator{__x} += __y; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator+(difference_type __x, const __elements_view_iterator& __y) + _LIBCUDACXX_TRAILING_REQUIRES(__elements_view_iterator)(random_access_range<_Base2<_Const2>>) + { + return __y + __x; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator-(const __elements_view_iterator& __x, difference_type __y) + _LIBCUDACXX_TRAILING_REQUIRES(__elements_view_iterator)(random_access_range<_Base2<_Const2>>) + { + return __elements_view_iterator{__x} -= __y; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator-(const __elements_view_iterator& __x, const __elements_view_iterator& __y) _LIBCUDACXX_TRAILING_REQUIRES( + difference_type)(sized_sentinel_for>, iterator_t<_Base2<_Const2>>>) + { + return __x.__current_ - __y.__current_; + } +}; + +template +class __elements_view_sentinel +{ +private: + using _Base = __maybe_const<_Const, _View>; + _CCCL_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + + template + friend class __elements_view_sentinel; + + template + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) + __get_current(const __elements_view_iterator<_View, _Np, _AnyConst>& __iter) + { + return (__iter.__current_); + } + +public: + __elements_view_sentinel() = default; + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr explicit __elements_view_sentinel( + sentinel_t<_Base> __end) + : __end_(_CUDA_VSTD::move(__end)) + {} + + _LIBCUDACXX_TEMPLATE(bool _Const2 = _Const) + _LIBCUDACXX_REQUIRES(_Const2 _LIBCUDACXX_AND convertible_to, sentinel_t<_Base>>) + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __elements_view_sentinel( + __elements_view_sentinel<_View, _Np, !_Const2> __other) + : __end_(_CUDA_VSTD::move(__other.__end_)) + {} + + _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr sentinel_t<_Base> base() const + { + return __end_; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator==(const __elements_view_iterator<_View, _Np, _OtherConst>& __x, const __elements_view_sentinel& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>>) + { + return __get_current(__x) == __y.__end_; + } +# if _CCCL_STD_VER <= 2017 + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator==(const __elements_view_sentinel& __y, const __elements_view_iterator<_View, _Np, _OtherConst>& __x) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>>) + { + return __get_current(__x) == __y.__end_; + } + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator!=(const __elements_view_iterator<_View, _Np, _OtherConst>& __x, const __elements_view_sentinel& __y) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>>) + { + return __get_current(__x) != __y.__end_; + } + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator!=(const __elements_view_sentinel& __y, const __elements_view_iterator<_View, _Np, _OtherConst>& __x) + _LIBCUDACXX_TRAILING_REQUIRES(bool)(sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>>) + { + return __get_current(__x) != __y.__end_; + } +# endif // _CCCL_STD_VER <= 2017 + + template + static constexpr bool __sized_sentinel = + sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>>; + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator-(const __elements_view_iterator<_View, _Np, _OtherConst>& __x, const __elements_view_sentinel& __y) + _LIBCUDACXX_TRAILING_REQUIRES(range_difference_t<__maybe_const<_OtherConst, _View>>)(__sized_sentinel<_OtherConst>) + { + return __get_current(__x) - __y.__end_; + } + + template + friend _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator-(const __elements_view_sentinel& __x, const __elements_view_iterator<_View, _Np, _OtherConst>& __y) + _LIBCUDACXX_TRAILING_REQUIRES(range_difference_t<__maybe_const<_OtherConst, _View>>)(__sized_sentinel<_OtherConst>) + { + return __x.__end_ - __get_current(__y); + } +}; + +_LIBCUDACXX_END_NAMESPACE_RANGES_ABI + +template +_LIBCUDACXX_INLINE_VAR constexpr bool enable_borrowed_range> = enable_borrowed_range<_Tp>; + +template +using keys_view = elements_view<_Tp, 0>; +template +using values_view = elements_view<_Tp, 1>; + +_LIBCUDACXX_END_NAMESPACE_RANGES + +_LIBCUDACXX_BEGIN_NAMESPACE_VIEWS +_LIBCUDACXX_BEGIN_NAMESPACE_CPO(__elements) + +template +struct __fn : __range_adaptor_closure<__fn<_Np>> +{ + template + _CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto + operator()(_Range&& __range) const + noexcept(noexcept(/**/ elements_view, _Np>(_CUDA_VSTD::forward<_Range>(__range)))) + -> elements_view, _Np> + { + return /*-----------*/ elements_view, _Np>(_CUDA_VSTD::forward<_Range>(__range)); + } +}; +_LIBCUDACXX_END_NAMESPACE_CPO + +inline namespace __cpo +{ +# if defined(_CCCL_COMPILER_MSVC) +template +_LIBCUDACXX_INLINE_VAR constexpr auto elements = __elements::__fn<_Np>{}; +# else // ^^^ _CCCL_COMPILER_MSVC ^^^ / vvv !_CCCL_COMPILER_MSVC vvv +template +_LIBCUDACXX_CPO_ACCESSIBILITY auto elements = __elements::__fn<_Np>{}; +# endif // !_CCCL_COMPILER_MSVC +_LIBCUDACXX_CPO_ACCESSIBILITY auto keys = elements<0>; +_LIBCUDACXX_CPO_ACCESSIBILITY auto values = elements<1>; +} // namespace __cpo + +_LIBCUDACXX_END_NAMESPACE_VIEWS + +_CCCL_DIAG_POP + +#endif // _CCCL_STD_VER >= 2017 && !defined(_CCCL_COMPILER_MSVC_2017) + +#endif // _LIBCUDACXX___RANGES_ELEMENTS_VIEW_H diff --git a/libcudacxx/include/cuda/std/detail/libcxx/include/ranges b/libcudacxx/include/cuda/std/detail/libcxx/include/ranges index 575b91c60c0..0d25b987b45 100644 --- a/libcudacxx/include/cuda/std/detail/libcxx/include/ranges +++ b/libcudacxx/include/cuda/std/detail/libcxx/include/ranges @@ -116,6 +116,27 @@ namespace std::ranges { template using borrowed_subrange_t = see below; + // [range.elements], elements view + template + requires see below + class elements_view; + + template + inline constexpr bool enable_borrowed_range> = + enable_borrowed_range; + + template + using keys_view = elements_view; + template + using values_view = elements_view; + + namespace views { + template + inline constexpr unspecified elements = unspecified; + inline constexpr auto keys = elements<0>; + inline constexpr auto values = elements<1>; + } + // [range.empty], empty view template requires is_object_v @@ -329,6 +350,7 @@ _CCCL_DIAG_SUPPRESS_MSVC(4848) #include #include #include +#include #include #include #include diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp new file mode 100644 index 00000000000..1d85d7c4474 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp @@ -0,0 +1,236 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// cuda::std::views::elements +// cuda::std::views::keys +// cuda::std::views::values + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +template +struct View : cuda::std::ranges::view_base +{ + __host__ __device__ T* begin() const; + __host__ __device__ T* end() const; +}; + +static_assert(!cuda::std::is_invocable_v) )>); +static_assert(!cuda::std::is_invocable_v) ), View>); +static_assert(cuda::std::is_invocable_v) ), View>>); +static_assert(cuda::std::is_invocable_v) ), View>>); +static_assert(!cuda::std::is_invocable_v) ), View>>); + +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>>); + +#if TEST_STD_VER >= 2020 +template +concept CanBePiped = requires(View&& view, T&& t) { + { + cuda::std::forward(view) | cuda::std::forward(t) + }; +}; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool CanBePiped = false; + +template +inline constexpr bool + CanBePiped() | cuda::std::declval())>> = true; +#endif // TEST_STD_VER <= 2017 +static_assert(!CanBePiped, decltype((cuda::std::views::elements<0>) )>); +static_assert(CanBePiped>, decltype((cuda::std::views::elements<0>) )>); +static_assert(CanBePiped>, decltype((cuda::std::views::elements<0>) )>); +static_assert(!CanBePiped>, decltype((cuda::std::views::elements<5>) )>); + +static_assert(!CanBePiped, decltype((cuda::std::views::keys))>); +static_assert(CanBePiped>, decltype((cuda::std::views::keys))>); +static_assert(CanBePiped>, decltype((cuda::std::views::keys))>); + +static_assert(!CanBePiped, decltype((cuda::std::views::values))>); +static_assert(CanBePiped>, decltype((cuda::std::views::values))>); +static_assert(!CanBePiped>, decltype((cuda::std::views::values))>); + +template +__host__ __device__ constexpr bool equal(Range&& range, Expected&& expected) +{ + auto irange = range.begin(); + auto iexpected = cuda::std::begin(expected); + for (; irange != range.end(); ++irange, ++iexpected) + { + if (*irange != *iexpected) + { + return false; + } + } + return true; +} + +__host__ __device__ constexpr bool test() +{ + cuda::std::pair buff[] = {{1, 2}, {3, 4}, {5, 6}}; + + // Test `views::elements(v)` + { + using Result = cuda::std::ranges::elements_view[3]>, 0>; + decltype(auto) result = cuda::std::views::elements<0>(buff); + static_assert(cuda::std::same_as); + auto expected = {1, 3, 5}; + assert(equal(result, expected)); + } + + // Test `views::keys(v)` + { + using Result = cuda::std::ranges::elements_view[3]>, 0>; + decltype(auto) result = cuda::std::views::keys(buff); + static_assert(cuda::std::same_as); + auto expected = {1, 3, 5}; + assert(equal(result, expected)); + } + + // Test `views::values(v)` + { + using Result = cuda::std::ranges::elements_view[3]>, 1>; + decltype(auto) result = cuda::std::views::values(buff); + static_assert(cuda::std::same_as); + auto expected = {2, 4, 6}; + assert(equal(result, expected)); + } + + // Test `v | views::elements` + { + using Result = cuda::std::ranges::elements_view[3]>, 1>; + decltype(auto) result = buff | cuda::std::views::elements<1>; + static_assert(cuda::std::same_as); + auto expected = {2, 4, 6}; + assert(equal(result, expected)); + } + + // Test `v | views::keys` + { + using Result = cuda::std::ranges::elements_view[3]>, 0>; + decltype(auto) result = buff | cuda::std::views::keys; + static_assert(cuda::std::same_as); + auto expected = {1, 3, 5}; + assert(equal(result, expected)); + } + + // Test `v | views::values` + { + using Result = cuda::std::ranges::elements_view[3]>, 1>; + decltype(auto) result = buff | cuda::std::views::values; + static_assert(cuda::std::same_as); + auto expected = {2, 4, 6}; + assert(equal(result, expected)); + } + + // Test views::elements<0> | views::elements<0> + { + cuda::std::pair, cuda::std::tuple> nested[] = {{{1}, {2}}, {{3}, {4}}, {{5}, {6}}}; + using Result = cuda::std::ranges::elements_view< + cuda::std::ranges:: + elements_view, cuda::std::tuple>[3]>, 0>, + 0>; + auto const partial = cuda::std::views::elements<0> | cuda::std::views::elements<0>; + decltype(auto) result = nested | partial; + static_assert(cuda::std::same_as); + auto expected = {1, 3, 5}; + assert(equal(result, expected)); + } + + // Test views::keys | views::keys + { + cuda::std::pair, cuda::std::tuple> nested[] = {{{1}, {2}}, {{3}, {4}}, {{5}, {6}}}; + using Result = cuda::std::ranges::elements_view< + cuda::std::ranges:: + elements_view, cuda::std::tuple>[3]>, 0>, + 0>; + auto const partial = cuda::std::views::keys | cuda::std::views::keys; + decltype(auto) result = nested | partial; + static_assert(cuda::std::same_as); + auto expected = {1, 3, 5}; + assert(equal(result, expected)); + } + + // Test views::values | views::values + { + cuda::std::pair, cuda::std::tuple> nested[] = { + {{1}, {2, 3}}, {{4}, {5, 6}}, {{7}, {8, 9}}}; + using Result = cuda::std::ranges::elements_view< + cuda::std::ranges::elements_view< + cuda::std::ranges::ref_view, cuda::std::tuple>[3]>, + 1>, + 1>; + auto const partial = cuda::std::views::values | cuda::std::views::values; + decltype(auto) result = nested | partial; + static_assert(cuda::std::same_as); + auto expected = {3, 6, 9}; + assert(equal(result, expected)); + } + + // Test views::keys | views::values + { + cuda::std::pair, cuda::std::tuple> nested[] = { + {{1, 2}, {3}}, {{4, 5}, {6}}, {{7, 8}, {9}}}; + using Result = cuda::std::ranges::elements_view< + cuda::std::ranges::elements_view< + cuda::std::ranges::ref_view, cuda::std::tuple>[3]>, + 0>, + 1>; + auto const partial = cuda::std::views::keys | cuda::std::views::values; + decltype(auto) result = nested | partial; + static_assert(cuda::std::same_as); + auto expected = {2, 5, 8}; + assert(equal(result, expected)); + } + + // Test views::values | views::keys + { + cuda::std::pair, cuda::std::tuple> nested[] = { + {{1}, {2, 3}}, {{4}, {5, 6}}, {{7}, {8, 9}}}; + using Result = cuda::std::ranges::elements_view< + cuda::std::ranges::elements_view< + cuda::std::ranges::ref_view, cuda::std::tuple>[3]>, + 1>, + 0>; + auto const partial = cuda::std::views::values | cuda::std::views::keys; + decltype(auto) result = nested | partial; + static_assert(cuda::std::same_as); + auto expected = {2, 5, 8}; + assert(equal(result, expected)); + } + + return true; +} + +int main(int, char**) +{ + test(); +#if defined(_LIBCUDACXX_ADDRESSOF) && !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + static_assert(test()); +#endif // defined(_LIBCUDACXX_ADDRESSOF) && !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/base.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/base.pass.cpp new file mode 100644 index 00000000000..b316e2485ab --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/base.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr V base() const & requires copy_constructible { return base_; } +// constexpr V base() && { return cuda::std::move(base_); } + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +struct View : cuda::std::ranges::view_base +{ + int i; + __host__ __device__ cuda::std::tuple* begin() const; + __host__ __device__ cuda::std::tuple* end() const; +}; + +struct MoveOnlyView : View +{ + MoveOnly mo; +}; + +#if TEST_STD_VER >= 2020 +template +concept HasBase = requires(T&& t) { cuda::std::forward(t).base(); }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool HasBase = false; + +template +inline constexpr bool HasBase().base())>> = true; +#endif // TEST_STD_VER <= 2017 +static_assert(HasBase const&>); +static_assert(HasBase&&>); + +static_assert(!HasBase const&>); +static_assert(HasBase&&>); + +__host__ __device__ constexpr bool test() +{ + // const & + { + const cuda::std::ranges::elements_view ev{View{{}, 5}}; + decltype(auto) v = ev.base(); + static_assert(cuda::std::same_as); + assert(v.i == 5); + } + + // & + { + cuda::std::ranges::elements_view ev{View{{}, 5}}; + decltype(auto) v = ev.base(); + static_assert(cuda::std::same_as); + assert(v.i == 5); + } + + // && + { + cuda::std::ranges::elements_view ev{View{{}, 5}}; + decltype(auto) v = cuda::std::move(ev).base(); + static_assert(cuda::std::same_as); + assert(v.i == 5); + } + + // const && + { + const cuda::std::ranges::elements_view ev{View{{}, 5}}; + decltype(auto) v = cuda::std::move(ev).base(); + static_assert(cuda::std::same_as); + assert(v.i == 5); + } + + // move only + { + cuda::std::ranges::elements_view ev{MoveOnlyView{{}, 5}}; + decltype(auto) v = cuda::std::move(ev).base(); + static_assert(cuda::std::same_as); + assert(v.mo.get() == 5); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/begin.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/begin.pass.cpp new file mode 100644 index 00000000000..0269a158d47 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/begin.pass.cpp @@ -0,0 +1,131 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr auto begin() requires (!simple-view) +// constexpr auto begin() const requires range + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +#if TEST_STD_VER >= 2020 +template +concept HasConstBegin = requires(const T ct) { ct.begin(); }; + +template +concept HasBegin = requires(T t) { t.begin(); }; + +template +concept HasConstAndNonConstBegin = + HasConstBegin && + // because const begin and non-const begin returns different types (iterator, iterator) + requires(T t, const T ct) { requires !cuda::std::same_as; }; + +template +concept HasOnlyNonConstBegin = HasBegin && !HasConstBegin; + +template +concept HasOnlyConstBegin = HasConstBegin && !HasConstAndNonConstBegin; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool HasConstBegin = false; + +template +inline constexpr bool HasConstBegin().begin())>> = true; + +template +inline constexpr bool HasBegin = false; + +template +inline constexpr bool HasBegin().begin())>> = true; + +template +inline constexpr bool HasConstAndNonConstBegin = false; + +template +inline constexpr bool HasConstAndNonConstBegin< + T, + cuda::std::void_t().begin()), decltype(cuda::std::declval().begin())>>>> = + true; + +template +inline constexpr bool HasOnlyNonConstBegin = HasBegin && !HasConstBegin; + +template +inline constexpr bool HasOnlyConstBegin = HasConstBegin && !HasConstAndNonConstBegin; +#endif // TEST_STD_VER <= 2017 +struct NoConstBeginView : TupleBufferView +{ + DELEGATE_TUPLEBUFFERVIEW(NoConstBeginView) + __host__ __device__ constexpr cuda::std::tuple* begin() + { + return buffer_; + } + __host__ __device__ constexpr cuda::std::tuple* end() + { + return buffer_ + size_; + } +}; + +// simple-view +static_assert(HasOnlyConstBegin>); + +// !simple-view && range +static_assert(HasConstAndNonConstBegin>); + +// !range +static_assert(HasOnlyNonConstBegin>); + +__host__ __device__ constexpr bool test() +{ + cuda::std::tuple buffer[] = {{1}, {2}}; + { + // underlying iterator should be pointing to the first element + auto ev = cuda::std::views::elements<0>(buffer); + auto iter = ev.begin(); + assert(&(*iter) == &cuda::std::get<0>(buffer[0])); + } + + { + // underlying range models simple-view + auto v = cuda::std::views::elements<0>(SimpleCommon{buffer}); + static_assert(cuda::std::is_same_v); + assert(v.begin() == cuda::std::as_const(v).begin()); + auto&& r = *cuda::std::as_const(v).begin(); + assert(&r == &cuda::std::get<0>(buffer[0])); + } + + { + // underlying const R is not a range + auto v = cuda::std::views::elements<0>(NoConstBeginView{buffer}); + auto&& r = *v.begin(); + assert(&r == &cuda::std::get<0>(buffer[0])); + } + + return true; +} + +int main(int, char**) +{ + test(); +#if defined(_LIBCUDACXX_ADDRESSOF) + static_assert(test()); +#endif // defined(_LIBCUDACXX_ADDRESSOF) + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/borrowed.compile.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/borrowed.compile.pass.cpp new file mode 100644 index 00000000000..a9f2be1ccfc --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/borrowed.compile.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 +// +// template +// inline constexpr bool enable_borrowed_range> = +// enable_borrowed_range; + +#include +#include + +struct NonBorrowed : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() + { + return nullptr; + } + __host__ __device__ cuda::std::tuple* end() + { + return nullptr; + } +}; + +struct Borrowed : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() + { + return nullptr; + } + __host__ __device__ cuda::std::tuple* end() + { + return nullptr; + } +}; + +template <> +inline constexpr bool cuda::std::ranges::enable_borrowed_range = true; + +static_assert(!cuda::std::ranges::borrowed_range>); +static_assert(cuda::std::ranges::borrowed_range>); + +int main(int, char**) +{ + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp new file mode 100644 index 00000000000..8ef8b8b1b39 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// elements_view() requires default_initializable = default; + +#include +#include +#include +#include + +template +struct View : cuda::std::ranges::view_base +{ + int i = 42; + template = 0> + __host__ __device__ constexpr explicit View() noexcept + {} + __host__ __device__ cuda::std::tuple* begin() const; + __host__ __device__ cuda::std::tuple* end() const; +}; + +// clang-format off +static_assert( cuda::std::is_default_constructible_v, 0>>); +static_assert(!cuda::std::is_default_constructible_v, 0>>); +// clang-format on + +__host__ __device__ constexpr bool test() +{ + { + cuda::std::ranges::elements_view, 0> ev = {}; + assert(ev.base().i == 42); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp new file mode 100644 index 00000000000..592555ef934 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr explicit elements_view(V base); + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct View : cuda::std::ranges::view_base +{ + MoveOnly mo; + __host__ __device__ cuda::std::tuple* begin() const; + __host__ __device__ cuda::std::tuple* end() const; +}; + +// Test Explicit +static_assert(cuda::std::is_constructible_v, View>); +static_assert(!cuda::std::is_convertible_v>); + +__host__ __device__ constexpr bool test() +{ + { + cuda::std::ranges::elements_view ev{View{{}, MoveOnly{5}}}; + assert(cuda::std::move(ev).base().mo.get() == 5); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/end.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/end.pass.cpp new file mode 100644 index 00000000000..37b0f6e5555 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/end.pass.cpp @@ -0,0 +1,167 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr auto end() requires (!simple-view && !common_range) +// constexpr auto end() requires (!simple-view && common_range) +// constexpr auto end() const requires range +// constexpr auto end() const requires common_range + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +// | simple | common | v.end() | as_const(v) +// | | | | .end() +// |--------|--------|------------------|--------------- +// | Y | Y | iterator | iterator +// | Y | N | sentinel | sentinel +// | N | Y | iterator | iterator +// | N | N | sentinel | sentinel + +// !range +#if TEST_STD_VER >= 2020 +template +concept HasEnd = requires(T t) { t.end(); }; + +template +concept HasConstEnd = requires(const T ct) { ct.end(); }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool HasEnd = false; + +template +inline constexpr bool HasEnd().end())>> = true; + +template +inline constexpr bool HasConstEnd = false; + +template +inline constexpr bool HasConstEnd().end())>> = true; +#endif // TEST_STD_VER <= 2017 +struct NoConstEndView : TupleBufferView +{ + DELEGATE_TUPLEBUFFERVIEW(NoConstEndView) + __host__ __device__ constexpr cuda::std::tuple* begin() + { + return buffer_; + } + __host__ __device__ constexpr cuda::std::tuple* end() + { + return buffer_ + size_; + } +}; + +static_assert(HasEnd>); +static_assert(!HasConstEnd>); + +__host__ __device__ constexpr bool test() +{ + cuda::std::tuple buffer[] = {{1}, {2}, {3}}; + + // simple-view && common_view + { + SimpleCommon v{buffer}; + auto ev = cuda::std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = cuda::std::as_const(ev).begin(); + decltype(auto) const_st = cuda::std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // Both iterator + static_assert(cuda::std::same_as); + static_assert(cuda::std::same_as); + static_assert(cuda::std::same_as); + } + + // simple-view && !common_view + { + SimpleNonCommon v{buffer}; + auto ev = cuda::std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = cuda::std::as_const(ev).begin(); + decltype(auto) const_st = cuda::std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // Both iterator + static_assert(cuda::std::same_as); + static_assert(!cuda::std::same_as); + static_assert(!cuda::std::same_as); + } + + // !simple-view && common_view + { + NonSimpleCommon v{buffer}; + auto ev = cuda::std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = cuda::std::as_const(ev).begin(); + decltype(auto) const_st = cuda::std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // iterator and iterator + static_assert(!cuda::std::same_as); + static_assert(cuda::std::same_as); + static_assert(cuda::std::same_as); + } + + // !simple-view && !common_view + { + NonSimpleNonCommon v{buffer}; + auto ev = cuda::std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = cuda::std::as_const(ev).begin(); + decltype(auto) const_st = cuda::std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // sentinel and sentinel + static_assert(!cuda::std::same_as); + static_assert(!cuda::std::same_as); + static_assert(!cuda::std::same_as); + } + + // LWG 3406 elements_view::begin() and elements_view::end() have incompatible constraints + { + cuda::std::tuple x[] = {{0, 0}}; + cuda::std::ranges::subrange r = {cuda::std::counted_iterator(x, 1), cuda::std::default_sentinel}; + auto v = r | cuda::std::views::elements<0>; + assert(v.begin() != v.end()); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/arithmetic.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/arithmetic.pass.cpp new file mode 100644 index 00000000000..e74f16308c3 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/arithmetic.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr iterator& operator+=(difference_type n) +// requires random_access_range; +// +// constexpr iterator& operator-=(difference_type n) +// requires random_access_range; +// +// friend constexpr iterator operator+(const iterator& x, difference_type y) +// requires random_access_range; +// +// friend constexpr iterator operator+(difference_type x, const iterator& y) +// requires random_access_range; +// +// friend constexpr iterator operator-(const iterator& x, difference_type y) +// requires random_access_range; +// +// friend constexpr difference_type operator-(const iterator& x, const iterator& y) +// requires sized_sentinel_for, iterator_t>; + +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +#if TEST_STD_VER >= 2020 +template +concept CanPlus = requires(T t, U u) { t + u; }; + +template +concept CanPlusEqual = requires(T t, U u) { t += u; }; + +template +concept CanMinus = requires(T t, U u) { t - u; }; + +template +concept CanMinusEqual = requires(T t, U u) { t -= u; }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +constexpr bool CanPlus = false; + +template +constexpr bool CanPlus() + cuda::std::declval())>> = true; + +template +constexpr bool CanPlusEqual = false; + +template +constexpr bool CanPlusEqual() += cuda::std::declval())>> = + true; + +template +constexpr bool CanMinus = false; + +template +constexpr bool CanMinus() - cuda::std::declval())>> = true; + +template +constexpr bool CanMinusEqual = false; + +template +constexpr bool CanMinusEqual() -= cuda::std::declval())>> = + true; +#endif // TEST_STD_VER <= 2017 +template +using ElemIter = cuda::std::ranges::iterator_t>; + +using RandomAccessRange = cuda::std::ranges::subrange*>; +static_assert(cuda::std::ranges::random_access_range); +static_assert(cuda::std::sized_sentinel_for, // + cuda::std::ranges::iterator_t>); + +static_assert(CanPlus, int>); +static_assert(CanPlus>); +static_assert(CanPlusEqual, int>); +static_assert(CanMinus, int>); +static_assert(CanMinus, ElemIter>); +static_assert(CanMinusEqual, int>); + +using BidiRange = cuda::std::ranges::subrange*>>; +static_assert(!cuda::std::ranges::random_access_range); +static_assert(!cuda::std::sized_sentinel_for, // + cuda::std::ranges::iterator_t>); + +static_assert(!CanPlus, int>); +static_assert(!CanPlus>); +static_assert(!CanPlusEqual, int>); +static_assert(!CanMinus, int>); +static_assert(!CanMinus, ElemIter>); +static_assert(!CanMinusEqual, int>); + +__host__ __device__ constexpr bool test() +{ + cuda::std::tuple ts[] = {{1}, {2}, {3}, {4}}; + + RandomAccessRange r{&ts[0], &ts[0] + 4}; + auto ev = r | cuda::std::views::elements<0>; + { + // operator+(x, n) operator+(n,x) and operator+= + auto it1 = ev.begin(); + + auto it2 = it1 + 3; + assert(it2.base() == &ts[3]); + + auto it3 = 3 + it1; + assert(it3.base() == &ts[3]); + + it1 += 3; + assert(it1 == it2); + assert(it1.base() == &ts[3]); + } + + { + // operator-(x, n) and operator-= + auto it1 = ev.end(); + + auto it2 = it1 - 3; + assert(it2.base() == &ts[1]); + + it1 -= 3; + assert(it1 == it2); + assert(it1.base() == &ts[1]); + } + + { + // operator-(x, y) + assert((ev.end() - ev.begin()) == 4); + + auto it1 = ev.begin() + 2; + auto it2 = ev.end() - 1; + assert((it1 - it2) == -1); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp new file mode 100644 index 00000000000..da163c2d3cf --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr const iterator_t& base() const & noexcept; +// constexpr iterator_t base() &&; + +#include +#include +#include +#include +#include + +#include "../types.h" +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Noexcept +#if TEST_STD_VER >= 2020 +template +concept IsBaseNoexcept = requires { + { + cuda::std::declval().base() + } noexcept; +}; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool IsBaseNoexcept = false; + +template +inline constexpr bool IsBaseNoexcept().base())>> = + noexcept(cuda::std::declval().base()); +#endif // TEST_STD_VER <= 2017 +using BaseView = cuda::std::ranges::subrange*>; +using ElementsIter = cuda::std::ranges::iterator_t>; + +static_assert(IsBaseNoexcept); +static_assert(IsBaseNoexcept); +static_assert(IsBaseNoexcept); +#if !defined(TEST_COMPILER_ICC) // broken noexcept +static_assert(!IsBaseNoexcept); +#endif // TEST_COMPILER_ICC + +struct MoveOnlyIter : IterBase +{ + MoveOnly mo; +}; +struct Sent +{ + __host__ __device__ friend constexpr bool operator==(const Sent&, const MoveOnlyIter&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const MoveOnlyIter&, const Sent&) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(const Sent&, const MoveOnlyIter&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const MoveOnlyIter&, const Sent&) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +__host__ __device__ constexpr bool test() +{ + cuda::std::tuple t{5}; + + // const & + { + const ElementsIter it{&t}; + decltype(auto) base = it.base(); + static_assert(cuda::std::is_same_v* const&>); + assert(base == &t); + } + + // & + { + ElementsIter it{&t}; + decltype(auto) base = it.base(); + static_assert(cuda::std::is_same_v* const&>); + assert(base == &t); + } + + // && + { + ElementsIter it{&t}; + decltype(auto) base = cuda::std::move(it).base(); + static_assert(cuda::std::is_same_v*>); + assert(base == &t); + } + + // const && + { + const ElementsIter it{&t}; + decltype(auto) base = cuda::std::move(it).base(); + static_assert(cuda::std::is_same_v* const&>); + assert(base == &t); + } + + // move only + { + using MoveOnlyElemIter = + cuda::std::ranges::iterator_t, 0>>; + + MoveOnlyElemIter it{MoveOnlyIter{{}, MoveOnly{5}}}; + decltype(auto) base = cuda::std::move(it).base(); + static_assert(cuda::std::is_same_v); + assert(base.mo.get() == 5); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/compare.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/compare.pass.cpp new file mode 100644 index 00000000000..43e10029c90 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/compare.pass.cpp @@ -0,0 +1,172 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// friend constexpr bool operator==(const iterator& x, const iterator& y) +// requires equality_comparable>; +// friend constexpr bool operator<(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator>(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator<=(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator>=(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr auto operator<=>(const iterator& x, const iterator& y) +// requires random_access_range && three_way_comparable>; + +#include +#include +#include +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +# include +#endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + +#include "test_iterators.h" +#include "test_macros.h" + +template +__host__ __device__ constexpr void compareOperatorTest(const Iter1& iter1, const Iter2& iter2) +{ + assert(!(iter1 < iter1)); + assert(iter1 < iter2); + assert(!(iter2 < iter1)); + + assert(iter1 <= iter1); + assert(iter1 <= iter2); + assert(!(iter2 <= iter1)); + + assert(!(iter1 > iter1)); + assert(!(iter1 > iter2)); + assert(iter2 > iter1); + + assert(iter1 >= iter1); + assert(!(iter1 >= iter2)); + assert(iter2 >= iter1); + + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + + assert(!(iter1 != iter1)); + assert(iter1 != iter2); + assert(!(iter2 != iter2)); +} + +template +__host__ __device__ constexpr void inequalityOperatorsDoNotExistTest(const Iter1& iter1, const Iter2& iter2) +{ + static_assert(!cuda::std::is_invocable_v, Iter1, Iter2>); + static_assert(!cuda::std::is_invocable_v, Iter1, Iter2>); + static_assert(!cuda::std::is_invocable_v, Iter1, Iter2>); + static_assert(!cuda::std::is_invocable_v, Iter1, Iter2>); +} + +__host__ __device__ constexpr bool test() +{ + cuda::std::tuple ts[] = {{1}, {2}, {3}}; + +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR + { + // Test a new-school iterator with operator<=>; the iterator should also have operator<=>. + using It = three_way_contiguous_iterator*>; + using Subrange = cuda::std::ranges::subrange; + static_assert(cuda::std::three_way_comparable); + using R = cuda::std::ranges::elements_view; + static_assert(cuda::std::three_way_comparable>); + + auto ev = Subrange{It{&ts[0]}, It{&ts[0] + 3}} | cuda::std::views::elements<0>; + auto iter1 = ev.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + + assert((iter1 <=> iter2) == cuda::std::strong_ordering::less); + assert((iter1 <=> iter1) == cuda::std::strong_ordering::equal); + assert((iter2 <=> iter1) == cuda::std::strong_ordering::greater); + } +#endif // !TEST_HAS_NO_SPACESHIP_OPERATOR + + { + // Test an old-school iterator with no operator<=>; the elements view iterator shouldn't have + // operator<=> either. + using It = random_access_iterator*>; + using Subrange = cuda::std::ranges::subrange; +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR + static_assert(!cuda::std::three_way_comparable); + using R = cuda::std::ranges::elements_view; + static_assert(!cuda::std::three_way_comparable>); +#endif // !TEST_HAS_NO_SPACESHIP_OPERATOR + + auto ev = Subrange{It{ts}, It{ts + 3}} | cuda::std::views::elements<0>; + auto iter1 = ev.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + } + + { + // non random_access_range + using It = bidirectional_iterator*>; + using Subrange = cuda::std::ranges::subrange; +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR + static_assert(!cuda::std::ranges::random_access_range); + using R = cuda::std::ranges::elements_view; + static_assert(!cuda::std::three_way_comparable>); +#endif // !TEST_HAS_NO_SPACESHIP_OPERATOR + + auto ev = Subrange{It{ts}, It{ts + 1}} | cuda::std::views::elements<0>; + + auto it1 = ev.begin(); + auto it2 = ev.end(); + + assert(it1 == it1); + assert(!(it1 != it1)); + assert(it2 == it2); + assert(!(it2 != it2)); + + assert(it1 != it2); + + ++it1; + assert(it1 == it2); + + inequalityOperatorsDoNotExistTest(it1, it2); + } + + { + // underlying iterator does not support == + using It = cpp20_input_iterator*>; + using Sent = sentinel_wrapper; + using Subrange = cuda::std::ranges::subrange; +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR + using R = cuda::std::ranges::elements_view; + static_assert(!cuda::std::three_way_comparable>); +#endif // !TEST_HAS_NO_SPACESHIP_OPERATOR + + auto ev = Subrange{It{ts}, Sent{It{ts + 1}}} | cuda::std::views::elements<0>; + auto it = ev.begin(); + + using ElemIter = decltype(it); + static_assert(!cuda::std::invocable, ElemIter, ElemIter>); + static_assert(!cuda::std::invocable, ElemIter, ElemIter>); + inequalityOperatorsDoNotExistTest(it, it); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp new file mode 100644 index 00000000000..c9d1b5f0ad7 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr explicit iterator(iterator_t current); + +#include +#include +#include + +#include "../types.h" + +// Test explicit +using BaseIter = cuda::std::tuple*; +using ElementsIter = + cuda::std::ranges::iterator_t, 0>>; + +static_assert(cuda::std::is_constructible_v); +static_assert(!cuda::std::is_convertible_v); + +struct TracedMoveIter : IterBase +{ + bool moved = false; + + constexpr TracedMoveIter() = default; + constexpr TracedMoveIter(const TracedMoveIter&) = default; + __host__ __device__ constexpr TracedMoveIter(TracedMoveIter&&) + : moved{true} + {} + constexpr TracedMoveIter& operator=(TracedMoveIter&&) = default; + constexpr TracedMoveIter& operator=(const TracedMoveIter&) = default; +}; + +struct TracedMoveView : cuda::std::ranges::view_base +{ + __host__ __device__ TracedMoveIter begin() const + { + return TracedMoveIter{}; + } + __host__ __device__ TracedMoveIter end() const + { + return TracedMoveIter{}; + } +}; + +__host__ __device__ constexpr bool test() +{ + using Iter = cuda::std::ranges::iterator_t>; + Iter iter{TracedMoveIter{}}; + assert(iter.base().moved); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.default.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.default.pass.cpp new file mode 100644 index 00000000000..09b1f71a231 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.default.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// iterator() requires default_initializable> = default; + +#include +#include + +#include "../types.h" + +struct PODIter : IterBase +{ + int i; // deliberately uninitialised +}; + +struct IterDefaultCtrView : cuda::std::ranges::view_base +{ + __host__ __device__ PODIter begin() const + { + return PODIter{}; + } + __host__ __device__ PODIter end() const + { + return PODIter{}; + } +}; + +struct IterNoDefaultCtrView : cuda::std::ranges::view_base +{ + __host__ __device__ cpp20_input_iterator*> begin() const + { + return cpp20_input_iterator*>{nullptr}; + } + __host__ __device__ sentinel_wrapper*>> end() const + { + return sentinel_wrapper*>>{}; + } +}; + +template +using ElementsIter = cuda::std::ranges::iterator_t>; + +static_assert(!cuda::std::default_initializable>); +static_assert(cuda::std::default_initializable>); + +__host__ __device__ constexpr bool test() +{ + using Iter = ElementsIter; + { + Iter iter; + assert(iter.base().i == 0); // PODIter has to be initialised to have value 0 + } + + { + Iter iter = {}; + assert(iter.base().i == 0); // PODIter has to be initialised to have value 0 + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp new file mode 100644 index 00000000000..4f9b14dc70d --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp @@ -0,0 +1,96 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr iterator(iterator i) +// requires Const && convertible_to, iterator_t>; + +#include +#include +#include + +#include "../types.h" + +template +struct ConvertibleIter : IterBase> +{ + using iterator_category = cuda::std::random_access_iterator_tag; + using value_type = cuda::std::tuple; + using difference_type = intptr_t; + + bool movedFromOtherConst = false; + int i = 0; + + constexpr ConvertibleIter() = default; + __host__ __device__ constexpr ConvertibleIter(int ii) + : i(ii) + {} + template = 0> + __host__ __device__ constexpr ConvertibleIter(ConvertibleIter it) + : movedFromOtherConst(true) + , i(it.i) + {} +}; + +template +struct BasicView : cuda::std::ranges::view_base +{ + __host__ __device__ Iter begin() + { + return Iter{}; + } + __host__ __device__ Iter end() + { + return Iter{}; + } + + __host__ __device__ ConstIter begin() const + { + return ConstIter{}; + } + __host__ __device__ ConstIter end() const + { + return ConstIter{}; + } +}; + +template +using ElemIter = cuda::std::ranges::iterator_t>; + +template +using ConstElemIter = cuda::std::ranges::iterator_t>; + +using ConvertibleView = BasicView, ConvertibleIter>; +using NonConvertibleView = + BasicView*>, bidirectional_iterator*>>; + +static_assert(cuda::std::is_constructible_v, ElemIter>); +static_assert(!cuda::std::is_constructible_v, ConstElemIter>); +static_assert(!cuda::std::is_constructible_v, ElemIter>); +static_assert(!cuda::std::is_constructible_v, ConstElemIter>); + +__host__ __device__ constexpr bool test() +{ + ElemIter iter{ConvertibleIter{5}}; + ConstElemIter constIter = iter; // implicit + assert(constIter.base().movedFromOtherConst); + assert(constIter.base().i == 5); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/decrement.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/decrement.pass.cpp new file mode 100644 index 00000000000..476ca538b43 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/decrement.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr iterator& operator--() requires bidirectional_range; +// constexpr iterator operator--(int) requires bidirectional_range; + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +#if TEST_STD_VER >= 2020 +template +concept CanPreDecrement = requires(T& t) { --t; }; + +template +concept CanPostDecrement = requires(T& t) { t--; }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool CanPreDecrement = false; + +template +inline constexpr bool CanPreDecrement())>> = true; + +template +inline constexpr bool CanPostDecrement = false; + +template +inline constexpr bool CanPostDecrement()--)>> = true; +#endif // TEST_STD_VER <= 2017 +template > +__host__ __device__ constexpr void testOne() +{ + using Range = cuda::std::ranges::subrange; + cuda::std::tuple ts[] = {{1}, {2}, {3}}; + auto ev = Range{Iter{ts}, Sent{Iter{ts + 3}}} | cuda::std::views::elements<0>; + using ElementIter = cuda::std::ranges::iterator_t; + + if constexpr (!cuda::std::bidirectional_iterator) + { + auto it = ev.begin(); + static_assert(!CanPreDecrement); + static_assert(!CanPostDecrement); + } + else + { + // --i + { + auto it = ev.begin(); + static_assert(CanPreDecrement); + + ++it; + assert(base(it.base()) == &ts[1]); + + decltype(auto) result = --it; + + static_assert(cuda::std::is_same_v); + assert(&result == &it); + + assert(base(it.base()) == &ts[0]); + } + + // i-- + { + auto it = ev.begin(); + static_assert(CanPostDecrement); + + ++it; + assert(base(it.base()) == &ts[1]); + + decltype(auto) result = it--; + + static_assert(cuda::std::is_same_v); + + assert(base(it.base()) == &ts[0]); + assert(base(result.base()) == &ts[1]); + } + } +} + +__host__ __device__ constexpr bool test() +{ + using Ptr = cuda::std::tuple*; + testOne>(); + testOne>(); + testOne>(); + testOne>(); + testOne>(); + testOne(); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/deref.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/deref.pass.cpp new file mode 100644 index 00000000000..5cdf45308e2 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/deref.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr decltype(auto) operator*() const; + +#include +#include +#include +#include +#include + +template +__host__ __device__ constexpr void testReference(T (&ts)[Size]) +{ + auto ev = ts | cuda::std::views::elements; + auto it = ev.begin(); + + decltype(auto) result = *it; + using ExpectedType = decltype(cuda::std::get(ts[0])); + static_assert(cuda::std::is_same_v); + + if constexpr (cuda::std::is_reference_v) + { + // tuple/array/pair + assert(&result == &cuda::std::get(ts[0])); + } + else + { + // subrange + assert(result == cuda::std::get(ts[0])); + } +} + +// LWG 3502 elements_view should not be allowed to return dangling references +template +__host__ __device__ constexpr void testValue(T t) +{ + auto ev = cuda::std::views::iota(0, 1) | cuda::std::views::transform([&t](int) { + return t; + }) + | cuda::std::views::elements; + auto it = ev.begin(); + + decltype(auto) result = *it; + using ExpectedType = cuda::std::remove_cvref_t(t))>; + static_assert(cuda::std::is_same_v); + + assert(result == cuda::std::get(t)); +} + +__host__ __device__ constexpr bool test() +{ + // test tuple + { + cuda::std::tuple ts[] = {{1, short(2), 3}, {4, short(5), 6}}; + testReference<0>(ts); + testReference<1>(ts); + testReference<2>(ts); + testValue<0>(ts[0]); + testValue<1>(ts[0]); + testValue<2>(ts[0]); + } + + // test pair + { + cuda::std::pair ps[] = {{1, short(2)}, {4, short(5)}}; + testReference<0>(ps); + testReference<1>(ps); + testValue<0>(ps[0]); + testValue<1>(ps[0]); + } + + // test array + { + cuda::std::array arrs[] = {{1, 2, 3}, {3, 4, 5}}; + testReference<0>(arrs); + testReference<1>(arrs); + testReference<2>(arrs); + testValue<0>(arrs[0]); + testValue<1>(arrs[0]); + testValue<2>(arrs[0]); + } + + // test subrange + { + int i = 5; + cuda::std::ranges::subrange srs[] = {{&i, &i}, {&i, &i}}; + testReference<0>(srs); + testReference<1>(srs); + testValue<0>(srs[0]); + testValue<1>(srs[0]); + } + + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER >= 2020 + static_assert(test()); +#endif // TEST_STD_VER >= 2020 + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp new file mode 100644 index 00000000000..a22bb4f3b1f --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr iterator& operator++(); +// constexpr void operator++(int); +// constexpr iterator operator++(int) requires forward_range; + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +template > +__host__ __device__ constexpr void testOne() +{ + using Range = cuda::std::ranges::subrange; + cuda::std::tuple ts[] = {{1}, {2}, {3}}; + auto ev = Range{Iter{ts}, Sent{Iter{ts + 3}}} | cuda::std::views::elements<0>; + using ElementIter = cuda::std::ranges::iterator_t; + + { // ++i + auto it = ev.begin(); + decltype(auto) result = ++it; + + static_assert(cuda::std::is_same_v); + assert(&result == &it); + + assert(base(it.base()) == &ts[1]); + } + + { // i++ + if constexpr (cuda::std::forward_iterator) + { + auto it = ev.begin(); + decltype(auto) result = it++; + + static_assert(cuda::std::is_same_v); + + assert(base(it.base()) == &ts[1]); + assert(base(result.base()) == &ts[0]); + } + else + { + auto it = ev.begin(); + it++; + + static_assert(cuda::std::is_same_v); + assert(base(it.base()) == &ts[1]); + } + } +} + +__host__ __device__ constexpr bool test() +{ + using Ptr = cuda::std::tuple*; +#if !defined(TEST_COMPILER_CLANG) || TEST_STD_VER >= 2020 // clang ICEs on the rvalue subrange + testOne>(); +#endif // !clang || C++20 + testOne>(); + testOne>(); + testOne>(); + testOne>(); + testOne(); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/member_types.compile.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/member_types.compile.pass.cpp new file mode 100644 index 00000000000..7897dbe6072 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/member_types.compile.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// Member typedefs in elements_view::iterator. + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +template +using Range = cuda::std::ranges::subrange>; + +template +using ElementsIter = cuda::std::ranges::iterator_t>; + +// using iterator_concept = see below; +static_assert(cuda::std::same_as*>>>::iterator_concept, + cuda::std::input_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_concept, // + cuda::std::forward_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_concept, + cuda::std::bidirectional_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_concept, + cuda::std::random_access_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_concept, + cuda::std::random_access_iterator_tag>); + +static_assert(cuda::std::same_as*>>::iterator_concept, // + cuda::std::random_access_iterator_tag>); + +// using iterator_category = see below; // not always present +#if TEST_STD_VER >= 2020 +template +concept HasIterCategory = requires { typename T::iterator_category; }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool HasIterCategory = false; + +template +inline constexpr bool HasIterCategory> = true; +#endif // TEST_STD_VER <= 2017 +static_assert(!HasIterCategory*>>>>); +static_assert(HasIterCategory*>>>>); + +static_assert(cuda::std::same_as*>>>::iterator_category, + cuda::std::forward_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_category, + cuda::std::bidirectional_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_category, + cuda::std::random_access_iterator_tag>); + +static_assert(cuda::std::same_as*>>>::iterator_category, + cuda::std::random_access_iterator_tag>); + +static_assert(cuda::std::same_as*>>::iterator_category, // + cuda::std::random_access_iterator_tag>); + +struct ToPair +{ + __host__ __device__ constexpr auto operator()(int) const noexcept + { + return cuda::std::pair{1, static_cast(1)}; + } +}; +using Generator = decltype(cuda::std::views::iota(0, 1) | cuda::std::views::transform(ToPair{})); +#ifndef TEST_COMPILER_CUDACC_BELOW_11_3 +static_assert(cuda::std::ranges::random_access_range); +#endif // !TEST_COMPILER_CUDACC_BELOW_11_3 + +static_assert(cuda::std::same_as::iterator_category, // + cuda::std::input_iterator_tag>); + +// using value_type = remove_cvref_t>>; +static_assert(cuda::std::same_as*>, 0>::value_type, int>); + +static_assert(cuda::std::same_as*>, 1>::value_type, long>); + +static_assert(cuda::std::same_as::value_type, int>); + +static_assert(cuda::std::same_as::value_type, short>); + +// using difference_type = range_difference_t; +static_assert(cuda::std::same_as*>>::difference_type, + cuda::std::ranges::range_difference_t*>>>); + +static_assert(cuda::std::same_as::difference_type, // + cuda::std::ranges::range_difference_t>); + +int main(int, char**) +{ + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/subscript.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/subscript.pass.cpp new file mode 100644 index 00000000000..0b44418aa22 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/iterator/subscript.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr decltype(auto) operator[](difference_type n) const +// requires random_access_range + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +#if TEST_STD_VER >= 2020 +template +concept CanSubscript = requires(T t, U u) { t[u]; }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool CanSubscript = false; + +template +inline constexpr bool CanSubscript()[cuda::std::declval()])>> = + true; +#endif // TEST_STD_VER <= 2017 +template +using ElemIter = cuda::std::ranges::iterator_t>; + +using RandomAccessRange = cuda::std::ranges::subrange*>; +static_assert(cuda::std::ranges::random_access_range); + +static_assert(CanSubscript, int>); + +using BidiRange = cuda::std::ranges::subrange*>>; +static_assert(!cuda::std::ranges::random_access_range); + +static_assert(!CanSubscript, int>); + +__host__ __device__ constexpr bool test() +{ + { + // reference + cuda::std::tuple ts[] = {{1}, {2}, {3}, {4}}; + auto ev = ts | cuda::std::views::elements<0>; + auto it = ev.begin(); + + assert(&it[0] == &*it); + assert(&it[2] == &*(it + 2)); + + static_assert(cuda::std::is_same_v); + } + + { + // value + auto ev = cuda::std::views::iota(0, 5) | cuda::std::views::transform([](int i) { + return cuda::std::tuple{i}; + }) + | cuda::std::views::elements<0>; + auto it = ev.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + + static_assert(cuda::std::is_same_v); + } + + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER >= 2020 && defined(_LIBCUDACXX_ADDRESSOF) + static_assert(test()); +#endif // TEST_STD_VER >= 2020 && defined(_LIBCUDACXX_ADDRESSOF) + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp new file mode 100644 index 00000000000..3ffcfc406a9 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// concept checking +// +// template +// concept has-tuple-element = +// tuple-like && N < tuple_size_v; +// +// template +// concept returnable-element = +// is_reference_v || move_constructible>; +// +// template +// requires view && has-tuple-element, N> && +// has-tuple-element>, N> && +// returnable-element, N> +// class elements_view; + +#include +#include +#include +#include +#include + +#include "test_iterators.h" + +template +using Range = cuda::std::ranges::subrange>; + +#if TEST_STD_VER >= 2020 +template +concept HasElementsView = requires { typename cuda::std::ranges::elements_view; }; +#else // ^^^ C++20 ^^^ / vvv C++17 vvv +template +inline constexpr bool HasElementsView = false; + +template +inline constexpr bool HasElementsView>> = true; +#endif // TEST_STD_VER <= 2017 +static_assert(HasElementsView*>, 0>); +static_assert(HasElementsView*>, 1>); +static_assert(HasElementsView*>, 2>); +static_assert(HasElementsView*>, 3>); + +// !view +static_assert(!cuda::std::ranges::view, 1>>); +static_assert(!HasElementsView, 1>, 0>); + +// !input_range +static_assert(!cuda::std::ranges::input_range*>>>); +static_assert(!HasElementsView*>>, 0>); + +// !tuple-like +LIBCPP_STATIC_ASSERT(!cuda::std::__tuple_like::value); +static_assert(!HasElementsView, 1>); + +// !(N < tuple_size_v) +static_assert(!(2 < cuda::std::tuple_size_v>) ); +static_assert(!HasElementsView*>, 2>); + +// ! (is_reference_v || move_constructible>) +struct NonMovable +{ + __host__ __device__ constexpr NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; +static_assert(!cuda::std::move_constructible); + +struct ToPair +{ + __host__ __device__ constexpr auto operator()(int) const noexcept + { + return cuda::std::pair{1, 1}; + } +}; + +using NonMovableGenerator = decltype(cuda::std::views::iota(0, 1) | cuda::std::views::transform(ToPair{})); + +static_assert(!HasElementsView); +static_assert(HasElementsView); + +int main(int, char**) +{ + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp new file mode 100644 index 00000000000..2a3544cd669 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr sentinel_t base() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Sent +{ + int i; + + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const Sent&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const Sent&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const Sent&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const Sent&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +__host__ __device__ constexpr bool test() +{ + using BaseRange = cuda::std::ranges::subrange*, Sent>; + using EleRange = cuda::std::ranges::elements_view; + using EleSent = cuda::std::ranges::sentinel_t; + + const EleSent st{Sent{5}}; + decltype(auto) base = st.base(); + static_assert(cuda::std::same_as); + assert(base.i == 5); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp new file mode 100644 index 00000000000..d7ea9675c0c --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr explicit sentinel(sentinel_t end); + +#include +#include +#include +#include + +#include "test_macros.h" + +struct Sent +{ + int i; + + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const Sent&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const Sent&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const Sent&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const Sent&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +struct Range : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() const + { + return nullptr; + } + __host__ __device__ Sent end() + { + return Sent{}; + } +}; + +// Test explicit + +static_assert( + cuda::std::is_constructible_v>, Sent>); +static_assert( + !cuda::std::is_convertible_v>>); + +__host__ __device__ constexpr bool test() +{ + // base is init correctly + { + using R = cuda::std::ranges::elements_view; + using Sentinel = cuda::std::ranges::sentinel_t; + + Sentinel s1(Sent{5}); + assert(s1.base().i == 5); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp new file mode 100644 index 00000000000..8ef7e7f2d1b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// constexpr sentinel(sentinel s) +// requires Const && convertible_to, sentinel_t>; + +#include +#include +#include + +#include "../types.h" +#include "test_macros.h" + +struct Sent +{ + int i; + Sent() = default; + __host__ __device__ constexpr Sent(int ii) + : i(ii) + {} + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const Sent&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const Sent&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const Sent&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const Sent&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +struct ConstSent +{ + int i; + ConstSent() = default; + __host__ __device__ constexpr ConstSent(int ii) + : i(ii) + {} + __host__ __device__ constexpr ConstSent(const Sent& s) + : i(s.i) + {} + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const ConstSent&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const ConstSent&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const ConstSent&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const ConstSent&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +struct Range : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() const + { + return nullptr; + } + __host__ __device__ Sent end() + { + return Sent{}; + } + __host__ __device__ ConstSent end() const + { + return ConstSent{}; + } +}; + +struct NonConvertConstSent +{ + int i; + NonConvertConstSent() = default; + __host__ __device__ constexpr NonConvertConstSent(int ii) + : i(ii) + {} + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const NonConvertConstSent&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const NonConvertConstSent&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const NonConvertConstSent&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const NonConvertConstSent&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +struct NonConvertConstSentRange : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() const + { + return nullptr; + } + __host__ __device__ Sent end() + { + return Sent{}; + } + __host__ __device__ NonConvertConstSent end() const + { + return NonConvertConstSent{}; + } +}; + +// Test Constraint +static_assert( + cuda::std::is_constructible_v>, + cuda::std::ranges::sentinel_t>>); + +// !Const +static_assert( + !cuda::std::is_constructible_v>, + cuda::std::ranges::sentinel_t>>); + +// !convertible_to, sentinel_t> +static_assert(!cuda::std::is_constructible_v< + cuda::std::ranges::sentinel_t>, + cuda::std::ranges::sentinel_t>>); + +__host__ __device__ constexpr bool test() +{ + // base is init correctly + { + using R = cuda::std::ranges::elements_view; + using Sentinel = cuda::std::ranges::sentinel_t; + using ConstSentinel = cuda::std::ranges::sentinel_t; + static_assert(!cuda::std::same_as); + + Sentinel s1(Sent{5}); + ConstSentinel s2 = s1; + assert(s2.base().i == 5); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.default.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.default.pass.cpp new file mode 100644 index 00000000000..b40084c29f9 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/ctor.default.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// sentinel() = default; + +#include +#include +#include + +#include "test_macros.h" + +struct PODSentinel +{ + int i; // deliberately uninitialised + + __host__ __device__ friend constexpr bool operator==(cuda::std::tuple*, const PODSentinel&) + { + return true; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const PODSentinel&, cuda::std::tuple*) + { + return true; + } + __host__ __device__ friend constexpr bool operator!=(cuda::std::tuple*, const PODSentinel&) + { + return false; + } + __host__ __device__ friend constexpr bool operator!=(const PODSentinel&, cuda::std::tuple*) + { + return false; + } +#endif // TEST_STD_VER <= 2017 +}; + +struct Range : cuda::std::ranges::view_base +{ + __host__ __device__ cuda::std::tuple* begin() const + { + return nullptr; + } + __host__ __device__ PODSentinel end() + { + return PODSentinel{}; + } +}; + +__host__ __device__ constexpr bool test() +{ + using EleView = cuda::std::ranges::elements_view; + using Sentinel = cuda::std::ranges::sentinel_t; + static_assert(!cuda::std::is_same_v>); + + { + Sentinel s; + assert(s.base().i == 0); + } + { + Sentinel s = {}; + assert(s.base().i == 0); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/equality.pass.cpp b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/equality.pass.cpp new file mode 100644 index 00000000000..8ea2525c251 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.elements/sentinel/equality.pass.cpp @@ -0,0 +1,272 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// template +// requires sentinel_for, iterator_t>> +// friend constexpr bool operator==(const iterator& x, const sentinel& y); + +#include +#include +#include + +#include "../types.h" +#include "test_macros.h" + +template +struct Iter +{ + cuda::std::tuple* it_; + + using value_type = cuda::std::tuple; + using difference_type = intptr_t; + using iterator_concept = cuda::std::input_iterator_tag; + + __host__ __device__ constexpr decltype(auto) operator*() const + { + return *it_; + } + __host__ __device__ constexpr Iter& operator++() + { + ++it_; + return *this; + } + __host__ __device__ constexpr void operator++(int) + { + ++it_; + } +}; + +template +struct Sent +{ + cuda::std::tuple* end_; + + __host__ __device__ friend constexpr bool operator==(const Sent& s, const Iter& i) + { + return i.it_ == s.end_; + } +#if TEST_STD_VER <= 2017 + __host__ __device__ friend constexpr bool operator==(const Iter& i, const Sent& s) + { + return i.it_ == s.end_; + } + __host__ __device__ friend constexpr bool operator!=(const Sent& s, const Iter& i) + { + return i.it_ != s.end_; + } + __host__ __device__ friend constexpr bool operator!=(const Iter& i, const Sent& s) + { + return i.it_ != s.end_; + } +#endif // TEST_STD_VER <= 2017 +}; + +template +struct CrossComparableSent +{ + cuda::std::tuple* end_; + + template + __host__ __device__ friend constexpr bool operator==(const CrossComparableSent& s, const Iter& i) + { + return i.it_ == s.end_; + } +#if TEST_STD_VER <= 2017 + template + __host__ __device__ friend constexpr bool operator==(const Iter& i, const CrossComparableSent& s) + { + return i.it_ == s.end_; + } + template + __host__ __device__ friend constexpr bool operator!=(const CrossComparableSent& s, const Iter& i) + { + return i.it_ != s.end_; + } + template + __host__ __device__ friend constexpr bool operator!=(const Iter& i, const CrossComparableSent& s) + { + return i.it_ != s.end_; + } +#endif // TEST_STD_VER <= 2017 +}; + +template