Coverage Report

Created: 2025-10-10 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cppitertools/cppitertools/internal/iteratoriterator.hpp
Line
Count
Source
1
#ifndef ITERATOR_ITERATOR_HPP_
2
#define ITERATOR_ITERATOR_HPP_
3
4
#include <iterator>
5
#include <type_traits>
6
#include <utility>
7
#include "iterbase.hpp"
8
9
// IterIterWrapper and IteratorIterator provide a means to have a container
10
// of iterators act like a container of the pointed to objects. This is useful
11
// for combinatorics and similar itertools which need to keep track of
12
// more than one element at a time.
13
// an IterIterWrapper<some_collection_type<collection<T>::iterator>>
14
// behave like some_collection<T> when iterated over or indexed
15
16
namespace iter {
17
  namespace impl {
18
    template <typename T, typename = void>
19
    struct HasConstDeref : std::false_type {};
20
21
    template <typename T>
22
    struct HasConstDeref<T, std::void_t<decltype(*std::declval<const T&>())>>
23
        : std::true_type {};
24
25
    template <typename TopIter>
26
    class IteratorIterator {
27
      template <typename>
28
      friend class IteratorIterator;
29
      using Diff = std::ptrdiff_t;
30
      static_assert(
31
          std::is_same<
32
              typename std::iterator_traits<TopIter>::iterator_category,
33
              std::random_access_iterator_tag>::value,
34
          "IteratorIterator only works with random access iterators");
35
36
     private:
37
      TopIter sub_iter;
38
39
     public:
40
      using iterator_category = std::random_access_iterator_tag;
41
      using value_type = std::remove_cv_t<
42
          std::remove_reference_t<decltype(**std::declval<TopIter>())>>;
43
      using difference_type = std::ptrdiff_t;
44
      using pointer =
45
          std::remove_reference_t<decltype(**std::declval<TopIter>())>*;
46
      using reference = std::add_lvalue_reference_t<
47
          std::remove_reference_t<decltype(**std::declval<TopIter>())>>;
48
49
      IteratorIterator() = default;
50
665k
      IteratorIterator(const TopIter& it) : sub_iter{it} {}
51
52
      const TopIter& get() const {
53
        return sub_iter;
54
      }
55
56
      template <typename T>
57
      bool operator==(const IteratorIterator<T>& other) const {
58
        return !(*this != other);
59
      }
60
61
      template <typename T>
62
2.75M
      bool operator!=(const IteratorIterator<T>& other) const {
63
2.75M
        return this->sub_iter != other.sub_iter;
64
2.75M
      }
65
66
2.42M
      IteratorIterator& operator++() {
67
2.42M
        ++this->sub_iter;
68
2.42M
        return *this;
69
2.42M
      }
70
71
      IteratorIterator operator++(int) {
72
        auto ret = *this;
73
        ++*this;
74
        return ret;
75
      }
76
77
      IteratorIterator& operator--() {
78
        --this->sub_iter;
79
        return *this;
80
      }
81
82
      IteratorIterator operator--(int) {
83
        auto ret = *this;
84
        --*this;
85
        return ret;
86
      }
87
88
2.42M
      auto operator*() const -> decltype(**sub_iter) {
89
2.42M
        return **this->sub_iter;
90
2.42M
      }
91
92
      auto operator->() const -> decltype(*sub_iter) {
93
        return *this->sub_iter;
94
      }
95
96
      IteratorIterator& operator+=(Diff n) {
97
        this->sub_iter += n;
98
        return *this;
99
      }
100
101
      IteratorIterator operator+(Diff n) const {
102
        auto it = *this;
103
        it += n;
104
        return it;
105
      }
106
107
      friend IteratorIterator operator+(Diff n, IteratorIterator it) {
108
        it += n;
109
        return it;
110
      }
111
112
      IteratorIterator& operator-=(Diff n) {
113
        this->sub_iter -= n;
114
        return *this;
115
      }
116
117
      IteratorIterator operator-(Diff n) const {
118
        auto it = *this;
119
        it -= n;
120
        return it;
121
      }
122
123
332k
      Diff operator-(const IteratorIterator& rhs) const {
124
332k
        return this->sub_iter - rhs.sub_iter;
125
332k
      }
126
127
      auto operator[](Diff idx) const -> decltype(*sub_iter[idx]) {
128
        return *sub_iter[idx];
129
      }
130
131
      bool operator<(const IteratorIterator& rhs) const {
132
        return this->sub_iter < rhs.sub_iter;
133
      }
134
135
      bool operator>(const IteratorIterator& rhs) const {
136
        return this->sub_iter > rhs.sub_iter;
137
      }
138
139
      bool operator<=(const IteratorIterator& rhs) const {
140
        return this->sub_iter <= rhs.sub_iter;
141
      }
142
143
      bool operator>=(const IteratorIterator& rhs) const {
144
        return this->sub_iter >= rhs.sub_iter;
145
      }
146
    };
147
148
    template <typename Container>
149
    class IterIterWrapper {
150
     private:
151
      Container container;
152
153
      using contained_iter = typename Container::value_type;
154
      using size_type = typename Container::size_type;
155
      using iterator = IteratorIterator<typename Container::iterator>;
156
      using const_iterator =
157
          IteratorIterator<typename Container::const_iterator>;
158
      using reverse_iterator =
159
          IteratorIterator<typename Container::reverse_iterator>;
160
      using const_reverse_iterator =
161
          IteratorIterator<typename Container::const_reverse_iterator>;
162
163
      template <typename U = Container, typename = void>
164
      struct ConstAtTypeOrVoid : type_is<void> {};
165
166
      template <typename U>
167
      struct ConstAtTypeOrVoid<U,
168
          std::void_t<decltype(*std::declval<const U&>().at(0))>>
169
          : type_is<decltype(*std::declval<const U&>().at(0))> {};
170
171
      using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type;
172
173
      template <typename U = Container, typename = void>
174
      struct ConstIndexTypeOrVoid : type_is<void> {};
175
176
      template <typename U>
177
      struct ConstIndexTypeOrVoid<U,
178
          std::void_t<decltype(*std::declval<const U&>()[0])>>
179
          : type_is<decltype(*std::declval<const U&>()[0])> {};
180
181
      using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type;
182
183
     public:
184
      IterIterWrapper() = default;
185
186
1.17k
      explicit IterIterWrapper(size_type sz) : container(sz) {}
187
188
      IterIterWrapper(size_type sz, const contained_iter& val)
189
          : container(sz, val) {}
190
191
      auto at(size_type pos) -> decltype(*container.at(pos)) {
192
        return *container.at(pos);
193
      }
194
195
      auto at(size_type pos) const -> const_at_type_or_void_t {
196
        return *container.at(pos);
197
      }
198
199
      auto operator[](size_type pos) noexcept(noexcept(*container[pos]))
200
          -> decltype(*container[pos]) {
201
        return *container[pos];
202
      }
203
204
      auto operator[](size_type pos) const noexcept(noexcept(*container[pos]))
205
          -> const_index_type_or_void_t {
206
        return *container[pos];
207
      }
208
209
      bool empty() const noexcept {
210
        return container.empty();
211
      }
212
213
      size_type size() const noexcept {
214
        return container.size();
215
      }
216
217
332k
      iterator begin() noexcept {
218
332k
        return {container.begin()};
219
332k
      }
220
221
332k
      iterator end() noexcept {
222
332k
        return {container.end()};
223
332k
      }
224
225
      const_iterator begin() const noexcept {
226
        return {container.begin()};
227
      }
228
229
      const_iterator end() const noexcept {
230
        return {container.end()};
231
      }
232
233
      const_iterator cbegin() const noexcept {
234
        return {container.cbegin()};
235
      }
236
237
      const_iterator cend() const noexcept {
238
        return {container.cend()};
239
      }
240
241
      reverse_iterator rbegin() noexcept {
242
        return {container.rbegin()};
243
      }
244
245
      reverse_iterator rend() noexcept {
246
        return {container.rend()};
247
      }
248
249
      const_reverse_iterator rbegin() const noexcept {
250
        return {container.rbegin()};
251
      }
252
253
      const_reverse_iterator rend() const noexcept {
254
        return {container.rend()};
255
      }
256
257
      const_reverse_iterator crbegin() const noexcept {
258
        return {container.rbegin()};
259
      }
260
261
      const_reverse_iterator crend() const noexcept {
262
        return {container.rend()};
263
      }
264
265
      // get() exposes the underlying container.  this allows the
266
      // itertools to manipulate the iterators in the container
267
      // and should not be depended on anywhere else.
268
1.46M
      Container& get() noexcept {
269
1.46M
        return container;
270
1.46M
      }
271
272
      const Container& get() const noexcept {
273
        return container;
274
      }
275
    };
276
  }
277
}
278
279
#endif