1#ifndef PROBFD_CONVERT_H
2#define PROBFD_CONVERT_H
9namespace probfd::views {
12template <
bool Const,
typename T>
13using maybe_const_t = std::conditional_t<Const, const T, T>;
16template <std::ranges::input_range Vw,
typename T>
17 requires std::ranges::view<Vw> &&
18 std::convertible_to<std::ranges::range_reference_t<Vw>, T>
19class convert_view :
public std::ranges::view_interface<convert_view<Vw, T>> {
25 struct CategoryBase {};
28 requires std::ranges::forward_range<detail::maybe_const_t<Const, Vw>>
29 struct CategoryBase<Const> {
30 using Base = detail::maybe_const_t<Const, Vw>;
31 using iterator_category = std::conditional_t<
32 std::is_reference_v<T>,
35 typename std::iterator_traits<
36 std::ranges::iterator_t<Base>>::iterator_category,
37 std::contiguous_iterator_tag>,
38 std::random_access_iterator_tag,
39 typename std::iterator_traits<
40 std::ranges::iterator_t<Base>>::iterator_category>,
41 std::input_iterator_tag>;
45 class Iterator :
public CategoryBase<Const> {
49 using Parent_t = detail::maybe_const_t<Const, convert_view>;
50 using Base = detail::maybe_const_t<Const, Vw>;
52 std::ranges::iterator_t<Base> Current{};
56 using iterator_concept = std::conditional_t<
57 std::ranges::random_access_range<Base>,
58 std::random_access_iterator_tag,
60 std::ranges::bidirectional_range<Base>,
61 std::bidirectional_iterator_tag,
63 std::ranges::forward_range<Base>,
64 std::forward_iterator_tag,
65 std::input_iterator_tag>>>;
67 using value_type = std::remove_cvref_t<T>;
68 using difference_type = std::ranges::range_difference_t<Base>;
71 requires std::default_initializable<
std::ranges::iterator_t<Base>>
76 std::ranges::iterator_t<Base>
77 Current_) noexcept(
std::
78 is_nothrow_move_constructible_v<
79 std::ranges::iterator_t<Base>>)
80 : Current{std::move(Current_)}
81 , Parent{std::addressof(Parent_)}
85 constexpr explicit(
false) Iterator(Iterator<!Const> It)
noexcept(
86 std::is_nothrow_constructible_v<
87 std::ranges::iterator_t<Base>,
88 std::ranges::iterator_t<Vw>>)
89 requires Const && std::convertible_to<
90 std::ranges::iterator_t<Vw>,
91 std::ranges::iterator_t<Base>>
92 : Current(
std::move(It.Current))
98 constexpr const std::ranges::iterator_t<Base>& base() const& noexcept
103 constexpr std::ranges::iterator_t<Base>
104 base() &&
noexcept(std::is_nothrow_move_constructible_v<
105 std::ranges::iterator_t<Base>>)
107 return std::move(Current);
111 constexpr decltype(
auto)
operator*()
const
112 noexcept(
noexcept(
static_cast<T
>(*Current)))
114 return static_cast<T
>(*Current);
118 operator++() noexcept(noexcept(++Current))
124 constexpr decltype(
auto) operator++(
int)
noexcept(
125 noexcept(++Current) && (!std::ranges::forward_range<Base> ||
126 std::is_nothrow_copy_constructible_v<
127 std::ranges::iterator_t<Base>>))
129 if constexpr (std::ranges::forward_range<Base>) {
139 operator--() noexcept(noexcept(--Current))
140 requires
std::ranges::bidirectional_range<Base>
146 constexpr Iterator operator--(
int)
noexcept(
147 noexcept(--Current) &&
148 std::is_nothrow_copy_constructible_v<std::ranges::iterator_t<Base>>)
149 requires std::ranges::bidirectional_range<Base>
157 operator+=(
const difference_type Off)
noexcept(
noexcept(Current += Off))
158 requires std::ranges::random_access_range<Base>
165 operator-=(
const difference_type Off)
noexcept(
noexcept(Current -= Off))
166 requires std::ranges::random_access_range<Base>
173 constexpr decltype(
auto)
operator[](
const difference_type Idx)
const
174 noexcept(
noexcept(
static_cast<T
>(Current[Idx])))
175 requires std::ranges::random_access_range<Base>
177 return static_cast<T
>(Current[Idx]);
181 friend constexpr bool
182 operator==(
const Iterator& Left,
const Iterator& Right)
noexcept(
183 noexcept(Left.Current == Right.Current))
184 requires std::equality_comparable<std::ranges::iterator_t<Base>>
186 return Left.Current == Right.Current;
190 friend constexpr bool
191 operator<(
const Iterator& Left,
const Iterator& Right)
noexcept(
192 noexcept(Left.Current < Right.Current))
193 requires std::ranges::random_access_range<Base>
195 return Left.Current < Right.Current;
199 friend constexpr bool
200 operator>(
const Iterator& Left,
const Iterator& Right)
noexcept(
201 noexcept(Left.Current < Right.Current))
202 requires std::ranges::random_access_range<Base>
208 friend constexpr bool
209 operator<=(
const Iterator& Left,
const Iterator& Right)
noexcept(
210 noexcept(Left.Current < Right.Current))
211 requires std::ranges::random_access_range<Base>
213 return !(Right < Left);
217 friend constexpr bool
218 operator>=(
const Iterator& Left,
const Iterator& Right)
noexcept(
219 noexcept(Left.Current < Right.Current))
220 requires std::ranges::random_access_range<Base>
222 return !(Left < Right);
226 friend constexpr auto
227 operator<=>(
const Iterator& Left,
const Iterator& Right)
noexcept(
228 noexcept(Left.Current <=> Right.Current))
229 requires std::ranges::random_access_range<Base> &&
230 std::three_way_comparable<std::ranges::iterator_t<Base>>
232 return Left.Current <=> Right.Current;
236 friend constexpr Iterator
237 operator+(Iterator It,
const difference_type Off)
noexcept(
238 noexcept(It.Current += Off))
239 requires std::ranges::random_access_range<Base>
246 friend constexpr Iterator
247 operator+(
const difference_type Off, Iterator It)
noexcept(
248 noexcept(It.Current += Off))
249 requires std::ranges::random_access_range<Base>
256 friend constexpr Iterator
257 operator-(Iterator It,
const difference_type Off)
noexcept(
258 noexcept(It.Current -= Off))
259 requires std::ranges::random_access_range<Base>
266 friend constexpr difference_type
267 operator-(
const Iterator& Left,
const Iterator& Right)
noexcept(
268 noexcept(Left.Current - Right.Current))
269 requires std::sized_sentinel_for<
270 std::ranges::iterator_t<Base>,
271 std::ranges::iterator_t<Base>>
273 return Left.Current - Right.Current;
277 template <
bool Const>
282 using Parent_t = detail::maybe_const_t<Const, convert_view>;
283 using Base = detail::maybe_const_t<Const, Vw>;
285 template <
bool OtherConst>
287 std::ranges::iterator_t<detail::maybe_const_t<OtherConst, Vw>>;
289 std::ranges::sentinel_t<Base> Last{};
291 template <
bool OtherConst>
293 static constexpr const const_iter<OtherConst>&
294 GetCurrent(
const Iterator<OtherConst>& It)
noexcept
300 Sentinel() =
default;
302 constexpr explicit Sentinel(
303 std::ranges::sentinel_t<Base>
304 Last_)
noexcept(std::
305 is_nothrow_move_constructible_v<
306 std::ranges::sentinel_t<Base>>)
307 : Last(
std::move(Last_))
311 constexpr explicit(
false) Sentinel(Sentinel<!Const> Se)
noexcept(
312 std::is_nothrow_constructible_v<
313 std::ranges::sentinel_t<Base>,
314 std::ranges::sentinel_t<Vw>>)
315 requires Const && std::convertible_to<
316 std::ranges::sentinel_t<Vw>,
317 std::ranges::sentinel_t<Base>>
318 : Last(
std::move(Se.Last))
323 constexpr std::ranges::sentinel_t<Base> base() const noexcept(
324 std::is_nothrow_copy_constructible_v<
std::ranges::sentinel_t<Base>>)
329 template <
bool OtherConst>
330 requires std::sentinel_for<
331 std::ranges::sentinel_t<Base>,
332 const_iter<OtherConst>>
334 friend constexpr bool operator==(
335 const Iterator<OtherConst>& Left,
337 Right)
noexcept(
noexcept(GetCurrent(Left) == Right.Last))
339 return GetCurrent(Left) == Right.Last;
342 template <
bool OtherConst>
343 requires std::sized_sentinel_for<
344 std::ranges::sentinel_t<Base>,
345 const_iter<OtherConst>>
347 friend constexpr std::ranges::range_difference_t<
348 detail::maybe_const_t<OtherConst, Vw>>
350 const Iterator<OtherConst>& Left,
352 Right)
noexcept(
noexcept(GetCurrent(Left) - Right.Last))
354 return GetCurrent(Left) - Right.Last;
357 template <
bool OtherConst>
358 requires std::sized_sentinel_for<
359 std::ranges::sentinel_t<Base>,
360 const_iter<OtherConst>>
362 friend constexpr std::ranges::range_difference_t<
363 detail::maybe_const_t<OtherConst, Vw>>
365 const Sentinel& Left,
366 const Iterator<OtherConst>&
367 Right)
noexcept(
noexcept(Left.Last - GetCurrent(Right)))
369 return Left.Last - GetCurrent(Right);
375 requires std::default_initializable<Vw>
378 constexpr explicit convert_view(Vw Range_) noexcept(
379 std::is_nothrow_move_constructible_v<Vw>)
380 : Range(
std::move(Range_))
386 base() const& noexcept(
std::is_nothrow_copy_constructible_v<Vw>)
387 requires
std::copy_constructible<Vw>
393 constexpr Vw base() &&
noexcept(std::is_nothrow_move_constructible_v<Vw>)
395 return std::move(Range);
399 constexpr Iterator<false> begin() noexcept(
400 noexcept(
std::ranges::begin(Range)) &&
401 std::is_nothrow_move_constructible_v<
std::ranges::iterator_t<Vw>>)
403 return Iterator<false>(*
this, std::ranges::begin(Range));
407 constexpr Iterator<true> begin() const noexcept(
408 noexcept(
std::ranges::begin(Range)) &&
409 std::is_nothrow_move_constructible_v<
std::ranges::iterator_t<Vw>>)
410 requires
std::ranges::range<const Vw>
412 return Iterator<true>(*
this, std::ranges::begin(Range));
416 constexpr auto end() noexcept(
417 noexcept(
std::ranges::end(Range)) &&
418 std::is_nothrow_move_constructible_v<decltype(
std::ranges::end(Range))>)
420 if constexpr (std::ranges::common_range<Vw>) {
421 return Iterator<false>(*
this, std::ranges::end(Range));
423 return Sentinel<false>(std::ranges::end(Range));
428 constexpr auto end() const noexcept(
429 noexcept(
std::ranges::end(Range)) &&
430 std::is_nothrow_move_constructible_v<decltype(
std::ranges::end(Range))>)
431 requires
std::ranges::range<const Vw>
433 if constexpr (std::ranges::common_range<Vw>) {
434 return Iterator<true>(*
this, std::ranges::end(Range));
436 return Sentinel<true>(std::ranges::end(Range));
441 constexpr auto size() noexcept(noexcept(
std::ranges::size(Range)))
442 requires
std::ranges::sized_range<Vw>
444 return std::ranges::size(Range);
448 constexpr auto size() const noexcept(noexcept(
std::ranges::size(Range)))
449 requires
std::ranges::sized_range<const Vw>
451 return std::ranges::size(Range);
458using all_t =
decltype(std::views::all(std::declval<T>()));
461struct convert_fn :
public std::ranges::range_adaptor_closure<convert_fn<T>> {
462 template <std::ranges::viewable_range Rng>
464 constexpr auto operator()(Rng&& Range)
const noexcept(
465 noexcept(convert_view<all_t<Rng>, T>(std::forward<Rng>(Range))))
467 convert_view<all_t<Rng>, T>(
static_cast<Rng&&
>(Range));
470 return convert_view<all_t<Rng>, T>(std::forward<Rng>(Range));
477inline constexpr detail::convert_fn<T> convert;