Coverage Report

Created: 2023-12-08 06:28

/src/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
  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
503
      : 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.00k
        : container_p_{&container}, indices_{n} {
58
1.00k
      if (n == 0) {
59
503
        steps_ = COMPLETE;
60
503
        return;
61
503
      }
62
503
      size_t inc = 0;
63
2.16k
      for (auto& iter : indices_.get()) {
64
2.16k
        auto it = get_begin(*container_p_);
65
2.16k
        dumb_advance(it, get_end(*container_p_), inc);
66
2.16k
        if (it != get_end(*container_p_)) {
67
1.99k
          iter = it;
68
1.99k
          ++inc;
69
1.99k
        } else {
70
174
          steps_ = COMPLETE;
71
174
          break;
72
174
        }
73
2.16k
      }
74
503
    }
75
76
294k
    CombIteratorDeref<ContainerT>& operator*() {
77
294k
      return indices_;
78
294k
    }
79
80
    CombIteratorDeref<ContainerT>* operator->() {
81
      return &indices_;
82
    }
83
84
294k
    Iterator& operator++() {
85
327k
      for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend();
86
327k
           ++iter) {
87
327k
        ++(*iter);
88
89
        // what we have to check here is if the distance between
90
        // the index and the end of indices_ is >= the distance
91
        // between the item and end of item
92
327k
        auto dist = std::distance(indices_.get().rbegin(), iter);
93
94
327k
        if (!(dumb_next(*iter, dist) != get_end(*container_p_))) {
95
33.3k
          if ((iter + 1) != indices_.get().rend()) {
96
33.2k
            size_t inc = 1;
97
54.4k
            for (auto down = iter; ; --down) {
98
54.4k
              (*down) = dumb_next(*(iter + 1), 1 + inc);
99
54.4k
              ++inc;
100
54.4k
              if (down == indices_.get().rbegin())
101
33.2k
                break;
102
54.4k
            }
103
33.2k
          } else {
104
148
            steps_ = COMPLETE;
105
148
            break;
106
148
          }
107
294k
        } else {
108
294k
          break;
109
294k
        }
110
        // we break because none of the rest of the items need
111
        // to be incremented
112
327k
      }
113
294k
      if (steps_ != COMPLETE) {
114
294k
        ++steps_;
115
294k
      }
116
294k
      return *this;
117
294k
    }
118
119
    Iterator operator++(int) {
120
      auto ret = *this;
121
      ++*this;
122
      return ret;
123
    }
124
125
    template <typename T>
126
295k
    bool operator!=(const Iterator<T>& other) const {
127
295k
      return !(*this == other);
128
295k
    }
129
130
    template <typename T>
131
295k
    bool operator==(const Iterator<T>& other) const {
132
295k
      return steps_ == other.steps_;
133
295k
    }
134
  };
135
136
503
  Iterator<Container> begin() {
137
503
    return {container_, length_};
138
503
  }
139
140
503
  Iterator<Container> end() {
141
503
    return {container_, 0};
142
503
  }
143
144
  Iterator<AsConst<Container>> begin() const {
145
    return {std::as_const(container_), length_};
146
  }
147
148
  Iterator<AsConst<Container>> end() const {
149
    return {std::as_const(container_), 0};
150
  }
151
};
152
153
#endif