File: drop_while_view.cpp

package info (click to toggle)
boost1.90 1.90.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 593,120 kB
  • sloc: cpp: 4,190,908; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,774; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (137 lines) | stat: -rw-r--r-- 4,191 bytes parent folder | download | duplicates (13)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (C) 2019 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/stl_interfaces/view_interface.hpp>

#include <algorithm>
#include <vector>

#include <cassert>


//[ all_view
// A subrange is simply an iterator-sentinel pair.  This one is a bit simpler
// than the one in std::ranges; its missing a bunch of constructors, prev(),
// next(), and advance().
template<typename Iterator, typename Sentinel>
struct subrange
    : boost::stl_interfaces::view_interface<subrange<Iterator, Sentinel>>
{
    subrange() = default;
    constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {}

    constexpr auto begin() const { return first_; }
    constexpr auto end() const { return last_; }

private:
    Iterator first_;
    Sentinel last_;
};

// std::view::all() returns one of several types, depending on what you pass
// it.  Here, we're keeping it simple; all() always returns a subrange.
template<typename Range>
auto all(Range && range)
{
    return subrange<decltype(range.begin()), decltype(range.end())>(
        range.begin(), range.end());
}

// A template alias that denotes the type of all(r) for some Range r.
template<typename Range>
using all_view = decltype(all(std::declval<Range>()));
//]

//[ drop_while_view_template

// Perhaps its clear now why we defined subrange, all(), etc. above.
// drop_while_view contains a view data member.  If we just took any old range
// that was passed to drop_while_view's constructor, we'd copy the range
// itself, which may be a std::vector.  So, we want to make a view out of
// whatever Range we're given so that this copy of an owning range does not
// happen.
template<typename Range, typename Pred>
struct drop_while_view
    : boost::stl_interfaces::view_interface<drop_while_view<Range, Pred>>
{
    using base_type = all_view<Range>;

    drop_while_view() = default;

    constexpr drop_while_view(Range & base, Pred pred) :
        base_(all(base)),
        pred_(std::move(pred))
    {}

    constexpr base_type base() const { return base_; }
    constexpr Pred const & pred() const noexcept { return pred_; }

    // A more robust implementation should probably cache the value computed
    // by this function, so that subsequent calls can just return the cached
    // iterator.
    constexpr auto begin()
    {
        // We're forced to write this out as a raw loop, since no
        // std::-namespace algorithms accept a sentinel.
        auto first = base_.begin();
        auto const last = base_.end();
        for (; first != last; ++first) {
            if (!pred_(*first))
                break;
        }
        return first;
    }

    constexpr auto end() { return base_.end(); }

private:
    base_type base_;
    Pred pred_;
};

// Since this is a C++14 and later library, we're not using CTAD; we therefore
// need a make-function.
template<typename Range, typename Pred>
auto make_drop_while_view(Range & base, Pred pred)
{
    return drop_while_view<Range, Pred>(base, std::move(pred));
}
//]


int main()
{
    //[ drop_while_view_usage
    std::vector<int> const ints = {2, 4, 3, 4, 5, 6};

    // all() returns a subrange, which is a view type containing ints.begin()
    // and ints.end().
    auto all_ints = all(ints);

    // This works using just the used-defined members of subrange: begin() and
    // end().
    assert(
        std::equal(all_ints.begin(), all_ints.end(), ints.begin(), ints.end()));

    // These are available because subrange is derived from view_interface.
    assert(all_ints[2] == 3);
    assert(all_ints.size() == 6u);

    auto even = [](int x) { return x % 2 == 0; };
    auto ints_after_even_prefix = make_drop_while_view(ints, even);

    // Available via begin()/end()...
    assert(std::equal(
        ints_after_even_prefix.begin(),
        ints_after_even_prefix.end(),
        ints.begin() + 2,
        ints.end()));

    // ... and via view_interface.
    assert(!ints_after_even_prefix.empty());
    assert(ints_after_even_prefix[2] == 5);
    assert(ints_after_even_prefix.back() == 6);
    //]
}