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 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___RANGES_REPEAT_VIEW_H |
11 | #define _LIBCPP___RANGES_REPEAT_VIEW_H |
12 | |
13 | #include <__assert> |
14 | #include <__concepts/constructible.h> |
15 | #include <__concepts/same_as.h> |
16 | #include <__concepts/semiregular.h> |
17 | #include <__config> |
18 | #include <__cstddef/ptrdiff_t.h> |
19 | #include <__iterator/concepts.h> |
20 | #include <__iterator/iterator_traits.h> |
21 | #include <__iterator/unreachable_sentinel.h> |
22 | #include <__memory/addressof.h> |
23 | #include <__ranges/iota_view.h> |
24 | #include <__ranges/movable_box.h> |
25 | #include <__ranges/view_interface.h> |
26 | #include <__type_traits/decay.h> |
27 | #include <__type_traits/is_object.h> |
28 | #include <__type_traits/make_unsigned.h> |
29 | #include <__type_traits/remove_cv.h> |
30 | #include <__utility/forward.h> |
31 | #include <__utility/in_place.h> |
32 | #include <__utility/move.h> |
33 | #include <__utility/piecewise_construct.h> |
34 | #include <tuple> |
35 | |
36 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
37 | # pragma GCC system_header |
38 | #endif |
39 | |
40 | _LIBCPP_PUSH_MACROS |
41 | #include <__undef_macros> |
42 | |
43 | _LIBCPP_BEGIN_NAMESPACE_STD |
44 | |
45 | #if _LIBCPP_STD_VER >= 23 |
46 | |
47 | namespace ranges { |
48 | |
49 | template <class _Tp> |
50 | concept __integer_like_with_usable_difference_type = |
51 | __signed_integer_like<_Tp> || (__integer_like<_Tp> && weakly_incrementable<_Tp>); |
52 | |
53 | template <class _Tp> |
54 | struct __repeat_view_iterator_difference { |
55 | using type _LIBCPP_NODEBUG = _IotaDiffT<_Tp>; |
56 | }; |
57 | |
58 | template <__signed_integer_like _Tp> |
59 | struct __repeat_view_iterator_difference<_Tp> { |
60 | using type _LIBCPP_NODEBUG = _Tp; |
61 | }; |
62 | |
63 | template <class _Tp> |
64 | using __repeat_view_iterator_difference_t _LIBCPP_NODEBUG = typename __repeat_view_iterator_difference<_Tp>::type; |
65 | |
66 | namespace views::__drop { |
67 | struct __fn; |
68 | } // namespace views::__drop |
69 | |
70 | namespace views::__take { |
71 | struct __fn; |
72 | } // namespace views::__take |
73 | |
74 | template <move_constructible _Tp, semiregular _Bound = unreachable_sentinel_t> |
75 | requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> && |
76 | (__integer_like_with_usable_difference_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>)) |
77 | class _LIBCPP_ABI_LLVM18_NO_UNIQUE_ADDRESS repeat_view : public view_interface<repeat_view<_Tp, _Bound>> { |
78 | friend struct views::__take::__fn; |
79 | friend struct views::__drop::__fn; |
80 | class __iterator; |
81 | |
82 | public: |
83 | _LIBCPP_HIDE_FROM_ABI repeat_view() |
84 | requires default_initializable<_Tp> |
85 | = default; |
86 | |
87 | _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(const _Tp& __value, _Bound __bound_sentinel = _Bound()) |
88 | requires copy_constructible<_Tp> |
89 | : __value_(in_place, __value), __bound_(__bound_sentinel) { |
90 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
91 | _LIBCPP_ASSERT_UNCATEGORIZED(__bound_ >= 0, "The value of bound must be greater than or equal to 0" ); |
92 | } |
93 | |
94 | _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(_Tp&& __value, _Bound __bound_sentinel = _Bound()) |
95 | : __value_(in_place, std::move(__value)), __bound_(__bound_sentinel) { |
96 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
97 | _LIBCPP_ASSERT_UNCATEGORIZED(__bound_ >= 0, "The value of bound must be greater than or equal to 0" ); |
98 | } |
99 | |
100 | template <class... _TpArgs, class... _BoundArgs> |
101 | requires(constructible_from<_Tp, _TpArgs...> && constructible_from<_Bound, _BoundArgs...>) |
102 | _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view( |
103 | piecewise_construct_t, tuple<_TpArgs...> __value_args, tuple<_BoundArgs...> __bound_args = tuple<>{}) |
104 | : __value_(in_place, std::make_from_tuple<_Tp>(std::move(__value_args))), |
105 | __bound_(std::make_from_tuple<_Bound>(std::move(__bound_args))) { |
106 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
107 | _LIBCPP_ASSERT_UNCATEGORIZED( |
108 | __bound_ >= 0, "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative" ); |
109 | } |
110 | |
111 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator(std::addressof(*__value_)); } |
112 | |
113 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const |
114 | requires(!same_as<_Bound, unreachable_sentinel_t>) |
115 | { |
116 | return __iterator(std::addressof(*__value_), __bound_); |
117 | } |
118 | |
119 | _LIBCPP_HIDE_FROM_ABI constexpr unreachable_sentinel_t end() const noexcept { return unreachable_sentinel; } |
120 | |
121 | _LIBCPP_HIDE_FROM_ABI constexpr auto size() const |
122 | requires(!same_as<_Bound, unreachable_sentinel_t>) |
123 | { |
124 | return std::__to_unsigned_like(__bound_); |
125 | } |
126 | |
127 | private: |
128 | _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Tp> __value_; |
129 | _LIBCPP_NO_UNIQUE_ADDRESS _Bound __bound_ = _Bound(); |
130 | }; |
131 | |
132 | template <class _Tp, class _Bound = unreachable_sentinel_t> |
133 | repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>; |
134 | |
135 | // [range.repeat.iterator] |
136 | template <move_constructible _Tp, semiregular _Bound> |
137 | requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> && |
138 | (__integer_like_with_usable_difference_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>)) |
139 | class repeat_view<_Tp, _Bound>::__iterator { |
140 | friend class repeat_view; |
141 | |
142 | using _IndexT _LIBCPP_NODEBUG = conditional_t<same_as<_Bound, unreachable_sentinel_t>, ptrdiff_t, _Bound>; |
143 | |
144 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(const _Tp* __value, _IndexT __bound_sentinel = _IndexT()) |
145 | : __value_(__value), __current_(__bound_sentinel) {} |
146 | |
147 | public: |
148 | using iterator_concept = random_access_iterator_tag; |
149 | using iterator_category = random_access_iterator_tag; |
150 | using value_type = _Tp; |
151 | using difference_type = __repeat_view_iterator_difference_t<_IndexT>; |
152 | |
153 | _LIBCPP_HIDE_FROM_ABI __iterator() = default; |
154 | |
155 | _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const noexcept { return *__value_; } |
156 | |
157 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { |
158 | ++__current_; |
159 | return *this; |
160 | } |
161 | |
162 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { |
163 | auto __tmp = *this; |
164 | ++*this; |
165 | return __tmp; |
166 | } |
167 | |
168 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() { |
169 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
170 | _LIBCPP_ASSERT_UNCATEGORIZED(__current_ > 0, "The value of bound must be greater than or equal to 0" ); |
171 | --__current_; |
172 | return *this; |
173 | } |
174 | |
175 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) { |
176 | auto __tmp = *this; |
177 | --*this; |
178 | return __tmp; |
179 | } |
180 | |
181 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n) { |
182 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
183 | _LIBCPP_ASSERT_UNCATEGORIZED(__current_ + __n >= 0, "The value of bound must be greater than or equal to 0" ); |
184 | __current_ += __n; |
185 | return *this; |
186 | } |
187 | |
188 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n) { |
189 | if constexpr (!same_as<_Bound, unreachable_sentinel_t>) |
190 | _LIBCPP_ASSERT_UNCATEGORIZED(__current_ - __n >= 0, "The value of bound must be greater than or equal to 0" ); |
191 | __current_ -= __n; |
192 | return *this; |
193 | } |
194 | |
195 | _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](difference_type __n) const noexcept { return *(*this + __n); } |
196 | |
197 | _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { |
198 | return __x.__current_ == __y.__current_; |
199 | } |
200 | |
201 | _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) { |
202 | return __x.__current_ <=> __y.__current_; |
203 | } |
204 | |
205 | _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) { |
206 | __i += __n; |
207 | return __i; |
208 | } |
209 | |
210 | _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) { |
211 | __i += __n; |
212 | return __i; |
213 | } |
214 | |
215 | _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) { |
216 | __i -= __n; |
217 | return __i; |
218 | } |
219 | |
220 | _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) { |
221 | return static_cast<difference_type>(__x.__current_) - static_cast<difference_type>(__y.__current_); |
222 | } |
223 | |
224 | private: |
225 | const _Tp* __value_ = nullptr; |
226 | _IndexT __current_ = _IndexT(); |
227 | }; |
228 | |
229 | // clang-format off |
230 | namespace views { |
231 | namespace __repeat { |
232 | struct __fn { |
233 | template <class _Tp> |
234 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value) |
235 | noexcept(noexcept(ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)))) |
236 | -> decltype( ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value))) |
237 | { return ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)); } |
238 | |
239 | template <class _Tp, class _Bound> |
240 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel) |
241 | noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)))) |
242 | -> decltype( ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel))) |
243 | { return ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)); } |
244 | }; |
245 | } // namespace __repeat |
246 | // clang-format on |
247 | |
248 | inline namespace __cpo { |
249 | inline constexpr auto repeat = __repeat::__fn{}; |
250 | } // namespace __cpo |
251 | } // namespace views |
252 | |
253 | template <class _Tp> |
254 | inline constexpr bool __is_repeat_specialization = false; |
255 | |
256 | template <class _Tp, class _Bound> |
257 | inline constexpr bool __is_repeat_specialization<repeat_view<_Tp, _Bound>> = true; |
258 | |
259 | } // namespace ranges |
260 | |
261 | #endif // _LIBCPP_STD_VER >= 23 |
262 | |
263 | _LIBCPP_END_NAMESPACE_STD |
264 | |
265 | _LIBCPP_POP_MACROS |
266 | |
267 | #endif // _LIBCPP___RANGES_REPEAT_VIEW_H |
268 | |