Coverage Report

Created: 2026-01-15 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cppitertools/cppitertools/combinations.hpp
Line
Count
Source
1
#ifndef ITER_COMBINATIONS_HPP_
2
#define ITER_COMBINATIONS_HPP_
3
4
#include "internal/iteratoriterator.hpp"
5
#include "internal/iterbase.hpp"
6
7
#include <iterator>
8
#include <type_traits>
9
#include <vector>
10
11
namespace iter {
12
  namespace impl {
13
    template <typename Container>
14
    class Combinator;
15
16
    using CombinationsFn = IterToolFnBindSizeTSecond<Combinator>;
17
  }
18
  inline constexpr impl::CombinationsFn combinations{};
19
}
20
21
template <typename Container>
22
class iter::impl::Combinator {
23
 private:
24
  Container container_;
25
  std::size_t length_;
26
27
  friend CombinationsFn;
28
29
  Combinator(Container&& container, std::size_t length)
30
599
      : container_(std::forward<Container>(container)), length_{length} {}
31
32
  template <typename T>
33
  using IndexVector = std::vector<iterator_type<T>>;
34
  template <typename T>
35
  using CombIteratorDeref = IterIterWrapper<IndexVector<T>>;
36
37
 public:
38
  Combinator(Combinator&&) = default;
39
  template <typename ContainerT>
40
  class Iterator {
41
   private:
42
    template <typename>
43
    friend class Iterator;
44
    constexpr static const int COMPLETE = -1;
45
    std::remove_reference_t<ContainerT>* container_p_;
46
    CombIteratorDeref<ContainerT> indices_;
47
    int steps_{};
48
49
   public:
50
    using iterator_category = std::input_iterator_tag;
51
    using value_type = CombIteratorDeref<ContainerT>;
52
    using difference_type = std::ptrdiff_t;
53
    using pointer = value_type*;
54
    using reference = value_type&;
55
56
    Iterator(ContainerT& container, std::size_t n)
57
1.19k
        : container_p_{&container}, indices_{n} {
58
1.19k
      if (n == 0) {
59
599
        steps_ = COMPLETE;
60
599
        return;
61
599
      }
62
599
      size_t inc = 0;
63
2.29k
      for (auto& iter : indices_.get()) {
64
2.29k
        auto it = get_begin(*container_p_);
65
2.29k
        dumb_advance(it, get_end(*container_p_), inc);
66
2.29k
        if (it != get_end(*container_p_)) {
67
2.10k
          iter = it;
68
2.10k
          ++inc;
69
2.10k
        } else {
70
192
          steps_ = COMPLETE;
71
192
          break;
72
192
        }
73
2.29k
      }
74
599
    }
75
76
0
    static Iterator zero_length_end(ContainerT& container) {
77
0
      Iterator it{container, 0};
78
0
      it.steps_ = 0;
79
0
      return it;
80
0
    }
81
82
325k
    CombIteratorDeref<ContainerT>& operator*() {
83
325k
      return indices_;
84
325k
    }
85
86
    CombIteratorDeref<ContainerT>* operator->() {
87
      return &indices_;
88
    }
89
90
324k
    Iterator& operator++() {
91
324k
      if (indices_.get().empty()) {
92
        // zero-length case.
93
0
        ++steps_;
94
0
        return *this;
95
0
      }
96
366k
      for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend();
97
366k
           ++iter) {
98
366k
        ++(*iter);
99
100
        // what we have to check here is if the distance between
101
        // the index and the end of indices_ is >= the distance
102
        // between the item and end of item
103
366k
        auto dist = std::distance(indices_.get().rbegin(), iter);
104
105
366k
        if (!(dumb_next(*iter, dist) != get_end(*container_p_))) {
106
41.4k
          if ((iter + 1) != indices_.get().rend()) {
107
41.2k
            size_t inc = 1;
108
62.6k
            for (auto down = iter;; --down) {
109
62.6k
              (*down) = dumb_next(*(iter + 1), 1 + inc);
110
62.6k
              ++inc;
111
62.6k
              if (down == indices_.get().rbegin()) break;
112
62.6k
            }
113
41.2k
          } else {
114
215
            steps_ = COMPLETE;
115
215
            break;
116
215
          }
117
324k
        } else {
118
324k
          break;
119
324k
        }
120
        // we break because none of the rest of the items need
121
        // to be incremented
122
366k
      }
123
324k
      if (steps_ != COMPLETE) {
124
324k
        ++steps_;
125
324k
      }
126
324k
      return *this;
127
324k
    }
128
129
    Iterator operator++(int) {
130
      auto ret = *this;
131
      ++*this;
132
      return ret;
133
    }
134
135
    template <typename T>
136
325k
    bool operator!=(const Iterator<T>& other) const {
137
325k
      return !(*this == other);
138
325k
    }
139
140
    template <typename T>
141
325k
    bool operator==(const Iterator<T>& other) const {
142
325k
      return steps_ == other.steps_;
143
325k
    }
144
  };
145
146
599
  Iterator<Container> begin() {
147
599
    return {container_, length_};
148
599
  }
149
150
599
  Iterator<Container> end() {
151
599
    if (length_ == 0) {
152
0
      return Iterator<Container>::zero_length_end(container_);
153
0
    }
154
599
    return {container_, 0};
155
599
  }
156
157
  Iterator<AsConst<Container>> begin() const {
158
    return {std::as_const(container_), length_};
159
  }
160
161
  Iterator<AsConst<Container>> end() const {
162
    if (length_ == 0) {
163
      return Iterator<AsConst<Container>>::zero_length_end(container_);
164
    }
165
    return {std::as_const(container_), 0};
166
  }
167
};
168
169
#endif