Skip to content

Commit bac1a0e

Browse files
committed
Implement ranges::single_view
1 parent 5916112 commit bac1a0e

File tree

19 files changed

+1309
-8
lines changed

19 files changed

+1309
-8
lines changed

libcudacxx/include/cuda/std/__ranges/movable_box.h

Lines changed: 406 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES
8+
//
9+
//===----------------------------------------------------------------------===//
10+
#ifndef _LIBCUDACXX___RANGES_SINGLE_VIEW_H
11+
#define _LIBCUDACXX___RANGES_SINGLE_VIEW_H
12+
13+
#include <cuda/std/detail/__config>
14+
15+
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
16+
# pragma GCC system_header
17+
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
18+
# pragma clang system_header
19+
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
20+
# pragma system_header
21+
#endif // no system header
22+
23+
#include <cuda/std/__concepts/constructible.h>
24+
#include <cuda/std/__ranges/movable_box.h>
25+
#include <cuda/std/__ranges/range_adaptor.h>
26+
#include <cuda/std/__ranges/view_interface.h>
27+
#include <cuda/std/__type_traits/decay.h>
28+
#include <cuda/std/__type_traits/enable_if.h>
29+
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
30+
#include <cuda/std/__type_traits/is_nothrow_copy_constructible.h>
31+
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
32+
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
33+
#include <cuda/std/__type_traits/is_object.h>
34+
#include <cuda/std/__type_traits/is_same.h>
35+
#include <cuda/std/__type_traits/remove_cvref.h>
36+
#include <cuda/std/__utility/forward.h>
37+
#include <cuda/std/__utility/in_place.h>
38+
#include <cuda/std/__utility/move.h>
39+
40+
_LIBCUDACXX_BEGIN_NAMESPACE_RANGES
41+
42+
#if !defined(_CCCL_NO_CONCEPTS)
43+
template <move_constructible _Tp>
44+
requires is_object_v<_Tp>
45+
#else // ^^^ !_CCCL_NO_CONCEPTS ^^^ / vvv _CCCL_NO_CONCEPTS vvv
46+
template <class _Tp, enable_if_t<move_constructible<_Tp>, int> = 0, enable_if_t<is_object_v<_Tp>, int> = 0>
47+
#endif // _CCCL_NO_CONCEPTS
48+
class single_view : public view_interface<single_view<_Tp>>
49+
{
50+
_CCCL_NO_UNIQUE_ADDRESS __movable_box<_Tp> __value_;
51+
52+
public:
53+
#if !defined(_CCCL_NO_CONCEPTS)
54+
_CCCL_HIDE_FROM_ABI single_view()
55+
requires default_initializable<_Tp>
56+
= default;
57+
#else // ^^^ !_CCCL_NO_CONCEPTS ^^^ / vvv _CCCL_NO_CONCEPTS vvv
58+
_CCCL_TEMPLATE(class _Tp2 = _Tp)
59+
_CCCL_REQUIRES(default_initializable<_Tp2>)
60+
_LIBCUDACXX_HIDE_FROM_ABI constexpr single_view() noexcept(is_nothrow_default_constructible_v<_Tp>)
61+
: view_interface<single_view<_Tp>>()
62+
, __value_(){};
63+
#endif // _CCCL_NO_CONCEPTS
64+
65+
_CCCL_TEMPLATE(class _Tp2 = _Tp)
66+
_CCCL_REQUIRES((!is_same_v<remove_cvref_t<_Tp2>, single_view>) _CCCL_AND copy_constructible<_Tp2>)
67+
_LIBCUDACXX_HIDE_FROM_ABI constexpr explicit single_view(const _Tp2& __t) noexcept(
68+
is_nothrow_copy_constructible_v<_Tp2>)
69+
: view_interface<single_view<_Tp2>>()
70+
, __value_(in_place, __t)
71+
{}
72+
73+
_LIBCUDACXX_HIDE_FROM_ABI constexpr explicit single_view(_Tp&& __t) noexcept(is_nothrow_move_constructible_v<_Tp>)
74+
: view_interface<single_view<_Tp>>()
75+
, __value_(in_place, _CUDA_VSTD::move(__t))
76+
{}
77+
78+
_CCCL_TEMPLATE(class... _Args)
79+
_CCCL_REQUIRES(constructible_from<_Tp, _Args...>)
80+
_LIBCUDACXX_HIDE_FROM_ABI constexpr explicit single_view(in_place_t, _Args&&... __args) noexcept(
81+
is_nothrow_constructible_v<_Tp, _Args...>)
82+
: view_interface<single_view<_Tp>>()
83+
, __value_{in_place, _CUDA_VSTD::forward<_Args>(__args)...}
84+
{}
85+
86+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr _Tp* begin() noexcept
87+
{
88+
return data();
89+
}
90+
91+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr const _Tp* begin() const noexcept
92+
{
93+
return data();
94+
}
95+
96+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr _Tp* end() noexcept
97+
{
98+
return data() + 1;
99+
}
100+
101+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr const _Tp* end() const noexcept
102+
{
103+
return data() + 1;
104+
}
105+
106+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI static constexpr size_t size() noexcept
107+
{
108+
return 1;
109+
}
110+
111+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr _Tp* data() noexcept
112+
{
113+
return __value_.operator->();
114+
}
115+
116+
_CCCL_NODISCARD _LIBCUDACXX_HIDE_FROM_ABI constexpr const _Tp* data() const noexcept
117+
{
118+
return __value_.operator->();
119+
}
120+
};
121+
122+
template <class _Tp>
123+
_CCCL_HOST_DEVICE single_view(_Tp) -> single_view<_Tp>;
124+
125+
_LIBCUDACXX_END_NAMESPACE_RANGES
126+
127+
_LIBCUDACXX_BEGIN_NAMESPACE_VIEWS
128+
_LIBCUDACXX_BEGIN_NAMESPACE_CPO(__single_view)
129+
130+
template <class _Range>
131+
_CCCL_CONCEPT __can_single_view = _CCCL_REQUIRES_EXPR((_Range))(typename(single_view<decay_t<_Range>>));
132+
133+
struct __fn : __range_adaptor_closure<__fn>
134+
{
135+
_CCCL_TEMPLATE(class _Range)
136+
_CCCL_REQUIRES(__can_single_view<_Range>) // MSVC breaks without it
137+
_LIBCUDACXX_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
138+
noexcept(noexcept(single_view<decay_t<_Range>>(_CUDA_VSTD::forward<_Range>(__range))))
139+
-> single_view<decay_t<_Range>>
140+
{
141+
return single_view<decay_t<_Range>>(_CUDA_VSTD::forward<_Range>(__range));
142+
}
143+
};
144+
_LIBCUDACXX_END_NAMESPACE_CPO
145+
146+
inline namespace __cpo
147+
{
148+
_CCCL_GLOBAL_CONSTANT auto single = __single_view::__fn{};
149+
} // namespace __cpo
150+
151+
_LIBCUDACXX_END_NAMESPACE_VIEWS
152+
153+
#endif // _LIBCUDACXX___RANGES_SINGLE_VIEW_H

libcudacxx/include/cuda/std/ranges

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ _CCCL_DIAG_SUPPRESS_MSVC(4848)
3838
#include <cuda/std/__ranges/rbegin.h>
3939
#include <cuda/std/__ranges/ref_view.h>
4040
#include <cuda/std/__ranges/rend.h>
41+
#include <cuda/std/__ranges/single_view.h>
4142
#include <cuda/std/__ranges/size.h>
4243
#include <cuda/std/__ranges/subrange.h>
4344
#include <cuda/std/__ranges/view_interface.h>

libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.all/range.all/range.owning.view/borrowing.compile.pass.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
#include "test_range.h"
1717

1818
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::owning_view<BorrowedView>>);
19-
#if _LIBCUDACXX_HAS_RANGES
2019
static_assert(!cuda::std::ranges::borrowed_range<cuda::std::ranges::owning_view<NonBorrowedView>>);
21-
#endif
2220

2321
int main(int, char**)
2422
{

libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.all/range.ref.view/borrowing.compile.pass.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717

1818
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::ref_view<BorrowedRange>>);
1919
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::ref_view<BorrowedView>>);
20-
#if _LIBCUDACXX_HAS_RANGES
2120
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::ref_view<NonBorrowedView>>);
22-
#endif
2321

2422
int main(int, char**)
2523
{

libcudacxx/test/libcudacxx/std/ranges/range.adaptors/range.empty/borrowing.compile.pass.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::empty_view<int>>);
2020
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::empty_view<int*>>);
2121
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::empty_view<BorrowedView>>);
22-
#if _LIBCUDACXX_HAS_RANGES
2322
static_assert(cuda::std::ranges::borrowed_range<cuda::std::ranges::empty_view<NonBorrowedView>>);
24-
#endif
2523

2624
int main(int, char**)
2725
{
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of libcu++, the C++ Standard Library for your entire system,
4+
// under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
11+
// Tests that <value_> is a <copyable-box>.
12+
13+
#include <cuda/std/cassert>
14+
#include <cuda/std/ranges>
15+
#include <cuda/std/utility>
16+
17+
#include "test_macros.h"
18+
19+
struct Copyable
20+
{
21+
__host__ __device__ constexpr Copyable() noexcept
22+
: val_(0)
23+
{}
24+
__host__ __device__ constexpr Copyable(const Copyable&)
25+
: val_(0)
26+
{}
27+
__host__ __device__ constexpr Copyable(Copyable&&)
28+
: val_(0)
29+
{}
30+
__host__ __device__ constexpr Copyable& operator=(const Copyable&)
31+
{
32+
val_ = 42;
33+
return *this;
34+
}
35+
36+
__host__ __device__ constexpr Copyable& operator=(Copyable&&)
37+
{
38+
val_ = 1337;
39+
return *this;
40+
}
41+
42+
int val_ = 0;
43+
};
44+
static_assert(cuda::std::copyable<Copyable>);
45+
46+
struct NotAssignable
47+
{
48+
NotAssignable() = default;
49+
NotAssignable(const NotAssignable&) = default;
50+
NotAssignable(NotAssignable&&) = default;
51+
52+
NotAssignable& operator=(const NotAssignable&) = delete;
53+
NotAssignable& operator=(NotAssignable&&) = delete;
54+
};
55+
56+
__host__ __device__ TEST_CONSTEXPR_CXX20 bool test()
57+
{
58+
{
59+
const cuda::std::ranges::single_view<NotAssignable> a;
60+
cuda::std::ranges::single_view<NotAssignable> b;
61+
b = a;
62+
b = cuda::std::move(a);
63+
unused(b);
64+
}
65+
66+
{
67+
cuda::std::ranges::single_view<Copyable> a;
68+
cuda::std::ranges::single_view<Copyable> b;
69+
b = a;
70+
assert(b.begin()->val_ == 42);
71+
b = cuda::std::move(a);
72+
assert(b.begin()->val_ == 1337);
73+
}
74+
75+
return true;
76+
}
77+
78+
int main(int, char**)
79+
{
80+
test();
81+
#if TEST_STD_VER >= 2020 && defined(_CCCL_BUILTIN_ADDRESSOF)
82+
static_assert(test());
83+
#endif // TEST_STD_VER >= 2020 && _CCCL_BUILTIN_ADDRESSOF
84+
85+
return 0;
86+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of libcu++, the C++ Standard Library for your entire system,
4+
// under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
11+
// constexpr T* begin() noexcept;
12+
// constexpr const T* begin() const noexcept;
13+
14+
#include <cuda/std/cassert>
15+
#include <cuda/std/ranges>
16+
17+
#include "test_macros.h"
18+
19+
struct Empty
20+
{};
21+
struct BigType
22+
{
23+
char buffer[64] = {10};
24+
};
25+
26+
__host__ __device__ constexpr bool test()
27+
{
28+
{
29+
auto sv = cuda::std::ranges::single_view<int>(42);
30+
assert(*sv.begin() == 42);
31+
32+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), int*>);
33+
static_assert(noexcept(sv.begin()));
34+
}
35+
{
36+
const auto sv = cuda::std::ranges::single_view<int>(42);
37+
assert(*sv.begin() == 42);
38+
39+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), const int*>);
40+
static_assert(noexcept(sv.begin()));
41+
}
42+
43+
{
44+
auto sv = cuda::std::ranges::single_view<Empty>(Empty());
45+
assert(sv.begin() != nullptr);
46+
47+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), Empty*>);
48+
}
49+
{
50+
const auto sv = cuda::std::ranges::single_view<Empty>(Empty());
51+
assert(sv.begin() != nullptr);
52+
53+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), const Empty*>);
54+
}
55+
56+
{
57+
auto sv = cuda::std::ranges::single_view<BigType>(BigType());
58+
assert(sv.begin()->buffer[0] == 10);
59+
60+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), BigType*>);
61+
}
62+
{
63+
const auto sv = cuda::std::ranges::single_view<BigType>(BigType());
64+
assert(sv.begin()->buffer[0] == 10);
65+
66+
static_assert(cuda::std::is_same_v<decltype(sv.begin()), const BigType*>);
67+
}
68+
69+
return true;
70+
}
71+
72+
int main(int, char**)
73+
{
74+
test();
75+
#if defined(_CCCL_BUILTIN_ADDRESSOF)
76+
static_assert(test());
77+
#endif // _CCCL_BUILTIN_ADDRESSOF
78+
79+
return 0;
80+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of libcu++, the C++ Standard Library for your entire system,
4+
// under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
11+
// single_view does not specialize enable_borrowed_range
12+
13+
#include <cuda/std/ranges>
14+
15+
#include "test_range.h"
16+
17+
static_assert(!cuda::std::ranges::borrowed_range<cuda::std::ranges::single_view<int>>);
18+
static_assert(!cuda::std::ranges::borrowed_range<cuda::std::ranges::single_view<int*>>);
19+
static_assert(!cuda::std::ranges::borrowed_range<cuda::std::ranges::single_view<BorrowedView>>);
20+
static_assert(!cuda::std::ranges::borrowed_range<cuda::std::ranges::single_view<NonBorrowedView>>);
21+
22+
int main(int, char**)
23+
{
24+
return 0;
25+
}

0 commit comments

Comments
 (0)