TRIQS/itertools 2.0.0
C++ range library
Loading...
Searching...
No Matches
product.hpp
Go to the documentation of this file.
1// Copyright (c) 2024 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Thomas Hahn, Olivier Parcollet, Nils Wentzell, chuffa
16
21
22#ifndef _ITERTOOLS_PRODUCT_HPP
23#define _ITERTOOLS_PRODUCT_HPP
24
25#include "./iterator_facade.hpp"
26#include "./sentinel.hpp"
27
28#include <cstddef>
29#include <iterator>
30#include <tuple>
31#include <utility>
32#include <vector>
33
34namespace itertools {
35
56 template <typename EndIters, typename... Iters>
57 struct prod_iter : iterator_facade<prod_iter<EndIters, Iters...>, std::tuple<typename std::iterator_traits<Iters>::value_type...>> {
59 std::tuple<Iters...> its_begin;
60
62 EndIters its_end;
63
65 std::tuple<Iters...> its = its_begin;
66
68 static constexpr long Rank = sizeof...(Iters);
69
71 prod_iter() = default;
72
79 prod_iter(std::tuple<Iters...> its_begin, EndIters its_end) : its_begin(std::move(its_begin)), its_end(std::move(its_end)) {}
80
81 private:
82 // Helper function to recursively increment the current iterators.
83 template <int N> void _increment() {
84 // increment Nth iterator
85 ++std::get<N>(its);
86 // recursively increment previous iterators if necessary
87 if constexpr (N > 0) {
88 // if Nth iterator is at its end, reset it to its begin iterator and increment N-1st iterator
89 if (std::get<N>(its) == std::get<N>(its_end)) {
90 std::get<N>(its) = std::get<N>(its_begin);
91 _increment<N - 1>();
92 }
93 }
94 }
95
96 public:
98 void increment() { _increment<Rank - 1>(); }
99
106 [[nodiscard]] bool operator==(prod_iter const &other) const { return its == other.its; }
107
117 template <typename SentinelIter> [[nodiscard]] bool operator==(sentinel_t<SentinelIter> const &s) const { return (s.it == std::get<0>(its)); }
118
119 private:
120 // Helper function to dereference all original iterators.
121 template <size_t... Is> [[gnu::always_inline]] [[nodiscard]] auto tuple_map_impl(std::index_sequence<Is...>) const {
122 return std::tuple<decltype(*std::get<Is>(its))...>(*std::get<Is>(its)...);
123 }
124
125 public:
130 [[nodiscard]] decltype(auto) dereference() const { return tuple_map_impl(std::index_sequence_for<Iters...>{}); }
131 };
132
141 template <typename... Rs> struct multiplied {
143 std::tuple<Rs...> tu;
144
146 using iterator = prod_iter<std::tuple<decltype(std::end(std::declval<Rs &>()))...>, decltype(std::begin(std::declval<Rs &>()))...>;
147
149 using const_iterator = prod_iter<std::tuple<decltype(std::cend(std::declval<Rs &>()))...>, decltype(std::cbegin(std::declval<Rs &>()))...>;
150
157 template <typename... Us> multiplied(Us &&...rgs) : tu{std::forward<Us>(rgs)...} {}
158
160 [[nodiscard]] bool operator==(multiplied const &) const = default;
161
162 private:
163 // Helper function to create an itertools::prod_iter representing the beginning of the product range.
164 template <size_t... Is> [[gnu::always_inline]] auto _begin(std::index_sequence<Is...>) {
165 return iterator{std::make_tuple(std::begin(std::get<Is>(tu))...), std::make_tuple(std::end(std::get<Is>(tu))...)};
166 }
167
168 // Const version of _begin(std::index_sequence<Is...>).
169 template <size_t... Is> [[gnu::always_inline]] auto _cbegin(std::index_sequence<Is...>) const {
170 return const_iterator{std::make_tuple(std::cbegin(std::get<Is>(tu))...), std::make_tuple(std::cend(std::get<Is>(tu))...)};
171 }
172
173 public:
178 [[nodiscard]] iterator begin() noexcept { return _begin(std::index_sequence_for<Rs...>{}); }
179
181 [[nodiscard]] const_iterator cbegin() const noexcept { return _cbegin(std::index_sequence_for<Rs...>{}); }
182
184 [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); }
185
191 [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(std::get<0>(tu))); }
192
194 [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(std::get<0>(tu))); }
195
197 [[nodiscard]] auto end() const noexcept { return cend(); }
198 };
199
200 // Class template argument deduction guide.
201 template <typename... Rs> multiplied(Rs &&...) -> multiplied<std::decay_t<Rs>...>;
202
220 template <typename Iter>
221 struct prod_iter_vec : iterator_facade<prod_iter_vec<Iter>, std::vector<typename std::iterator_traits<Iter>::value_type>> {
223 using value_type = typename std::iterator_traits<Iter>::value_type;
224
226 std::vector<Iter> its_begin;
227
229 std::vector<Iter> its_end;
230
232 std::vector<Iter> its;
233
235 bool done = false;
236
238 prod_iter_vec() = default;
239
246 prod_iter_vec(std::vector<Iter> its_begin, std::vector<Iter> its_end)
247 : its_begin(std::move(its_begin)), its_end(std::move(its_end)), its(this->its_begin) {}
248
250 void increment() {
251 if (its.empty()) {
252 done = true;
253 return;
254 }
255 for (std::size_t i = its.size(); i-- > 1;) {
256 ++its[i];
257 if (its[i] != its_end[i]) return;
258 its[i] = its_begin[i];
259 }
260 ++its[0];
261 }
262
269 [[nodiscard]] bool operator==(prod_iter_vec const &other) const { return its == other.its && done == other.done; }
270
281 template <typename SentinelIter> [[nodiscard]] bool operator==(sentinel_t<SentinelIter> const &s) const {
282 if (its.empty()) return done;
283 return s.it == its[0];
284 }
285
290 [[nodiscard]] std::vector<value_type> dereference() const {
291 std::vector<value_type> result;
292 result.reserve(its.size());
293 for (auto const &it : its) result.push_back(*it);
294 return result;
295 }
296 };
297
306 template <typename R> struct multiplied_vec {
308 std::vector<R> tu;
309
312
315
321 explicit multiplied_vec(std::vector<R> rgs) : tu(std::move(rgs)) {}
322
324 [[nodiscard]] bool operator==(multiplied_vec const &) const = default;
325
330 [[nodiscard]] iterator begin() noexcept {
331 std::vector<decltype(std::begin(std::declval<R &>()))> b, e;
332 b.reserve(tu.size());
333 e.reserve(tu.size());
334 for (auto &r : tu) {
335 b.push_back(std::begin(r));
336 e.push_back(std::end(r));
337 }
338 return iterator{std::move(b), std::move(e)};
339 }
340
342 [[nodiscard]] const_iterator cbegin() const noexcept {
343 std::vector<decltype(std::cbegin(std::declval<R const &>()))> b, e;
344 b.reserve(tu.size());
345 e.reserve(tu.size());
346 for (auto const &r : tu) {
347 b.push_back(std::cbegin(r));
348 e.push_back(std::cend(r));
349 }
350 return const_iterator{std::move(b), std::move(e)};
351 }
352
354 [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); }
355
361 [[nodiscard]] auto end() noexcept {
362 using SentinelIter = decltype(std::end(std::declval<R &>()));
363 if (tu.empty()) return make_sentinel(SentinelIter{});
364 return make_sentinel(std::end(tu[0]));
365 }
366
368 [[nodiscard]] auto cend() const noexcept {
369 using SentinelIter = decltype(std::cend(std::declval<R const &>()));
370 if (tu.empty()) return make_sentinel(SentinelIter{});
371 return make_sentinel(std::cend(tu[0]));
372 }
373
375 [[nodiscard]] auto end() const noexcept { return cend(); }
376 };
377
382
413 template <typename... Rs> [[nodiscard]] itertools::multiplied<Rs...> product(Rs &&...rgs) { return {std::forward<Rs>(rgs)...}; }
414
454 template <typename R> [[nodiscard]] itertools::multiplied_vec<R> product_vec(std::vector<R> rgs) { return multiplied_vec<R>{std::move(rgs)}; }
455
456 namespace detail {
457
458 // Helper function to create a product range from a container of ranges.
459 template <typename C, size_t... Is> [[gnu::always_inline]] [[nodiscard]] auto make_product_impl(C &cont, std::index_sequence<Is...>) {
460 return product(cont[Is]...);
461 }
462
463 } // namespace detail
464
473 template <typename R, size_t N> [[nodiscard]] auto make_product(std::array<R, N> &arr) {
474 return detail::make_product_impl(arr, std::make_index_sequence<N>{});
475 }
476
478 template <typename R, size_t N> [[nodiscard]] auto make_product(std::array<R, N> const &arr) {
479 return detail::make_product_impl(arr, std::make_index_sequence<N>{});
480 }
481
483
484} // namespace itertools
485
486#endif // _ITERTOOLS_PRODUCT_HPP
itertools::multiplied_vec< R > product_vec(std::vector< R > rgs)
Lazy-multiply a vector of homogeneous ranges by forming their cartesian product.
Definition product.hpp:454
auto make_product(std::array< R, N > &arr)
Create a cartesian product range from an array of ranges.
Definition product.hpp:473
itertools::multiplied< Rs... > product(Rs &&...rgs)
Lazy-multiply a given number of ranges by forming their cartesian product.
Definition product.hpp:413
sentinel_t< Iter > make_sentinel(Iter it)
Create an itertools::sentinel_t from an iterator using template type deduction.
Definition sentinel.hpp:50
Provides a CRTP base class for various iterator types in itertools.
Provides a generic sentinel type for various iterator types in itertools.
Represents a cartesian product of homogeneous ranges stored in a vector.
Definition product.hpp:306
auto end() const noexcept
Const overload of end().
Definition product.hpp:375
const_iterator begin() const noexcept
Const overload of begin().
Definition product.hpp:354
prod_iter_vec< decltype(std::cbegin(std::declval< R & >()))> const_iterator
Const iterator type of the product range.
Definition product.hpp:314
const_iterator cbegin() const noexcept
Const version of begin().
Definition product.hpp:342
iterator begin() noexcept
Beginning of the product range.
Definition product.hpp:330
prod_iter_vec< decltype(std::begin(std::declval< R & >()))> iterator
Iterator type of the product range.
Definition product.hpp:311
bool operator==(multiplied_vec const &) const =default
Default equal-to operator.
auto cend() const noexcept
Const version of end().
Definition product.hpp:368
std::vector< R > tu
Vector containing the original ranges.
Definition product.hpp:308
multiplied_vec(std::vector< R > rgs)
Constructs a cartesian product (multiplied_vec) range from a vector of ranges.
Definition product.hpp:321
auto end() noexcept
End of the product range.
Definition product.hpp:361
Represents a cartesian product of ranges.
Definition product.hpp:141
std::tuple< Rs... > tu
Tuple containing the original ranges.
Definition product.hpp:143
prod_iter< std::tuple< decltype(std::end(std::declval< Rs & >()))... >, decltype(std::begin(std::declval< Rs & >()))... > iterator
Iterator type of the product range.
Definition product.hpp:146
multiplied(Us &&...rgs)
Constructs a cartesian product (multiplied) range from the given ranges.
Definition product.hpp:157
const_iterator cbegin() const noexcept
Const version of begin().
Definition product.hpp:181
auto end() noexcept
End of the product range.
Definition product.hpp:191
bool operator==(multiplied const &) const =default
Default equal-to operator.
auto cend() const noexcept
Const version of end().
Definition product.hpp:194
iterator begin() noexcept
Beginning of the product range.
Definition product.hpp:178
auto end() const noexcept
Const overload of end().
Definition product.hpp:197
prod_iter< std::tuple< decltype(std::cend(std::declval< Rs & >()))... >, decltype(std::cbegin(std::declval< Rs & >()))... > const_iterator
Const iterator type of the product range.
Definition product.hpp:149
const_iterator begin() const noexcept
Const overload of begin().
Definition product.hpp:184
Iterator for an itertools::multiplied_vec (cartesian product of homogeneous ranges) range.
Definition product.hpp:221
bool operator==(sentinel_t< SentinelIter > const &s) const
Equal-to operator for an itertools::prod_iter_vec and an itertools::sentinel_t.
Definition product.hpp:281
std::vector< decltype(std::begin(std::declval< R & >())) > its_end
Definition product.hpp:229
void increment()
Increment the iterator by incrementing the current iterators starting with the iterator of the last r...
Definition product.hpp:250
std::vector< decltype(std::begin(std::declval< R & >())) > its_begin
Definition product.hpp:226
prod_iter_vec()=default
Default constructor.
typename std::iterator_traits< Iter >::value_type value_type
Value type of the dereferenced iterators.
Definition product.hpp:223
bool operator==(prod_iter_vec const &other) const
Equal-to operator for two itertools::prod_iter_vec objects.
Definition product.hpp:269
prod_iter_vec(std::vector< Iter > its_begin, std::vector< Iter > its_end)
Construct a product iterator from given begin iterators and end iterators.
Definition product.hpp:246
std::vector< value_type > dereference() const
Dereference the iterator.
Definition product.hpp:290
std::vector< decltype(std::begin(std::declval< R & >())) > its
Definition product.hpp:232
Iterator for an itertools::multiplied (cartesian product) range.
Definition product.hpp:57
bool operator==(sentinel_t< SentinelIter > const &s) const
Equal-to operator for an itertools::prod_iter and an itertools::sentinel_t.
Definition product.hpp:117
prod_iter(std::tuple< Iters... > its_begin, EndIters its_end)
Construct a product iterator from given begin iterators and end iterators.
Definition product.hpp:79
prod_iter()=default
Default constructor.
void increment()
Increment the iterator by incrementing the current iterators starting with the iterator of the last r...
Definition product.hpp:98
bool operator==(prod_iter const &other) const
Equal-to operator for two itertools::prod_iter objects.
Definition product.hpp:106
decltype(auto) dereference() const
Dereference the iterator.
Definition product.hpp:130
Generic sentinel type that can be used to mark the end of a range.
Definition sentinel.hpp:38
Iter it
End iterator of some range.
Definition sentinel.hpp:40