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