• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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().
18 template<typename Iterator, typename Sentinel>
19 struct subrange
20     : boost::stl_interfaces::view_interface<subrange<Iterator, Sentinel>>
21 {
22     subrange() = default;
subrangesubrange23     constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {}
24 
beginsubrange25     constexpr auto begin() const { return first_; }
endsubrange26     constexpr auto end() const { return last_; }
27 
28 private:
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.
35 template<typename Range>
all(Range && range)36 auto 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.
43 template<typename Range>
44 using 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.
55 template<typename Range, typename Pred>
56 struct 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 
drop_while_viewdrop_while_view63     constexpr drop_while_view(Range & base, Pred pred) :
64         base_(all(base)),
65         pred_(std::move(pred))
66     {}
67 
basedrop_while_view68     constexpr base_type base() const { return base_; }
preddrop_while_view69     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.
begindrop_while_view74     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 
enddrop_while_view87     constexpr auto end() { return base_.end(); }
88 
89 private:
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.
96 template<typename Range, typename Pred>
make_drop_while_view(Range & base,Pred pred)97 auto make_drop_while_view(Range & base, Pred pred)
98 {
99     return drop_while_view<Range, Pred>(base, std::move(pred));
100 }
101 //]
102 
103 
main()104 int 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(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(ints, 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