TRIQS/itertools 1.3.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 a 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
190 [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(std::get<0>(tu))); }
191
193 [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(std::get<0>(tu))); }
194
196 [[nodiscard]] auto end() const noexcept { return cend(); }
197 };
198
199 // Class template argument deduction guide.
200 template <typename... Rs> multiplied(Rs &&...) -> multiplied<std::decay_t<Rs>...>;
201
219 template <typename Iter>
220 struct prod_iter_vec : iterator_facade<prod_iter_vec<Iter>, std::vector<typename std::iterator_traits<Iter>::value_type>> {
222 using value_type = typename std::iterator_traits<Iter>::value_type;
223
225 std::vector<Iter> its_begin;
226
228 std::vector<Iter> its_end;
229
231 std::vector<Iter> its;
232
234 bool done = false;
235
237 prod_iter_vec() = default;
238
245 prod_iter_vec(std::vector<Iter> its_begin, std::vector<Iter> its_end)
246 : its_begin(std::move(its_begin)), its_end(std::move(its_end)), its(this->its_begin) {}
247
249 void increment() {
250 if (its.empty()) {
251 done = true;
252 return;
253 }
254 for (std::size_t i = its.size(); i-- > 1;) {
255 ++its[i];
256 if (its[i] != its_end[i]) return;
257 its[i] = its_begin[i];
258 }
259 ++its[0];
260 }
261
268 [[nodiscard]] bool operator==(prod_iter_vec const &other) const { return its == other.its && done == other.done; }
269
280 template <typename SentinelIter> [[nodiscard]] bool operator==(sentinel_t<SentinelIter> const &s) const {
281 if (its.empty()) return done;
282 return s.it == its[0];
283 }
284
289 [[nodiscard]] std::vector<value_type> dereference() const {
290 std::vector<value_type> result;
291 result.reserve(its.size());
292 for (auto const &it : its) result.push_back(*it);
293 return result;
294 }
295 };
296
305 template <typename R> struct multiplied_vec {
307 std::vector<R> tu;
308
311
314
320 explicit multiplied_vec(std::vector<R> rgs) : tu(std::move(rgs)) {}
321
323 [[nodiscard]] bool operator==(multiplied_vec const &) const = default;
324
329 [[nodiscard]] iterator begin() noexcept {
330 std::vector<decltype(std::begin(std::declval<R &>()))> b, e;
331 b.reserve(tu.size());
332 e.reserve(tu.size());
333 for (auto &r : tu) {
334 b.push_back(std::begin(r));
335 e.push_back(std::end(r));
336 }
337 return iterator{std::move(b), std::move(e)};
338 }
339
341 [[nodiscard]] const_iterator cbegin() const noexcept {
342 std::vector<decltype(std::cbegin(std::declval<R const &>()))> b, e;
343 b.reserve(tu.size());
344 e.reserve(tu.size());
345 for (auto const &r : tu) {
346 b.push_back(std::cbegin(r));
347 e.push_back(std::cend(r));
348 }
349 return const_iterator{std::move(b), std::move(e)};
350 }
351
353 [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); }
354
360 [[nodiscard]] auto end() noexcept {
361 using SentinelIter = decltype(std::end(std::declval<R &>()));
362 if (tu.empty()) return make_sentinel(SentinelIter{});
363 return make_sentinel(std::end(tu[0]));
364 }
365
367 [[nodiscard]] auto cend() const noexcept {
368 using SentinelIter = decltype(std::cend(std::declval<R const &>()));
369 if (tu.empty()) return make_sentinel(SentinelIter{});
370 return make_sentinel(std::cend(tu[0]));
371 }
372
374 [[nodiscard]] auto end() const noexcept { return cend(); }
375 };
376
381
416 template <typename... Rs> [[nodiscard]] itertools::multiplied<Rs...> product(Rs &&...rgs) { return {std::forward<Rs>(rgs)...}; }
417
457 template <typename R> [[nodiscard]] itertools::multiplied_vec<R> product_vec(std::vector<R> rgs) { return multiplied_vec<R>{std::move(rgs)}; }
458
459 namespace detail {
460
461 // Helper function to create a product range from a container of ranges.
462 template <typename C, size_t... Is> [[gnu::always_inline]] [[nodiscard]] auto make_product_impl(C &cont, std::index_sequence<Is...>) {
463 return product(cont[Is]...);
464 }
465
466 } // namespace detail
467
476 template <typename R, size_t N> [[nodiscard]] auto make_product(std::array<R, N> &arr) {
477 return detail::make_product_impl(arr, std::make_index_sequence<N>{});
478 }
479
481 template <typename R, size_t N> [[nodiscard]] auto make_product(std::array<R, N> const &arr) {
482 return detail::make_product_impl(arr, std::make_index_sequence<N>{});
483 }
484
486
487} // namespace itertools
488
489#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:457
auto make_product(std::array< R, N > &arr)
Create a cartesian product range from an array of ranges.
Definition product.hpp:476
itertools::multiplied< Rs... > product(Rs &&...rgs)
Lazy-multiply a given number of ranges by forming their cartesian product.
Definition product.hpp:416
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:305
auto end() const noexcept
Const overload of end().
Definition product.hpp:374
const_iterator begin() const noexcept
Const overload of begin().
Definition product.hpp:353
prod_iter_vec< decltype(std::cbegin(std::declval< R & >()))> const_iterator
Const iterator type the product range.
Definition product.hpp:313
const_iterator cbegin() const noexcept
Const version of begin().
Definition product.hpp:341
iterator begin() noexcept
Beginning of the product range.
Definition product.hpp:329
prod_iter_vec< decltype(std::begin(std::declval< R & >()))> iterator
Iterator type of the product range.
Definition product.hpp:310
bool operator==(multiplied_vec const &) const =default
Default equal-to operator.
auto cend() const noexcept
Const version of end().
Definition product.hpp:367
std::vector< R > tu
Vector containing the original ranges.
Definition product.hpp:307
multiplied_vec(std::vector< R > rgs)
Constructs a cartesian product (multiplied_vec) range from a vector of ranges.
Definition product.hpp:320
auto end() noexcept
End of the product range.
Definition product.hpp:360
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:190
bool operator==(multiplied const &) const =default
Default equal-to operator.
auto cend() const noexcept
Const version of end().
Definition product.hpp:193
iterator begin() noexcept
Beginning of the product range.
Definition product.hpp:178
auto end() const noexcept
Const overload of end().
Definition product.hpp:196
prod_iter< std::tuple< decltype(std::cend(std::declval< Rs & >()))... >, decltype(std::cbegin(std::declval< Rs & >()))... > const_iterator
Const iterator type the product range.
Definition product.hpp:149
const_iterator begin() const noexcept
Const overload of begin().
Definition product.hpp:184
Iterator for a itertools::multiplied_vec (cartesian product of homogeneous ranges) range.
Definition product.hpp:220
bool operator==(sentinel_t< SentinelIter > const &s) const
Equal-to operator for a itertools::prod_iter_vec and an itertools::sentinel_t.
Definition product.hpp:280
std::vector< decltype(std::begin(std::declval< R & >())) > its_end
Definition product.hpp:228
void increment()
Increment the iterator by incrementing the current iterators starting with the iterator of the last r...
Definition product.hpp:249
std::vector< decltype(std::begin(std::declval< R & >())) > its_begin
Definition product.hpp:225
prod_iter_vec()=default
Default constructor.
typename std::iterator_traits< Iter >::value_type value_type
Value type of the dereferenced iterators.
Definition product.hpp:222
bool operator==(prod_iter_vec const &other) const
Equal-to operator for two itertools::prod_iter_vec objects.
Definition product.hpp:268
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:245
std::vector< value_type > dereference() const
Dereference the iterator.
Definition product.hpp:289
std::vector< decltype(std::begin(std::declval< R & >())) > its
Definition product.hpp:231
Iterator for a itertools::multiplied (cartesian product) range.
Definition product.hpp:57
bool operator==(sentinel_t< SentinelIter > const &s) const
Equal-to operator for a 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