Skip to content

Commit 76f21cb

Browse files
authored
Implement ranges::views::drop_while_view (#8392)
* Implement views::drop_while
1 parent b452ae2 commit 76f21cb

12 files changed

Lines changed: 1167 additions & 1 deletion

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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) 2026 NVIDIA CORPORATION & AFFILIATES.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
11+
#ifndef _CUDA_STD___RANGES_DROP_WHILE_VIEW_H
12+
#define _CUDA_STD___RANGES_DROP_WHILE_VIEW_H
13+
14+
#include <cuda/std/detail/__config>
15+
16+
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
17+
# pragma GCC system_header
18+
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
19+
# pragma clang system_header
20+
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
21+
# pragma system_header
22+
#endif // no system header
23+
24+
#include <cuda/std/__algorithm/ranges_find_if_not.h>
25+
#include <cuda/std/__concepts/constructible.h>
26+
#include <cuda/std/__functional/bind_back.h>
27+
#include <cuda/std/__functional/reference_wrapper.h>
28+
#include <cuda/std/__iterator/concepts.h>
29+
#include <cuda/std/__ranges/access.h>
30+
#include <cuda/std/__ranges/all.h>
31+
#include <cuda/std/__ranges/concepts.h>
32+
#include <cuda/std/__ranges/enable_borrowed_range.h>
33+
#include <cuda/std/__ranges/movable_box.h>
34+
#include <cuda/std/__ranges/non_propagating_cache.h>
35+
#include <cuda/std/__ranges/range_adaptor.h>
36+
#include <cuda/std/__ranges/view_interface.h>
37+
#include <cuda/std/__type_traits/conditional.h>
38+
#include <cuda/std/__type_traits/decay.h>
39+
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
40+
#include <cuda/std/__type_traits/is_object.h>
41+
#include <cuda/std/__utility/forward.h>
42+
#include <cuda/std/__utility/in_place.h>
43+
#include <cuda/std/__utility/move.h>
44+
45+
#include <cuda/std/__cccl/prologue.h>
46+
47+
_CCCL_BEGIN_NAMESPACE_CUDA_STD_RANGES
48+
49+
#if _CCCL_HAS_CONCEPTS()
50+
template <view _View, class _Pred>
51+
requires input_range<_View> && ::cuda::std::is_object_v<_Pred>
52+
&& ::cuda::std::indirect_unary_predicate<const _Pred, iterator_t<_View>>
53+
#else // ^^^ _CCCL_HAS_CONCEPTS() ^^^ / vvv !_CCCL_HAS_CONCEPTS() vvv
54+
template <class _View,
55+
class _Pred,
56+
::cuda::std::enable_if_t<view<_View>, int> = 0,
57+
::cuda::std::enable_if_t<input_range<_View>, int> = 0,
58+
::cuda::std::enable_if_t<::cuda::std::is_object_v<_Pred>, int> = 0,
59+
::cuda::std::enable_if_t<::cuda::std::indirect_unary_predicate<const _Pred, iterator_t<_View>>, int> = 0>
60+
#endif // !_CCCL_HAS_CONCEPTS()
61+
class drop_while_view : public view_interface<drop_while_view<_View, _Pred>>
62+
{
63+
_CCCL_NO_UNIQUE_ADDRESS _View __base_{};
64+
_CCCL_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_{};
65+
66+
static constexpr bool _use_cache = forward_range<_View>;
67+
using _cache_type _CCCL_NODEBUG =
68+
::cuda::std::conditional_t<_use_cache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
69+
_CCCL_NO_UNIQUE_ADDRESS _cache_type __cached_begin_{};
70+
71+
public:
72+
#if _CCCL_HAS_CONCEPTS()
73+
_CCCL_HIDE_FROM_ABI drop_while_view()
74+
requires ::cuda::std::default_initializable<_View> && ::cuda::std::default_initializable<_Pred>
75+
= default;
76+
#else // ^^^ _CCCL_HAS_CONCEPTS() ^^^ / vvv !_CCCL_HAS_CONCEPTS() vvv
77+
_CCCL_TEMPLATE(class _View2 = _View, class _Pred2 = _Pred)
78+
_CCCL_REQUIRES(::cuda::std::default_initializable<_View2> _CCCL_AND ::cuda::std::default_initializable<_Pred2>)
79+
_CCCL_API constexpr drop_while_view() noexcept(::cuda::std::is_nothrow_default_constructible_v<_View2>
80+
&& ::cuda::std::is_nothrow_default_constructible_v<_Pred2>)
81+
: view_interface<drop_while_view<_View, _Pred>>{}
82+
{}
83+
#endif // !_CCCL_HAS_CONCEPTS()
84+
85+
_CCCL_API constexpr explicit drop_while_view(_View __base, _Pred __pred)
86+
: __base_{::cuda::std::move(__base)}
87+
, __pred_{::cuda::std::in_place, ::cuda::std::move(__pred)}
88+
89+
{}
90+
91+
_CCCL_TEMPLATE(class _View2 = _View)
92+
_CCCL_REQUIRES(::cuda::std::copy_constructible<_View2>)
93+
[[nodiscard]] _CCCL_API constexpr _View base() const& noexcept(::cuda::std::is_nothrow_copy_constructible_v<_View>)
94+
{
95+
return __base_;
96+
}
97+
98+
[[nodiscard]] _CCCL_API constexpr _View base() && noexcept(::cuda::std::is_nothrow_move_constructible_v<_View>)
99+
{
100+
return ::cuda::std::move(__base_);
101+
}
102+
103+
[[nodiscard]] _CCCL_API constexpr const _Pred& pred() const
104+
{
105+
return *__pred_;
106+
}
107+
108+
[[nodiscard]] _CCCL_API constexpr auto begin()
109+
{
110+
_CCCL_ASSERT(__pred_.__has_value(),
111+
"drop_while_view needs to have a valid predicate before calling begin() -- did a previous "
112+
"assignment to this drop_while_view fail?");
113+
114+
if constexpr (_use_cache)
115+
{
116+
if (!__cached_begin_.__has_value())
117+
{
118+
__cached_begin_.__emplace(::cuda::std::ranges::find_if_not(__base_, ::cuda::std::cref(*__pred_)));
119+
}
120+
return *__cached_begin_;
121+
}
122+
else
123+
{
124+
return ::cuda::std::ranges::find_if_not(__base_, ::cuda::std::cref(*__pred_));
125+
}
126+
_CCCL_UNREACHABLE();
127+
}
128+
129+
[[nodiscard]] _CCCL_API constexpr auto end()
130+
{
131+
return ::cuda::std::ranges::end(__base_);
132+
}
133+
};
134+
135+
template <class _View, class _Pred>
136+
inline constexpr bool enable_borrowed_range<drop_while_view<_View, _Pred>> = enable_borrowed_range<_View>;
137+
138+
template <class _Range, class _Pred>
139+
_CCCL_HOST_DEVICE drop_while_view(_Range&&, _Pred) -> drop_while_view<::cuda::std::ranges::views::all_t<_Range>, _Pred>;
140+
141+
_CCCL_END_NAMESPACE_CUDA_STD_VIEWS
142+
143+
_CCCL_BEGIN_NAMESPACE_CUDA_STD_VIEWS
144+
_CCCL_BEGIN_NAMESPACE_CPO(__drop_while)
145+
146+
struct __fn
147+
{
148+
template <class _Range, class _Pred>
149+
[[nodiscard]] _CCCL_API constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
150+
noexcept(noexcept(drop_while_view{::cuda::std::forward<_Range>(__range), ::cuda::std::forward<_Pred>(__pred)}))
151+
-> decltype(drop_while_view{::cuda::std::forward<_Range>(__range), ::cuda::std::forward<_Pred>(__pred)})
152+
{
153+
return drop_while_view{::cuda::std::forward<_Range>(__range), ::cuda::std::forward<_Pred>(__pred)};
154+
}
155+
156+
_CCCL_TEMPLATE(class _Pred)
157+
_CCCL_REQUIRES(::cuda::std::constructible_from<::cuda::std::decay_t<_Pred>, _Pred>)
158+
[[nodiscard]] _CCCL_API constexpr auto operator()(_Pred&& __pred) const
159+
noexcept(::cuda::std::is_nothrow_constructible_v<::cuda::std::decay_t<_Pred>, _Pred>)
160+
{
161+
return ::cuda::std::ranges::__pipeable{::cuda::std::__bind_back(*this, ::cuda::std::forward<_Pred>(__pred))};
162+
}
163+
};
164+
165+
_CCCL_END_NAMESPACE_CPO
166+
167+
inline namespace __cpo
168+
{
169+
_CCCL_GLOBAL_CONSTANT auto drop_while = __drop_while::__fn{};
170+
} // namespace __cpo
171+
172+
_CCCL_END_NAMESPACE_CUDA_STD_VIEWS
173+
174+
#include <cuda/std/__cccl/epilogue.h>
175+
176+
#endif // _CUDA_STD___RANGES_DROP_WHILE_VIEW_H

libcudacxx/include/cuda/std/ranges

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// under the Apache License v2.0 with LLVM Exceptions.
55
// See https://llvm.org/LICENSE.txt for license information.
66
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7-
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
7+
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
88
//
99
//===----------------------------------------------------------------------===//
1010

@@ -32,6 +32,7 @@ _CCCL_DIAG_SUPPRESS_MSVC(4848)
3232
#include <cuda/std/__ranges/dangling.h>
3333
#include <cuda/std/__ranges/data.h>
3434
#include <cuda/std/__ranges/drop_view.h>
35+
#include <cuda/std/__ranges/drop_while_view.h>
3536
#include <cuda/std/__ranges/empty.h>
3637
#include <cuda/std/__ranges/empty_view.h>
3738
#include <cuda/std/__ranges/enable_borrowed_range.h>
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// cuda::std::views::drop_while
11+
12+
// #include <cuda/std/algorithm>
13+
#include <cuda/std/cassert>
14+
#include <cuda/std/ranges>
15+
#include <cuda/std/type_traits>
16+
#include <cuda/std/utility>
17+
18+
#include "test_macros.h"
19+
20+
struct Pred
21+
{
22+
TEST_FUNC constexpr bool operator()(int i) const
23+
{
24+
return i < 3;
25+
}
26+
};
27+
28+
struct Foo
29+
{};
30+
31+
template <class T>
32+
struct BufferView : cuda::std::ranges::view_base
33+
{
34+
T* buffer_;
35+
cuda::std::size_t size_;
36+
37+
template <cuda::std::size_t N>
38+
TEST_FUNC constexpr BufferView(T (&b)[N])
39+
: buffer_(b)
40+
, size_(N)
41+
{}
42+
};
43+
44+
using IntBufferView = BufferView<int>;
45+
46+
struct MoveOnlyView : IntBufferView
47+
{
48+
#if TEST_COMPILER(NVRTC)
49+
MoveOnlyView() noexcept = default;
50+
51+
template <class T>
52+
TEST_FUNC constexpr MoveOnlyView(T&& arr) noexcept(noexcept(IntBufferView(cuda::std::declval<T>())))
53+
: IntBufferView(cuda::std::forward<T>(arr))
54+
{}
55+
#else
56+
using IntBufferView::IntBufferView;
57+
#endif
58+
59+
MoveOnlyView(const MoveOnlyView&) = delete;
60+
MoveOnlyView& operator=(const MoveOnlyView&) = delete;
61+
MoveOnlyView(MoveOnlyView&&) = default;
62+
MoveOnlyView& operator=(MoveOnlyView&&) = default;
63+
TEST_FUNC constexpr const int* begin() const
64+
{
65+
return buffer_;
66+
}
67+
TEST_FUNC constexpr const int* end() const
68+
{
69+
return buffer_ + size_;
70+
}
71+
};
72+
73+
static_assert(!cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while))>);
74+
static_assert(cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), int>);
75+
static_assert(cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), Pred>);
76+
static_assert(!cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), int, Pred>);
77+
static_assert(cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), int (&)[2], Pred>);
78+
static_assert(!cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), Foo (&)[2], Pred>);
79+
static_assert(cuda::std::is_invocable_v<decltype((cuda::std::views::drop_while)), MoveOnlyView, Pred>);
80+
81+
template <class View, class T>
82+
_CCCL_CONCEPT CanBePiped =
83+
_CCCL_REQUIRES_EXPR((View, T), View&& view, T&& t)((cuda::std::forward<View>(view) | cuda::std::forward<T>(t)));
84+
85+
static_assert(!CanBePiped<MoveOnlyView, decltype(cuda::std::views::drop_while)>);
86+
static_assert(CanBePiped<MoveOnlyView, decltype(cuda::std::views::drop_while(Pred{}))>);
87+
static_assert(CanBePiped<int (&)[2], decltype(cuda::std::views::drop_while(Pred{}))>);
88+
static_assert(!CanBePiped<int, decltype(cuda::std::views::drop_while(Pred{}))>);
89+
static_assert(!CanBePiped<Foo (&)[2], decltype(cuda::std::views::drop_while(Pred{}))>);
90+
91+
template <class Range, class Expected>
92+
TEST_FUNC constexpr bool equal(Range&& range, Expected&& expected)
93+
{
94+
auto irange = range.begin();
95+
auto iexpected = cuda::std::begin(expected);
96+
for (; irange != range.end(); ++irange, ++iexpected)
97+
{
98+
if (*irange != *iexpected)
99+
{
100+
return false;
101+
}
102+
}
103+
return true;
104+
}
105+
106+
TEST_FUNC constexpr bool test()
107+
{
108+
int buff[] = {1, 2, 3, 4, 3, 2, 1};
109+
110+
// Test `views::drop_while(p)(v)`
111+
{
112+
using Result = cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>;
113+
decltype(auto) result = cuda::std::views::drop_while(Pred{})(MoveOnlyView{buff});
114+
static_assert(cuda::std::same_as<decltype(result), Result>);
115+
auto expected = {3, 4, 3, 2, 1};
116+
assert(equal(result, expected));
117+
}
118+
{
119+
auto const partial = cuda::std::views::drop_while(Pred{});
120+
using Result = cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>;
121+
decltype(auto) result = partial(MoveOnlyView{buff});
122+
static_assert(cuda::std::same_as<decltype(result), Result>);
123+
auto expected = {3, 4, 3, 2, 1};
124+
assert(equal(result, expected));
125+
}
126+
127+
// Test `v | views::drop_while(p)`
128+
{
129+
using Result = cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>;
130+
decltype(auto) result = MoveOnlyView{buff} | cuda::std::views::drop_while(Pred{});
131+
static_assert(cuda::std::same_as<decltype(result), Result>);
132+
auto expected = {3, 4, 3, 2, 1};
133+
assert(equal(result, expected));
134+
}
135+
{
136+
auto const partial = cuda::std::views::drop_while(Pred{});
137+
using Result = cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>;
138+
decltype(auto) result = MoveOnlyView{buff} | partial;
139+
static_assert(cuda::std::same_as<decltype(result), Result>);
140+
auto expected = {3, 4, 3, 2, 1};
141+
assert(equal(result, expected));
142+
}
143+
144+
// Test `views::drop_while(v, p)`
145+
{
146+
using Result = cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>;
147+
decltype(auto) result = cuda::std::views::drop_while(MoveOnlyView{buff}, Pred{});
148+
static_assert(cuda::std::same_as<decltype(result), Result>);
149+
auto expected = {3, 4, 3, 2, 1};
150+
assert(equal(result, expected));
151+
}
152+
153+
// Test adaptor | adaptor
154+
{
155+
struct Pred2
156+
{
157+
TEST_FUNC constexpr bool operator()(int i) const
158+
{
159+
return i < 4;
160+
}
161+
};
162+
auto const partial = cuda::std::views::drop_while(Pred{}) | cuda::std::views::drop_while(Pred2{});
163+
using Result = cuda::std::ranges::drop_while_view<cuda::std::ranges::drop_while_view<MoveOnlyView, Pred>, Pred2>;
164+
decltype(auto) result = MoveOnlyView{buff} | partial;
165+
static_assert(cuda::std::same_as<decltype(result), Result>);
166+
auto expected = {4, 3, 2, 1};
167+
assert(equal(result, expected));
168+
}
169+
return true;
170+
}
171+
172+
int main(int, char**)
173+
{
174+
test();
175+
#if TEST_STD_VER >= 2020 && defined(_CCCL_BUILTIN_ADDRESSOF)
176+
static_assert(test());
177+
#endif // TEST_STD_VER >= 2020 && defined(_CCCL_BUILTIN_ADDRESSOF)
178+
179+
return 0;
180+
}

0 commit comments

Comments
 (0)