File: take_view.hpp

package info (click to toggle)
boost1.90 1.90.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 593,156 kB
  • sloc: cpp: 4,190,642; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,776; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (141 lines) | stat: -rw-r--r-- 4,543 bytes parent folder | download | duplicates (6)
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
138
139
140
141
// Copyright (C) 2022 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)
#ifndef BOOST_STL_INTERFACES_EXAMPLE_TAKE_VIEW_HPP
#define BOOST_STL_INTERFACES_EXAMPLE_TAKE_VIEW_HPP
#include "all_view.hpp"

namespace detail {
    //[ take_view_defn
    // This is a really simple iterator that converts the given iterator Iter
    // to a forward_iterator that counts how many times it has ben
    // incremented.  It counts down from an initial count to zero.
    template<typename Iter>
    struct take_iterator
        : boost::stl_interfaces::iterator_interface<
#if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS
              take_iterator<Iter>,
#endif
              std::forward_iterator_tag,
              typename std::iterator_traits<Iter>::value_type,
              typename std::iterator_traits<Iter>::reference,
              typename std::iterator_traits<Iter>::pointer,
              typename std::iterator_traits<Iter>::difference_type>
    {
        constexpr take_iterator() = default;
        constexpr explicit take_iterator(Iter it, int n) :
            it_(std::move(it)), n_(n)
        {}

        constexpr Iter base() const { return it_; }
        constexpr int count() const { return n_; }

        constexpr take_iterator & operator++()
        {
            ++it_;
            --n_;
            return *this;
        }

    private:
        friend boost::stl_interfaces::access;
        constexpr Iter & base_reference() { return it_; }
        constexpr Iter const & base_reference() const { return it_; }

        template<typename Iter2>
        friend struct take_iterator;

        Iter it_;
        int n_;
    };

    // This sentinel compares equal to any take_iterator whose count has
    // reached zero, or the end of the underlying range if that comes first.
    template<typename Sentinel>
    struct take_sentinel
    {
        take_sentinel() = default;
        explicit take_sentinel(Sentinel sent) : sent_(sent) {}

        template<typename Iter>
        friend constexpr bool
        operator==(take_iterator<Iter> it, take_sentinel s)
        {
            return !it.count() || it.base() == s.sent_;
        }
        template<typename Iter>
        friend constexpr bool
        operator!=(take_iterator<Iter> it, take_sentinel s)
        {
            return !(it == s);
        }

    private:
        Sentinel sent_;
    };

    // The take_iterator and take_sentinel templates do all the hard work,
    // which leaves take_view quite simple.
#if BOOST_STL_INTERFACES_USE_CONCEPTS
    template<std::ranges::view View>
    requires std::is_object_v<View>
#else
    template<
        typename View,
        typename Enable = std::enable_if_t<std::is_object<View>::value>>
#endif
    struct take_view : boost::stl_interfaces::view_interface<take_view<View>>
    {
        using iterator = take_iterator<iterator_t<View>>;
        using sentinel = take_sentinel<sentinel_t<View>>;

        // We don't need a phony initial int param for this constructor, since
        // it already takes two parameters; it won't get confused for a copy
        // or a move.  The count here is just an int to keep things simple.
#if BOOST_STL_INTERFACES_USE_CONCEPTS
        template<typename View2>
        requires std::is_same_v<std::remove_reference_t<View2>, View>
#else
        template<
            typename View2,
            typename E = std::enable_if_t<
                std::is_same<std::remove_reference_t<View2>, View>::value>>
#endif
        explicit take_view(View2 && r, int n) :
            first_(r.begin(), n), last_(r.end())
        {}

        iterator begin() const { return first_; }
        sentinel end() const { return last_; }

    private:
        iterator first_;
        sentinel last_;
    };

#if defined(__cpp_deduction_guides)
    template<typename R>
    take_view(R &&, int)->detail::take_view<std::remove_reference_t<R>>;
#endif
    //]
}

#if defined(__cpp_deduction_guides)
//[ take_defn
// Use the adaptor template to support calling the given lambda with either
// all the parameters or all the parameters after the first.
inline constexpr boost::stl_interfaces::adaptor take =
    []<typename R>(R && r, int n) { return detail::take_view((R &&) r, n); };
//]
#endif

#if BOOST_STL_INTERFACES_USE_CONCEPTS
namespace std::ranges {
    template<typename View>
    inline constexpr bool enable_borrowed_range<detail::take_view<View>> = true;
}
#endif

#endif