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
46namespace ranges {
47
48template <class _Tp>
49concept __integer_like_with_usable_difference_type =
50 __signed_integer_like<_Tp> || (__integer_like<_Tp> && weakly_incrementable<_Tp>);
51
52template <class _Tp>
53struct __repeat_view_iterator_difference {
54 using type = _IotaDiffT<_Tp>;
55};
56
57template <__signed_integer_like _Tp>
58struct __repeat_view_iterator_difference<_Tp> {
59 using type = _Tp;
60};
61
62template <class _Tp>
63using __repeat_view_iterator_difference_t = typename __repeat_view_iterator_difference<_Tp>::type;
64
65namespace views::__drop {
66struct __fn;
67} // namespace views::__drop
68
69namespace views::__take {
70struct __fn;
71} // namespace views::__take
72
73template <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>))
76class _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
81public:
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
126private:
127 _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Tp> __value_;
128 _LIBCPP_NO_UNIQUE_ADDRESS _Bound __bound_ = _Bound();
129};
130
131template <class _Tp, class _Bound = unreachable_sentinel_t>
132repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;
133
134// [range.repeat.iterator]
135template <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>))
138class 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
146public:
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
223private:
224 const _Tp* __value_ = nullptr;
225 _IndexT __current_ = _IndexT();
226};
227
228// clang-format off
229namespace views {
230namespace __repeat {
231struct __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
247inline namespace __cpo {
248inline constexpr auto repeat = __repeat::__fn{};
249} // namespace __cpo
250} // namespace views
251
252template <class _Tp>
253inline constexpr bool __is_repeat_specialization = false;
254
255template <class _Tp, class _Bound>
256inline 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