1// Copyright (C) 2019 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#include <boost/stl_interfaces/view_interface.hpp>
7
8#include <algorithm>
9#include <vector>
10
11#include <cassert>
12
13
14//[ all_view
15// A subrange is simply an iterator-sentinel pair. This one is a bit simpler
16// than the one in std::ranges; its missing a bunch of constructors, prev(),
17// next(), and advance().
18template<typename Iterator, typename Sentinel>
19struct subrange
20 : boost::stl_interfaces::view_interface<subrange<Iterator, Sentinel>>
21{
22 subrange() = default;
23 constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {}
24
25 constexpr auto begin() const { return first_; }
26 constexpr auto end() const { return last_; }
27
28private:
29 Iterator first_;
30 Sentinel last_;
31};
32
33// std::view::all() returns one of several types, depending on what you pass
34// it. Here, we're keeping it simple; all() always returns a subrange.
35template<typename Range>
36auto all(Range && range)
37{
38 return subrange<decltype(range.begin()), decltype(range.end())>(
39 range.begin(), range.end());
40}
41
42// A template alias that denotes the type of all(r) for some Range r.
43template<typename Range>
44using all_view = decltype(all(std::declval<Range>()));
45//]
46
47//[ drop_while_view_template
48
49// Perhaps its clear now why we defined subrange, all(), etc. above.
50// drop_while_view contains a view data member. If we just took any old range
51// that was passed to drop_while_view's constructor, we'd copy the range
52// itself, which may be a std::vector. So, we want to make a view out of
53// whatever Range we're given so that this copy of an owning range does not
54// happen.
55template<typename Range, typename Pred>
56struct drop_while_view
57 : boost::stl_interfaces::view_interface<drop_while_view<Range, Pred>>
58{
59 using base_type = all_view<Range>;
60
61 drop_while_view() = default;
62
63 constexpr drop_while_view(Range & base, Pred pred) :
64 base_(all(base)),
65 pred_(std::move(pred))
66 {}
67
68 constexpr base_type base() const { return base_; }
69 constexpr Pred const & pred() const noexcept { return pred_; }
70
71 // A more robust implementation should probably cache the value computed
72 // by this function, so that subsequent calls can just return the cached
73 // iterator.
74 constexpr auto begin()
75 {
76 // We're forced to write this out as a raw loop, since no
77 // std::-namespace algorithms accept a sentinel.
78 auto first = base_.begin();
79 auto const last = base_.end();
80 for (; first != last; ++first) {
81 if (!pred_(*first))
82 break;
83 }
84 return first;
85 }
86
87 constexpr auto end() { return base_.end(); }
88
89private:
90 base_type base_;
91 Pred pred_;
92};
93
94// Since this is a C++14 and later library, we're not using CTAD; we therefore
95// need a make-function.
96template<typename Range, typename Pred>
97auto make_drop_while_view(Range & base, Pred pred)
98{
99 return drop_while_view<Range, Pred>(base, std::move(pred));
100}
101//]
102
103
104int main()
105{
106 //[ drop_while_view_usage
107 std::vector<int> const ints = {2, 4, 3, 4, 5, 6};
108
109 // all() returns a subrange, which is a view type containing ints.begin()
110 // and ints.end().
111 auto all_ints = all(range: ints);
112
113 // This works using just the used-defined members of subrange: begin() and
114 // end().
115 assert(
116 std::equal(all_ints.begin(), all_ints.end(), ints.begin(), ints.end()));
117
118 // These are available because subrange is derived from view_interface.
119 assert(all_ints[2] == 3);
120 assert(all_ints.size() == 6u);
121
122 auto even = [](int x) { return x % 2 == 0; };
123 auto ints_after_even_prefix = make_drop_while_view(base: ints, pred: even);
124
125 // Available via begin()/end()...
126 assert(std::equal(
127 ints_after_even_prefix.begin(),
128 ints_after_even_prefix.end(),
129 ints.begin() + 2,
130 ints.end()));
131
132 // ... and via view_interface.
133 assert(!ints_after_even_prefix.empty());
134 assert(ints_after_even_prefix[2] == 5);
135 assert(ints_after_even_prefix.back() == 6);
136 //]
137}
138

source code of boost/libs/stl_interfaces/example/drop_while_view.cpp