1// Copyright (C) 2022 T. Zachary Laine
2//
3// Distributed under the Boost Software License, Version 1.0. (See
4// accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6#ifndef BOOST_STL_INTERFACES_EXAMPLE_TAKE_VIEW_HPP
7#define BOOST_STL_INTERFACES_EXAMPLE_TAKE_VIEW_HPP
8#include "all_view.hpp"
9
10namespace detail {
11 //[ take_view_defn
12 // This is a really simple iterator that converts the given iterator Iter
13 // to a forward_iterator that counts how many times it has ben
14 // incremented. It counts down from an initial count to zero.
15 template<typename Iter>
16 struct take_iterator
17 : boost::stl_interfaces::iterator_interface<
18#if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS
19 take_iterator<Iter>,
20#endif
21 std::forward_iterator_tag,
22 typename std::iterator_traits<Iter>::value_type,
23 typename std::iterator_traits<Iter>::reference,
24 typename std::iterator_traits<Iter>::pointer,
25 typename std::iterator_traits<Iter>::difference_type>
26 {
27 constexpr take_iterator() = default;
28 constexpr explicit take_iterator(Iter it, int n) :
29 it_(std::move(it)), n_(n)
30 {}
31
32 constexpr Iter base() const { return it_; }
33 constexpr int count() const { return n_; }
34
35 constexpr take_iterator & operator++()
36 {
37 ++it_;
38 --n_;
39 return *this;
40 }
41
42 private:
43 friend boost::stl_interfaces::access;
44 constexpr Iter & base_reference() { return it_; }
45 constexpr Iter const & base_reference() const { return it_; }
46
47 template<typename Iter2>
48 friend struct take_iterator;
49
50 Iter it_;
51 int n_;
52 };
53
54 // This sentinel compares equal to any take_iterator whose count has
55 // reached zero, or the end of the underlying range if that comes first.
56 template<typename Sentinel>
57 struct take_sentinel
58 {
59 take_sentinel() = default;
60 explicit take_sentinel(Sentinel sent) : sent_(sent) {}
61
62 template<typename Iter>
63 friend constexpr bool
64 operator==(take_iterator<Iter> it, take_sentinel s)
65 {
66 return !it.count() || it.base() == s.sent_;
67 }
68 template<typename Iter>
69 friend constexpr bool
70 operator!=(take_iterator<Iter> it, take_sentinel s)
71 {
72 return !(it == s);
73 }
74
75 private:
76 Sentinel sent_;
77 };
78
79 // The take_iterator and take_sentinel templates do all the hard work,
80 // which leaves take_view quite simple.
81#if BOOST_STL_INTERFACES_USE_CONCEPTS
82 template<std::ranges::view View>
83 requires std::is_object_v<View>
84#else
85 template<
86 typename View,
87 typename Enable = std::enable_if_t<std::is_object<View>::value>>
88#endif
89 struct take_view : boost::stl_interfaces::view_interface<take_view<View>>
90 {
91 using iterator = take_iterator<iterator_t<View>>;
92 using sentinel = take_sentinel<sentinel_t<View>>;
93
94 // We don't need a phony initial int param for this constructor, since
95 // it already takes two parameters; it won't get confused for a copy
96 // or a move. The count here is just an int to keep things simple.
97#if BOOST_STL_INTERFACES_USE_CONCEPTS
98 template<typename View2>
99 requires std::is_same_v<std::remove_reference_t<View2>, View>
100#else
101 template<
102 typename View2,
103 typename E = std::enable_if_t<
104 std::is_same<std::remove_reference_t<View2>, View>::value>>
105#endif
106 explicit take_view(View2 && r, int n) :
107 first_(r.begin(), n), last_(r.end())
108 {}
109
110 iterator begin() const { return first_; }
111 sentinel end() const { return last_; }
112
113 private:
114 iterator first_;
115 sentinel last_;
116 };
117
118#if defined(__cpp_deduction_guides)
119 template<typename R>
120 take_view(R &&, int)->detail::take_view<std::remove_reference_t<R>>;
121#endif
122 //]
123}
124
125#if defined(__cpp_deduction_guides)
126//[ take_defn
127// Use the adaptor template to support calling the given lambda with either
128// all the parameters or all the parameters after the first.
129inline constexpr boost::stl_interfaces::adaptor take =
130 []<typename R>(R && r, int n) { return detail::take_view((R &&) r, n); };
131//]
132#endif
133
134#if BOOST_STL_INTERFACES_USE_CONCEPTS
135namespace std::ranges {
136 template<typename View>
137 inline constexpr bool enable_borrowed_range<detail::take_view<View>> = true;
138}
139#endif
140
141#endif
142

source code of boost/libs/stl_interfaces/example/take_view.hpp