dune-common 2.12-git
Loading...
Searching...
No Matches
rangeutilities.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5#ifndef DUNE_COMMON_RANGE_UTILITIES_HH
6#define DUNE_COMMON_RANGE_UTILITIES_HH
7
8#include <algorithm>
9#include <utility>
10#include <type_traits>
11#include <bitset>
12#include <ranges>
13#include <concepts>
14
17
25namespace Dune
26{
27
38 template <typename T,
39 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
40 typename T::value_type
41 max_value(const T & v) {
42 using std::max_element;
43 return *max_element(v.begin(), v.end());
44 }
45
46 template <typename T,
47 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
48 const T & max_value(const T & v) { return v; }
49
55 template <typename T,
56 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
57 typename T::value_type
58 min_value(const T & v) {
59 using std::min_element;
60 return *min_element(v.begin(), v.end());
61 }
62
63 template <typename T,
64 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
65 const T & min_value(const T & v) { return v; }
66
72 template <typename T,
73 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
74 bool any_true(const T & v) {
75 bool b = false;
76 for (const auto & e : v)
77 b = b or bool(e);
78 return b;
79 }
80
81 template <typename T,
82 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
83 bool any_true(const T & v) { return v; }
84
85 template<std::size_t N>
86 bool any_true(const std::bitset<N> & b)
87 {
88 return b.any();
89 }
90
96 template <typename T,
97 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
98 bool all_true(const T & v) {
99 bool b = true;
100 for (const auto & e : v)
101 b = b and bool(e);
102 return b;
103 }
104
105 template <typename T,
106 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
107 bool all_true(const T & v) { return v; }
108
109 template<std::size_t N>
110 bool all_true(const std::bitset<N> & b)
111 {
112 return b.all();
113 }
114
115
116
117 namespace Impl
118 {
119
120 // Tag base used to opt dune ranges into std::ranges::borrowed_range via the constrained partial specialization below.
121 struct BorrowedIntegralRange {};
122
123 template <class T>
124 class IntegralRangeIterator
125 {
126 public:
127 typedef std::random_access_iterator_tag iterator_category;
128 typedef T value_type;
129 typedef std::make_signed_t<T> difference_type;
130 typedef const T *pointer;
131 typedef T reference;
132
133 constexpr IntegralRangeIterator() noexcept : value_(0) {}
134 constexpr explicit IntegralRangeIterator(value_type value) noexcept : value_(value) {}
135
136 pointer operator->() const noexcept { return &value_; }
137 constexpr reference operator*() const noexcept { return value_; }
138
139 constexpr reference operator[]( difference_type n ) const noexcept { return (value_ + n); }
140
141 constexpr auto operator<=>(const IntegralRangeIterator & other) const noexcept = default;
142
143 constexpr IntegralRangeIterator& operator++() noexcept { ++value_; return *this; }
144 constexpr IntegralRangeIterator operator++(int) noexcept { IntegralRangeIterator copy( *this ); ++(*this); return copy; }
145
146 constexpr IntegralRangeIterator& operator--() noexcept { --value_; return *this; }
147 constexpr IntegralRangeIterator operator--(int) noexcept { IntegralRangeIterator copy( *this ); --(*this); return copy; }
148
149 constexpr IntegralRangeIterator& operator+=(difference_type n) noexcept { value_ += n; return *this; }
150 constexpr IntegralRangeIterator& operator-=(difference_type n) noexcept { value_ -= n; return *this; }
151
152 friend constexpr IntegralRangeIterator operator+(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ + n); }
153 friend constexpr IntegralRangeIterator operator+(difference_type n, const IntegralRangeIterator &a) noexcept { return IntegralRangeIterator(a.value_ + n); }
154 friend constexpr IntegralRangeIterator operator-(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ - n); }
155
156 constexpr difference_type operator-(const IntegralRangeIterator &other) const noexcept { return (static_cast<difference_type>(value_) - static_cast<difference_type>(other.value_)); }
157
158 private:
159 value_type value_;
160 };
161
162 } // namespace Impl
163
164
165
174 template <class T>
175 class IntegralRange : public Impl::BorrowedIntegralRange
176 {
177 public:
179 typedef T value_type;
181 typedef Impl::IntegralRangeIterator<T> iterator;
184
186 constexpr IntegralRange(value_type from, value_type to) noexcept : from_(from), to_(to) {}
188 constexpr explicit IntegralRange(value_type to) noexcept : from_(0), to_(to) {}
190 constexpr IntegralRange(std::pair<value_type, value_type> range) noexcept : from_(range.first), to_(range.second) {}
191
193 constexpr iterator begin() const noexcept { return iterator(from_); }
195 constexpr iterator end() const noexcept { return iterator(to_); }
196
198 constexpr value_type operator[](const value_type &i) const noexcept { return (from_ + i); }
199
201 constexpr bool empty() const noexcept { return (from_ == to_); }
203 constexpr size_type size() const noexcept { return (static_cast<size_type>(to_) - static_cast<size_type>(from_)); }
204
206 constexpr bool contains(value_type index) const noexcept { return from_ <= index && index < to_; }
207
208 private:
209 value_type from_, to_;
210 };
211
212
227 template <class T, T to, T from = 0>
228 class StaticIntegralRange : public Impl::BorrowedIntegralRange
229 {
230 template <T ofs, T... i>
231 static std::integer_sequence<T, (i+ofs)...> shift_integer_sequence(std::integer_sequence<T, i...>);
232
233 public:
235 typedef T value_type;
237 typedef Impl::IntegralRangeIterator<T> iterator;
240
242 typedef decltype(shift_integer_sequence<from>(std::make_integer_sequence<T, to-from>())) integer_sequence;
243
245 constexpr StaticIntegralRange() noexcept = default;
246
248 constexpr operator IntegralRange<T>() const noexcept { return {from, to}; }
250 constexpr operator integer_sequence() const noexcept { return {}; }
251
253 static constexpr integer_sequence to_integer_sequence() noexcept { return {}; }
254
256 static constexpr iterator begin() noexcept { return iterator(from); }
258 static constexpr iterator end() noexcept { return iterator(to); }
259
261 template <class U, U i>
262 constexpr auto operator[](const std::integral_constant<U, i> &) const noexcept
264 {
265 return {};
266 }
267
269 constexpr value_type operator[](const size_type &i) const noexcept { return (from + static_cast<value_type>(i)); }
270
272 static constexpr std::integral_constant<bool, from == to> empty() noexcept { return {}; }
274 static constexpr std::integral_constant<size_type, static_cast<size_type>(to) - static_cast<size_type>(from) > size() noexcept { return {}; }
275
277 static constexpr bool contains(value_type index) noexcept { return from <= index && index < to; }
278
279 };
280
290 template<std::integral T>
291 constexpr static IntegralRange<T> range(T from, T to) noexcept
292 {
293 return IntegralRange<T>(from, to);
294 }
295
296 template<std::integral T>
297 constexpr static IntegralRange<T> range(T to) noexcept
298 {
299 return IntegralRange<T>(to);
300 }
301
302 template<class T>
303 requires (std::is_enum_v<T>)
304 constexpr static IntegralRange<std::underlying_type_t<T>> range(T to) noexcept
305 {
307 }
308
309 template<class T>
310 requires (std::is_enum_v<T>)
311 constexpr static IntegralRange<std::underlying_type_t<T>> range(T from, T to) noexcept
312 {
314 }
315
316 template<class T, T from, T to>
321
322 template<class T, T to>
324 {
325 return {};
326 }
327
328
329
334
339
340 namespace Impl
341 {
342
343
344
345 // An iterator transforming a wrapped iterator using
346 // an unary function. It inherits the iterator-category
347 // of the underlying iterator.
348 //
349 // \tparam I Type of the underlying iterator
350 // \tparam F Type of transformation function that can either be applied directly or after dereferencing
351 // \tparam TT Type of transformation (ValueTransformationTag or IteratorTransformationTag)
352 // \tparam C An iterator category tag, defaults to the one of I
353 template <class I, class F, class TT, class C = typename std::iterator_traits<I>::iterator_category>
354 class TransformedRangeIterator;
355
356 template<class I, class F, class TT, class C>
357 struct TransformationRangeIteratorTraits
358 {
359 template<class FF>
360 static decltype(auto) transform(FF&& f, const I& it) {
361 if constexpr (std::is_same_v<TT,IteratorTransformationTag>)
362 {
363 if constexpr (Dune::IsCallable<FF(const I&)>::value)
364 return f(it);
365 else
366 return (*f)(it);
367 }
368 else
369 {
370 if constexpr (Dune::IsCallable<FF(decltype(*it))>::value)
371 return f(*it);
372 else
373 return (*f)(*it);
374 }
375 }
376
377 using reference = decltype(transform(std::declval<F>(), std::declval<I>()));
378 using value_type = Dune::AutonomousValue<reference>;
379 using pointer = std::conditional_t<std::is_lvalue_reference_v<reference>, value_type*, ProxyArrowResult<reference>>;
380 using difference_type = typename std::iterator_traits<I>::difference_type;
381 using Facade = Dune::IteratorFacade<TransformedRangeIterator<I,F,TT,C>, C, value_type, reference, pointer, difference_type>;
382 };
383
384
385 template <class I, class F, class TT, class C>
386 class TransformedRangeIterator :
387 public TransformationRangeIteratorTraits<I,F, TT, C>::Facade
388 {
389 using Traits = TransformationRangeIteratorTraits<I,F, TT, C>;
390 using Facade = typename Traits::Facade;
391
392 static constexpr bool isBidirectional = std::is_convertible_v<C, std::bidirectional_iterator_tag>;
393 static constexpr bool isRandomAccess = std::is_convertible_v<C, std::random_access_iterator_tag>;
394
395 public:
396
397 using Function = F;
398 using reference = typename Facade::reference;
399 using difference_type = typename Facade::difference_type;
400
401 template<class II, class FF>
402 constexpr TransformedRangeIterator(II&& it, FF&& f) noexcept :
403 it_(std::forward<II>(it)),
404 f_(std::forward<FF>(f))
405 {}
406
407 template<class II,
408 disableCopyMove<TransformedRangeIterator,II> =0,
409 std::enable_if_t<std::is_convertible_v<II, I> and std::is_default_constructible_v<F>, int> =0>
410 constexpr TransformedRangeIterator(II&& it) noexcept :
411 it_(std::forward<II>(it)),
412 f_()
413 {}
414
415 template<class FF,
416 disableCopyMove<TransformedRangeIterator,FF> =0,
417 std::enable_if_t<std::is_convertible_v<FF, F> and std::is_default_constructible_v<I>, int> =0>
418 constexpr TransformedRangeIterator(FF&& f) noexcept :
419 it_(),
420 f_(std::forward<FF>(f))
421 {}
422
423 // Explicitly initialize members. Using a plain
424 //
425 // constexpr TransformedRangeIterator() noexcept {}
426 //
427 // would default-initialize the members while
428 //
429 // constexpr TransformedRangeIterator() noexcept : it_(), f_() {}
430 //
431 // leads to value-initialization. This is a case where
432 // both are really different. If it_ is a raw pointer (i.e. POD)
433 // then default-initialization leaves it uninitialized while
434 // value-initialization zero-initializes it.
435 constexpr TransformedRangeIterator() noexcept :
436 it_(),
437 f_()
438 {}
439
440 // Dereferencing returns a value created by the function
441 constexpr reference operator*() const noexcept {
442 return Traits::transform(f_, it_);
443 }
444
445 protected:
446
448
449 // Export base iterator, such that equalilty comparison,
450 // differences, and inequality comparisons are automatically
451 // forwarded to the base iterator by the facade.
452 const I& baseIterator() const noexcept {
453 return it_;
454 }
455
456 I& baseIterator() noexcept {
457 return it_;
458 }
459
460 I it_;
461 Function f_;
462 };
463
464 } // namespace Impl
465
466
467
504 template <class R, class F, class T=ValueTransformationTag>
506 {
509
510 public:
511
518 using const_iterator = Impl::TransformedRangeIterator<RawConstIterator, const F*, T>;
519
526 using iterator = Impl::TransformedRangeIterator<RawIterator, F*, T>;
527
535
539 template<class RR, class FF>
540 constexpr TransformedRangeView(RR&& rawRange, FF&& f) noexcept :
541 rawRange_(std::forward<RR>(rawRange)),
542 f_(std::forward<FF>(f))
543 {
544 static_assert(std::is_same_v<T, ValueTransformationTag> or std::is_same_v<T, IteratorTransformationTag>,
545 "The TransformationType passed to TransformedRangeView has to be either ValueTransformationTag or IteratorTransformationTag.");
546 }
547
556 constexpr const_iterator begin() const noexcept {
557 return const_iterator(rawRange_.begin(), &f_);
558 }
559
560 constexpr iterator begin() noexcept {
561 return iterator(rawRange_.begin(), &f_);
562 }
563
572 constexpr const_iterator end() const noexcept {
573 return const_iterator(rawRange_.end(), &f_);
574 }
575
576 constexpr iterator end() noexcept {
577 return iterator(rawRange_.end(), &f_);
578 }
579
583 template<class It=const_iterator,
585 constexpr decltype(auto) operator[](std::size_t i) const noexcept
586 {
587 return this->begin()[i];
588 }
589
593 template<class It=iterator,
595 constexpr decltype(auto) operator[](std::size_t i) noexcept
596 {
597 return this->begin()[i];
598 }
599
610 template<class Range=R,
612 auto size() const noexcept
613 {
614 return rawRange_.size();
615 }
616
620 constexpr bool empty() const noexcept
621 {
622 return rawRange_.begin() == rawRange_.end();
623 }
624
628 const RawRange& rawRange() const noexcept
629 {
630 return rawRange_;
631 }
632
636 RawRange& rawRange() noexcept
637 {
638 return rawRange_;
639 }
640
641 private:
642 R rawRange_;
643 F f_;
644 };
645
674 template <class R, class F>
676 {
677 return TransformedRangeView<R, std::decay_t<F>, ValueTransformationTag>(std::forward<R>(range), std::forward<F>(f));
678 }
679
707 template <class R, class F>
709 {
710 return TransformedRangeView<R, std::decay_t<F>, IteratorTransformationTag>(std::forward<R>(range), std::forward<F>(f));
711 }
712
713
726 template<class Range>
727 auto sparseRange(Range&& range) {
728 return Dune::iteratorTransformedRangeView(std::forward<Range>(range), [](auto&& it) {
729 return std::tuple<decltype(*it), decltype(it.index())>(*it, it.index());
730 });
731 }
732
737}
738
739template <std::derived_from<Dune::Impl::BorrowedIntegralRange> T>
740constexpr bool std::ranges::enable_borrowed_range<T> = true;
741
742#endif // DUNE_COMMON_RANGE_UTILITIES_HH
This file implements iterator facade classes for writing stl conformant iterators.
Traits for type conversions and type information.
auto iteratorTransformedRangeView(R &&range, F &&f)
Create a TransformedRangeView using an iterator transformation.
Definition rangeutilities.hh:708
auto transformedRangeView(R &&range, F &&f)
Create a TransformedRangeView.
Definition rangeutilities.hh:675
auto sparseRange(Range &&range)
Allow structured-binding for-loops for sparse iterators.
Definition rangeutilities.hh:727
static constexpr IntegralRange< T > range(T from, T to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition rangeutilities.hh:291
typename AutonomousValueType< T >::type AutonomousValue
Type free of internal references that T can be converted to.
Definition typetraits.hh:573
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition bigunsignedint.hh:572
bigunsignedint< k > operator-(const bigunsignedint< k > &x, std::uintmax_t y)
Definition bigunsignedint.hh:565
bigunsignedint< k > operator+(const bigunsignedint< k > &x, std::uintmax_t y)
Definition bigunsignedint.hh:558
Dune namespace
Definition alignedallocator.hh:13
bool any_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:506
bool all_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:512
T max_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:494
T min_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:500
This class encapsulates access of IteratorFacade.
Definition iteratorfacades.hh:786
CRTP-Mixing class for stl conformant iterators of given iterator category.
Definition iteratorfacades.hh:1053
constexpr decltype(auto) operator*() const
Dereferencing operator.
Definition iteratorfacades.hh:1119
dynamic integer range for use in range-based for loops
Definition rangeutilities.hh:176
constexpr iterator begin() const noexcept
obtain a random-access iterator to the first element
Definition rangeutilities.hh:193
constexpr iterator end() const noexcept
obtain a random-access iterator past the last element
Definition rangeutilities.hh:195
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition rangeutilities.hh:183
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition rangeutilities.hh:181
constexpr value_type operator[](const value_type &i) const noexcept
access specified element
Definition rangeutilities.hh:198
constexpr bool contains(value_type index) const noexcept
check whether given index is within range [from, to)
Definition rangeutilities.hh:206
constexpr bool empty() const noexcept
check whether the range is empty
Definition rangeutilities.hh:201
constexpr IntegralRange(std::pair< value_type, value_type > range) noexcept
construct integer range std::pair
Definition rangeutilities.hh:190
constexpr IntegralRange(value_type from, value_type to) noexcept
construct integer range [from, to)
Definition rangeutilities.hh:186
constexpr size_type size() const noexcept
obtain number of elements in the range
Definition rangeutilities.hh:203
constexpr IntegralRange(value_type to) noexcept
construct integer range [0, to)
Definition rangeutilities.hh:188
T value_type
type of integers contained in the range
Definition rangeutilities.hh:179
static integer range for use in range-based for loops
Definition rangeutilities.hh:229
static constexpr iterator end() noexcept
obtain a random-access iterator past the last element
Definition rangeutilities.hh:258
decltype(shift_integer_sequence< from >(std::make_integer_sequence< T, to-from >())) integer_sequence
type of corresponding std::integer_sequence
Definition rangeutilities.hh:242
static constexpr bool contains(value_type index) noexcept
check whether given index is within range [from, to)
Definition rangeutilities.hh:277
constexpr StaticIntegralRange() noexcept=default
default constructor
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition rangeutilities.hh:239
T value_type
type of integers contained in the range
Definition rangeutilities.hh:235
constexpr auto operator[](const std::integral_constant< U, i > &) const noexcept -> std::integral_constant< value_type, from+static_cast< value_type >(i)>
access specified element (static version)
Definition rangeutilities.hh:262
static constexpr std::integral_constant< bool, from==to > empty() noexcept
check whether the range is empty
Definition rangeutilities.hh:272
static constexpr iterator begin() noexcept
obtain a random-access iterator to the first element
Definition rangeutilities.hh:256
static constexpr integer_sequence to_integer_sequence() noexcept
return corresponding std::integer_sequence
Definition rangeutilities.hh:253
constexpr value_type operator[](const size_type &i) const noexcept
access specified element (dynamic version)
Definition rangeutilities.hh:269
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition rangeutilities.hh:237
static constexpr std::integral_constant< size_type, static_cast< size_type >(to) - static_cast< size_type >(from) > size() noexcept
obtain number of elements in the range
Definition rangeutilities.hh:274
Tag to enable value based transformations in TransformedRangeView.
Definition rangeutilities.hh:333
Tag to enable iterator based transformations in TransformedRangeView.
Definition rangeutilities.hh:338
A range transforming the values of another range on-the-fly.
Definition rangeutilities.hh:506
Impl::TransformedRangeIterator< RawIterator, F *, T > iterator
Iterator type.
Definition rangeutilities.hh:526
constexpr TransformedRangeView(RR &&rawRange, FF &&f) noexcept
Construct from range and function.
Definition rangeutilities.hh:540
constexpr iterator end() noexcept
Definition rangeutilities.hh:576
Impl::TransformedRangeIterator< RawConstIterator, const F *, T > const_iterator
Const iterator type.
Definition rangeutilities.hh:518
constexpr iterator begin() noexcept
Definition rangeutilities.hh:560
RawRange & rawRange() noexcept
Export the wrapped untransformed range.
Definition rangeutilities.hh:636
const RawRange & rawRange() const noexcept
Export the wrapped untransformed range.
Definition rangeutilities.hh:628
constexpr const_iterator begin() const noexcept
Obtain a iterator to the first element.
Definition rangeutilities.hh:556
auto size() const noexcept
Obtain the size of the range.
Definition rangeutilities.hh:612
constexpr const_iterator end() const noexcept
Obtain a iterator past the last element.
Definition rangeutilities.hh:572
constexpr bool empty() const noexcept
Checks whether the range is empty.
Definition rangeutilities.hh:620
Check if a type is callable with ()-operator and given arguments.
Definition typetraits.hh:162
T any(T... args)
T copy(T... args)
T max_element(T... args)
T min_element(T... args)
T transform(T... args)