/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 |