1 #pragma once
2
3 /// \file IteratorAdapters.h
4 /// \brief Helper objects allowing to iterate in reverse, iterate over multiple containeres, etc.
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7
8 #include "objects/containers/Tuple.h"
9 #include "objects/utility/Iterator.h"
10
11 NAMESPACE_SPH_BEGIN
12
13 //-----------------------------------------------------------------------------------------------------------
14 // ReverseIterator
15 //-----------------------------------------------------------------------------------------------------------
16
17 /// Generic reverse iterator over continuous array of objects of type T.
18 template <typename TIterator>
19 class ReverseIterator {
20 protected:
21 TIterator iter;
22
23 public:
24 ReverseIterator() = default;
25
ReverseIterator(TIterator iter)26 explicit ReverseIterator(TIterator iter)
27 : iter(iter) {}
28
decltype(auto)29 decltype(auto) operator*() const {
30 return *iter;
31 }
decltype(auto)32 decltype(auto) operator*() {
33 return *iter;
34 }
35 ReverseIterator& operator++() {
36 --iter;
37 return *this;
38 }
39 ReverseIterator operator++(int) {
40 ReverseIterator tmp(*this);
41 operator++();
42 return tmp;
43 }
44 ReverseIterator& operator--() {
45 ++iter;
46 return *this;
47 }
48 ReverseIterator operator--(int) {
49 ReverseIterator tmp(*this);
50 operator--();
51 return tmp;
52 }
53 bool operator==(const ReverseIterator& other) const {
54 return iter == other.iter;
55 }
56 bool operator!=(const ReverseIterator& other) const {
57 return iter != other.iter;
58 }
59 };
60
61 /// Creates reverse iterator by wrapping forward iterator, utilizes type deduction.
62 template <typename TIterator>
reverseIterator(const TIterator iter)63 ReverseIterator<TIterator> reverseIterator(const TIterator iter) {
64 return ReverseIterator<TIterator>(iter);
65 }
66
67
68 /// Wrapper of generic container allowing to iterate over its elements in reverse order. The wrapper can hold
69 /// l-value reference, or the container can be moved into the wrapper.
70 template <typename TContainer>
71 class ReverseAdapter {
72 private:
73 TContainer container;
74
75 using Iterator = decltype(std::declval<std::decay_t<TContainer>>().begin());
76
77 public:
78 template <typename T>
ReverseAdapter(T && container)79 explicit ReverseAdapter(T&& container)
80 : container(std::forward<T>(container)) {}
81
82 /// Returns iterator pointing to the last element in container.
begin()83 ReverseIterator<Iterator> begin() {
84 if (Iterator iter = container.end()) {
85 --iter;
86 return reverseIterator(iter);
87 } else {
88 return ReverseIterator<Iterator>(nullptr);
89 }
90 }
91
92 /// Returns iterator pointiing to one before the first element.
end()93 ReverseIterator<Iterator> end() {
94 if (Iterator iter = container.begin()) {
95 --iter;
96 return reverseIterator(iter);
97 } else {
98 return ReverseIterator<Iterator>(nullptr);
99 }
100 }
101
size()102 Size size() const {
103 return container.size();
104 }
105 };
106
107 /// Creates the ReverseAdapter over given container, utilizing type deduction.
108 /// To iterate over elements of container in reverse order, use
109 /// \code
110 /// for (T& value : reverse(container)) {
111 /// // do something with value
112 /// }
113 /// \endcode
114 template <typename TContainer>
reverse(TContainer && container)115 ReverseAdapter<TContainer> reverse(TContainer&& container) {
116 return ReverseAdapter<TContainer>(std::forward<TContainer>(container));
117 }
118
119 //-----------------------------------------------------------------------------------------------------------
120 // TupleIterator
121 //-----------------------------------------------------------------------------------------------------------
122
123 /// \brief Holds multiple iterators, advancing all of them at the same time.
124 ///
125 /// Has only the necessary functions to use in range-based for loops.
126 template <typename TElement, typename... TIterator>
127 class TupleIterator {
128 private:
129 Tuple<TIterator...> iterators;
130
131 public:
TupleIterator(const TIterator &...iters)132 explicit TupleIterator(const TIterator&... iters)
133 : iterators(iters...) {}
134
135 TupleIterator& operator++() {
136 forEach(iterators, [](auto& iter) { ++iter; });
137 return *this;
138 }
139
140 TElement operator*() {
141 return apply(iterators, [](auto&... values) -> TElement { return { *values... }; });
142 }
143
144 const TElement operator*() const {
145 return apply(iterators, [](const auto&... values) -> TElement { return { *values... }; });
146 }
147
148 bool operator==(const TupleIterator& other) const {
149 const bool result = iterators.template get<0>() == other.iterators.template get<0>();
150 // check that all iterators return the same result (all containers have the same size)
151 SPH_ASSERT(checkEqual(result, other, std::index_sequence_for<TIterator...>{}));
152 return result;
153 }
154
155 bool operator!=(const TupleIterator& other) const {
156 const bool result = iterators.template get<0>() != other.iterators.template get<0>();
157 // check that all iterators return the same result (all containers have the same size)
158 SPH_ASSERT(checkEqual(!result, other, std::index_sequence_for<TIterator...>{}));
159 return result;
160 }
161
162 private:
163 template <std::size_t First, std::size_t... Rest>
checkEqual(const bool equal,const TupleIterator & other,std::index_sequence<First,Rest...>)164 bool checkEqual(const bool equal, const TupleIterator& other, std::index_sequence<First, Rest...>) const {
165 if (equal != (iterators.template get<First>() == other.iterators.template get<First>())) {
166 // different size
167 return false;
168 }
169 return checkEqual(equal, other, std::index_sequence<Rest...>{});
170 }
171
172 // last step to end the recursion
checkEqual(const bool,const TupleIterator &,std::index_sequence<>)173 bool checkEqual(const bool, const TupleIterator&, std::index_sequence<>) const {
174 return true;
175 }
176 };
177
178 /// Creates TupleIterator from individual iterators, utilizing type deduction.
179 template <typename TElement, typename... TIterators>
makeTupleIterator(const TIterators &...iterators)180 TupleIterator<TElement, TIterators...> makeTupleIterator(const TIterators&... iterators) {
181 return TupleIterator<TElement, TIterators...>(iterators...);
182 }
183
184 /// Wraps any number of containers, providing means to iterate over all of them at the same time. This can
185 /// only be used for containers of the same size.
186 template <typename TElement, typename... TContainers>
187 class TupleAdapter {
188 private:
189 Tuple<TContainers...> tuple;
190
191 public:
TupleAdapter(TContainers &&...containers)192 explicit TupleAdapter(TContainers&&... containers)
193 : tuple(std::forward<TContainers>(containers)...) {
194 SPH_ASSERT(tuple.size() > 1);
195 }
196
begin()197 auto begin() {
198 return apply(tuple, [](auto&... containers) { //
199 return makeTupleIterator<TElement>(containers.begin()...);
200 });
201 }
202
begin()203 auto begin() const {
204 return apply(tuple, [](const auto&... containers) { //
205 return makeTupleIterator<TElement>(containers.begin()...);
206 });
207 }
208
end()209 auto end() {
210 return apply(tuple, [](auto&... containers) { //
211 return makeTupleIterator<TElement>(containers.end()...);
212 });
213 }
214
end()215 auto end() const {
216 return apply(tuple, [](const auto&... containers) { //
217 return makeTupleIterator<TElement>(containers.end()...);
218 });
219 }
220
size()221 Size size() const {
222 return tuple.template get<0>().size();
223 }
224 };
225
226 template <typename TElement, typename... TContainers>
iterateTuple(TContainers &&...containers)227 TupleAdapter<TElement, TContainers...> iterateTuple(TContainers&&... containers) {
228 return TupleAdapter<TElement, TContainers...>(std::forward<TContainers>(containers)...);
229 }
230
231 //-----------------------------------------------------------------------------------------------------------
232 // IteratorWithIndex
233 //-----------------------------------------------------------------------------------------------------------
234
235 template <typename TValue>
236 class ElementWithIndex {
237 private:
238 TValue data;
239 Size idx;
240
241 public:
ElementWithIndex(TValue && value,const Size index)242 ElementWithIndex(TValue&& value, const Size index)
243 : data(std::forward<TValue>(value))
244 , idx(index) {}
245
value()246 INLINE TValue& value() {
247 return data;
248 }
249
value()250 INLINE const TValue& value() const {
251 return data;
252 }
253
254 INLINE operator TValue&() {
255 return value();
256 }
257
258 INLINE operator const TValue&() const {
259 return value();
260 }
261
index()262 INLINE Size index() const {
263 return idx;
264 }
265 };
266
267 template <typename TValue>
makeElementWithIndex(TValue && value,const Size index)268 ElementWithIndex<TValue> makeElementWithIndex(TValue&& value, const Size index) {
269 return ElementWithIndex<TValue>(std::forward<TValue>(value), index);
270 }
271
272 /// Wrapper of iterator keeping also an index of current element.
273 template <typename TIterator>
274 class IteratorWithIndex {
275 private:
276 TIterator iterator;
277 Size index;
278
279 using TValue = decltype(*std::declval<TIterator>());
280
281 public:
IteratorWithIndex(const TIterator iterator,const Size index)282 IteratorWithIndex(const TIterator iterator, const Size index)
283 : iterator(iterator)
284 , index(index) {}
285
286 ElementWithIndex<TValue> operator*() {
287 return makeElementWithIndex(*iterator, index);
288 }
289
290 ElementWithIndex<const TValue> operator*() const {
291 return makeElementWithIndex(*iterator, index);
292 }
293
294 IteratorWithIndex& operator++() {
295 ++iterator;
296 ++index;
297 return *this;
298 }
299
300 bool operator!=(const IteratorWithIndex& other) const {
301 return iterator != other.iterator;
302 }
303 };
304
305 template <typename TIterator>
makeIteratorWithIndex(TIterator && iterator,const Size index)306 IteratorWithIndex<TIterator> makeIteratorWithIndex(TIterator&& iterator, const Size index) {
307 return IteratorWithIndex<TIterator>(std::forward<TIterator>(iterator), index);
308 }
309
310
311 template <typename TContainer>
312 class IndexAdapter {
313 private:
314 TContainer container;
315
316 public:
IndexAdapter(TContainer && container)317 explicit IndexAdapter(TContainer&& container)
318 : container(std::forward<TContainer>(container)) {}
319
begin()320 auto begin() {
321 return makeIteratorWithIndex(container.begin(), 0);
322 }
323
end()324 auto end() {
325 return makeIteratorWithIndex(container.end(), container.size());
326 }
327 };
328
329 template <typename TContainer>
iterateWithIndex(TContainer && container)330 IndexAdapter<TContainer> iterateWithIndex(TContainer&& container) {
331 return IndexAdapter<TContainer>(std::forward<TContainer>(container));
332 }
333
334 //-----------------------------------------------------------------------------------------------------------
335 // Subrange
336 //-----------------------------------------------------------------------------------------------------------
337
338 template <typename TIterator>
339 struct SubRange : public Noncopyable {
340 private:
341 TIterator first;
342 TIterator last;
343
344 public:
345 template <typename TContainer>
SubRangeSubRange346 explicit SubRange(const TContainer& container, const Size firstIdx, const Size lastIdx) {
347 SPH_ASSERT(lastIdx <= container.size());
348 first = container.begin() + firstIdx;
349 last = container.begin() + lastIdx;
350 }
351
beginSubRange352 INLINE TIterator begin() const {
353 return first;
354 }
355
endSubRange356 INLINE TIterator end() const {
357 return last;
358 }
359 };
360
361 template <typename TContainer>
subrange(const TContainer & container,const Size firstIdx,const Size lastIdx)362 INLINE auto subrange(const TContainer& container, const Size firstIdx, const Size lastIdx) {
363 return SubRange<TContainer>(container, firstIdx, lastIdx);
364 }
365
366 //-----------------------------------------------------------------------------------------------------------
367 // SubsetIterator
368 //-----------------------------------------------------------------------------------------------------------
369
370 /// Allows to iterate over a given subset of a container, given by condition functor.
371 template <typename TIterator, typename TCondition>
372 class SubsetIterator {
373 private:
374 TIterator iter;
375 TIterator end;
376 TCondition condition;
377
378 public:
SubsetIterator(const TIterator & iterator,const TIterator & end,TCondition && condition)379 SubsetIterator(const TIterator& iterator, const TIterator& end, TCondition&& condition)
380 : iter(iterator)
381 , end(end)
382 , condition(std::forward<TCondition>(condition)) {
383 // move to first element of the subset
384 while (iter != end && !condition(*iter)) {
385 ++iter;
386 }
387 }
388
389 INLINE SubsetIterator& operator++() {
390 do {
391 ++iter;
392 } while (iter != end && !condition(*iter));
393 return *this;
394 }
395
decltype(auto)396 INLINE decltype(auto) operator*() {
397 SPH_ASSERT(iter != end);
398 return *iter;
399 }
400
decltype(auto)401 INLINE decltype(auto) operator*() const {
402 SPH_ASSERT(iter != end);
403 return *iter;
404 }
405
406 INLINE bool operator==(const SubsetIterator& other) const {
407 return iter == other.iter;
408 }
409
410 INLINE bool operator!=(const SubsetIterator& other) const {
411 return iter != other.iter;
412 }
413 };
414
415 /// \todo test
416 template <typename TIterator, typename TCondition>
makeSubsetIterator(const TIterator & iterator,const TIterator & end,TCondition && condition)417 INLINE auto makeSubsetIterator(const TIterator& iterator, const TIterator& end, TCondition&& condition) {
418 return SubsetIterator<TIterator, TCondition>(iterator, end, std::forward<TCondition>(condition));
419 }
420
421 /// Non-owning view to access and iterate over subset of container
422 template <typename TContainer, typename TCondition>
423 class SubsetAdapter {
424 private:
425 TContainer container;
426 TCondition condition;
427
428 public:
SubsetAdapter(TContainer && container,TCondition && condition)429 SubsetAdapter(TContainer&& container, TCondition&& condition)
430 : container(std::forward<TContainer>(container))
431 , condition(std::forward<TCondition>(condition)) {}
432
begin()433 auto begin() {
434 return makeSubsetIterator(container.begin(), container.end(), condition);
435 }
436
end()437 auto end() {
438 return makeSubsetIterator(container.end(), container.end(), condition);
439 }
440 };
441
442 /// \todo test
443 template <typename TContainer, typename TCondition>
subset(TContainer && container,TCondition && condition)444 auto subset(TContainer&& container, TCondition&& condition) {
445 return SubsetAdapter<TContainer, TCondition>(
446 std::forward<TContainer>(container), std::forward<TCondition>(condition));
447 }
448
449 //-----------------------------------------------------------------------------------------------------------
450 // IndexIterator
451 //-----------------------------------------------------------------------------------------------------------
452
453 class IndexIterator {
454 protected:
455 Size idx;
456
457 public:
IndexIterator(const Size idx)458 INLINE explicit IndexIterator(const Size idx)
459 : idx(idx) {}
460
461 INLINE Size operator*() const {
462 return idx;
463 }
464
465 INLINE IndexIterator& operator++() {
466 ++idx;
467 return *this;
468 }
469
470 INLINE bool operator!=(const IndexIterator other) const {
471 return idx != other.idx;
472 }
473 };
474
475 class IndexSequence {
476 protected:
477 Size from;
478 Size to;
479
480 public:
IndexSequence(const Size from,const Size to)481 INLINE IndexSequence(const Size from, const Size to)
482 : from(from)
483 , to(to) {
484 SPH_ASSERT(from <= to);
485 }
486
begin()487 INLINE IndexIterator begin() const {
488 return IndexIterator(from);
489 }
490
end()491 INLINE IndexIterator end() const {
492 return IndexIterator(to);
493 }
494
size()495 INLINE Size size() const {
496 return to - from;
497 }
498
499 INLINE bool operator==(const IndexSequence& other) const {
500 return from == other.from && to == other.to;
501 }
502
503 friend std::ostream& operator<<(std::ostream& ofs, const IndexSequence& sequence) {
504 ofs << sequence.from << " - " << sequence.to;
505 return ofs;
506 }
507 };
508
509 NAMESPACE_SPH_END
510