DUNE PDELab (unstable)

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;
183 typedef std::make_unsigned_t<T> size_type;
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;
239 typedef std::make_unsigned_t<T> size_type;
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
263 -> std::integral_constant<value_type, from + static_cast<value_type>(i)>
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<class T, class U,
291 std::enable_if_t<std::is_same<std::decay_t<T>, std::decay_t<U>>::value, int> = 0,
292 std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
293 constexpr static IntegralRange<std::decay_t<T>> range(T &&from, U &&to) noexcept
294 {
295 return IntegralRange<std::decay_t<T>>(std::forward<T>(from), std::forward<U>(to));
296 }
297
298 template<class T, std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
299 constexpr static IntegralRange<std::decay_t<T>> range(T &&to) noexcept
300 {
301 return IntegralRange<std::decay_t<T>>(std::forward<T>(to));
302 }
303
304 template<class T, std::enable_if_t<std::is_enum<std::decay_t<T>>::value, int> = 0>
305 constexpr static IntegralRange<std::underlying_type_t<std::decay_t<T>>> range(T &&to) noexcept
306 {
307 return IntegralRange<std::underlying_type_t<std::decay_t<T>>>(std::forward<T>(to));
308 }
309
310 template<class T, T from, T to>
311 constexpr static StaticIntegralRange<T, to, from> range(std::integral_constant<T, from>, std::integral_constant<T, to>) noexcept
312 {
313 return {};
314 }
315
316 template<class T, T to>
317 constexpr static StaticIntegralRange<T, to> range(std::integral_constant<T, to>) noexcept
318 {
319 return {};
320 }
321
322
323
328
333
334 namespace Impl
335 {
336
337
338
339 // An iterator transforming a wrapped iterator using
340 // an unary function. It inherits the iterator-category
341 // of the underlying iterator.
342 //
343 // \tparam I Type of the underlying iterator
344 // \tparam F Type of transformation function that can either be applied directly or after dereferencing
345 // \tparam TT Type of transformation (ValueTransformationTag or IteratorTransformationTag)
346 // \tparam C An iterator category tag, defaults to the one of I
347 template <class I, class F, class TT, class C = typename std::iterator_traits<I>::iterator_category>
348 class TransformedRangeIterator;
349
350 template<class I, class F, class TT, class C>
351 struct TransformationRangeIteratorTraits
352 {
353 template<class FF>
354 static decltype(auto) transform(FF&& f, const I& it) {
355 if constexpr (std::is_same_v<TT,IteratorTransformationTag>)
356 {
357 if constexpr (Dune::IsCallable<FF(const I&)>::value)
358 return f(it);
359 else
360 return (*f)(it);
361 }
362 else
363 {
364 if constexpr (Dune::IsCallable<FF(decltype(*it))>::value)
365 return f(*it);
366 else
367 return (*f)(*it);
368 }
369 }
370
371 using reference = decltype(transform(std::declval<F>(), std::declval<I>()));
372 using value_type = Dune::AutonomousValue<reference>;
373 using pointer = std::conditional_t<std::is_lvalue_reference_v<reference>, value_type*, ProxyArrowResult<reference>>;
374 using difference_type = typename std::iterator_traits<I>::difference_type;
375 using Facade = Dune::IteratorFacade<TransformedRangeIterator<I,F,TT,C>, C, value_type, reference, pointer, difference_type>;
376 };
377
378
379 template <class I, class F, class TT, class C>
380 class TransformedRangeIterator :
381 public TransformationRangeIteratorTraits<I,F, TT, C>::Facade
382 {
383 using Traits = TransformationRangeIteratorTraits<I,F, TT, C>;
384 using Facade = typename Traits::Facade;
385
386 static constexpr bool isBidirectional = std::is_convertible_v<C, std::bidirectional_iterator_tag>;
387 static constexpr bool isRandomAccess = std::is_convertible_v<C, std::random_access_iterator_tag>;
388
389 public:
390
391 using Function = F;
392 using reference = typename Facade::reference;
393 using difference_type = typename Facade::difference_type;
394
395 template<class II, class FF>
396 constexpr TransformedRangeIterator(II&& it, FF&& f) noexcept :
397 it_(std::forward<II>(it)),
398 f_(std::forward<FF>(f))
399 {}
400
401 template<class II,
402 disableCopyMove<TransformedRangeIterator,II> =0,
403 std::enable_if_t<std::is_convertible_v<II, I> and std::is_default_constructible_v<F>, int> =0>
404 constexpr TransformedRangeIterator(II&& it) noexcept :
405 it_(std::forward<II>(it)),
406 f_()
407 {}
408
409 template<class FF,
410 disableCopyMove<TransformedRangeIterator,FF> =0,
411 std::enable_if_t<std::is_convertible_v<FF, F> and std::is_default_constructible_v<I>, int> =0>
412 constexpr TransformedRangeIterator(FF&& f) noexcept :
413 it_(),
414 f_(std::forward<FF>(f))
415 {}
416
417 // Explicitly initialize members. Using a plain
418 //
419 // constexpr TransformedRangeIterator() noexcept {}
420 //
421 // would default-initialize the members while
422 //
423 // constexpr TransformedRangeIterator() noexcept : it_(), f_() {}
424 //
425 // leads to value-initialization. This is a case where
426 // both are really different. If it_ is a raw pointer (i.e. POD)
427 // then default-initialization leaves it uninitialized while
428 // value-initialization zero-initializes it.
429 constexpr TransformedRangeIterator() noexcept :
430 it_(),
431 f_()
432 {}
433
434 // Dereferencing returns a value created by the function
435 constexpr reference operator*() const noexcept {
436 return Traits::transform(f_, it_);
437 }
438
439 protected:
440
442
443 // Export base iterator, such that equalilty comparison,
444 // differences, and inequality comparisons are automatically
445 // forwarded to the base iterator by the facade.
446 const I& baseIterator() const noexcept {
447 return it_;
448 }
449
450 I& baseIterator() noexcept {
451 return it_;
452 }
453
454 I it_;
455 Function f_;
456 };
457
458 } // namespace Impl
459
460
461
498 template <class R, class F, class T=ValueTransformationTag>
500 {
501 using RawConstIterator = std::decay_t<decltype(std::declval<const R>().begin())>;
502 using RawIterator = std::decay_t<decltype(std::declval<R>().begin())>;
503
504 public:
505
512 using const_iterator = Impl::TransformedRangeIterator<RawConstIterator, const F*, T>;
513
520 using iterator = Impl::TransformedRangeIterator<RawIterator, F*, T>;
521
528 using RawRange = std::remove_reference_t<R>;
529
533 template<class RR, class FF>
534 constexpr TransformedRangeView(RR&& rawRange, FF&& f) noexcept :
535 rawRange_(std::forward<RR>(rawRange)),
536 f_(std::forward<FF>(f))
537 {
538 static_assert(std::is_same_v<T, ValueTransformationTag> or std::is_same_v<T, IteratorTransformationTag>,
539 "The TransformationType passed to TransformedRangeView has to be either ValueTransformationTag or IteratorTransformationTag.");
540 }
541
550 constexpr const_iterator begin() const noexcept {
551 return const_iterator(rawRange_.begin(), &f_);
552 }
553
554 constexpr iterator begin() noexcept {
555 return iterator(rawRange_.begin(), &f_);
556 }
557
566 constexpr const_iterator end() const noexcept {
567 return const_iterator(rawRange_.end(), &f_);
568 }
569
570 constexpr iterator end() noexcept {
571 return iterator(rawRange_.end(), &f_);
572 }
573
577 template<class It=const_iterator,
578 std::enable_if_t<std::is_same_v<typename It::iterator_category,std::random_access_iterator_tag>, int> = 0>
579 constexpr decltype(auto) operator[](std::size_t i) const noexcept
580 {
581 return this->begin()[i];
582 }
583
587 template<class It=iterator,
588 std::enable_if_t<std::is_same_v<typename It::iterator_category,std::random_access_iterator_tag>, int> = 0>
589 constexpr decltype(auto) operator[](std::size_t i) noexcept
590 {
591 return this->begin()[i];
592 }
593
604 template<class Range=R,
605 class = std::void_t<decltype(std::declval<const Range>().size())>>
606 auto size() const noexcept
607 {
608 return rawRange_.size();
609 }
610
614 constexpr bool empty() const noexcept
615 {
616 return rawRange_.begin() == rawRange_.end();
617 }
618
622 const RawRange& rawRange() const noexcept
623 {
624 return rawRange_;
625 }
626
630 RawRange& rawRange() noexcept
631 {
632 return rawRange_;
633 }
634
635 private:
636 R rawRange_;
637 F f_;
638 };
639
668 template <class R, class F>
670 {
671 return TransformedRangeView<R, std::decay_t<F>, ValueTransformationTag>(std::forward<R>(range), std::forward<F>(f));
672 }
673
701 template <class R, class F>
703 {
704 return TransformedRangeView<R, std::decay_t<F>, IteratorTransformationTag>(std::forward<R>(range), std::forward<F>(f));
705 }
706
707
720 template<class Range>
721 auto sparseRange(Range&& range) {
722 return Dune::iteratorTransformedRangeView(std::forward<Range>(range), [](auto&& it) {
723 return std::tuple<decltype(*it), decltype(it.index())>(*it, it.index());
724 });
725 }
726
731}
732
733template <std::derived_from<Dune::Impl::BorrowedIntegralRange> T>
734constexpr bool std::ranges::enable_borrowed_range<T> = true;
735
736#endif // DUNE_COMMON_RANGE_UTILITIES_HH
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
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
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
A range transforming the values of another range on-the-fly.
Definition: rangeutilities.hh:500
Impl::TransformedRangeIterator< RawIterator, F *, T > iterator
Iterator type.
Definition: rangeutilities.hh:520
constexpr TransformedRangeView(RR &&rawRange, FF &&f) noexcept
Construct from range and function.
Definition: rangeutilities.hh:534
Impl::TransformedRangeIterator< RawConstIterator, const F *, T > const_iterator
Const iterator type.
Definition: rangeutilities.hh:512
std::remove_reference_t< R > RawRange
Export type of the wrapped untransformed range.
Definition: rangeutilities.hh:528
RawRange & rawRange() noexcept
Export the wrapped untransformed range.
Definition: rangeutilities.hh:630
const RawRange & rawRange() const noexcept
Export the wrapped untransformed range.
Definition: rangeutilities.hh:622
constexpr const_iterator begin() const noexcept
Obtain a iterator to the first element.
Definition: rangeutilities.hh:550
auto size() const noexcept
Obtain the size of the range.
Definition: rangeutilities.hh:606
constexpr const_iterator end() const noexcept
Obtain a iterator past the last element.
Definition: rangeutilities.hh:566
constexpr bool empty() const noexcept
Checks whether the range is empty.
Definition: rangeutilities.hh:614
Traits for type conversions and type information.
typename AutonomousValueType< T >::type AutonomousValue
Type free of internal references that T can be converted to.
Definition: typetraits.hh:566
auto iteratorTransformedRangeView(R &&range, F &&f)
Create a TransformedRangeView using an iterator transformation.
Definition: rangeutilities.hh:702
auto transformedRangeView(R &&range, F &&f)
Create a TransformedRangeView.
Definition: rangeutilities.hh:669
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:293
auto sparseRange(Range &&range)
Allow structured-binding for-loops for sparse iterators.
Definition: rangeutilities.hh:721
This file implements iterator facade classes for writing stl conformant iterators.
Dune namespace
Definition: alignedallocator.hh:13
Check if a type is callable with ()-operator and given arguments.
Definition: typetraits.hh:162
This class encapsulates access of IteratorFacade.
Definition: iteratorfacades.hh:786
Tag to enable iterator based transformations in TransformedRangeView.
Definition: rangeutilities.hh:332
Tag to enable value based transformations in TransformedRangeView.
Definition: rangeutilities.hh:327
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jun 10, 22:32, 2026)