Dune Core Modules (2.7.1)

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#ifndef DUNE_COMMON_RANGE_UTILITIES_HH
4#define DUNE_COMMON_RANGE_UTILITIES_HH
5
7#include <algorithm>
8#include <utility>
9#include <type_traits>
10#include <bitset>
11
24namespace Dune
25{
31 template <typename T,
32 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
33 typename T::value_type
34 max_value(const T & v) {
35 using std::max_element;
36 return *max_element(v.begin(), v.end());
37 }
38
39 template <typename T,
40 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
41 const T & max_value(const T & v) { return v; }
42
48 template <typename T,
49 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
50 typename T::value_type
51 min_value(const T & v) {
52 using std::min_element;
53 return *min_element(v.begin(), v.end());
54 }
55
56 template <typename T,
57 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
58 const T & min_value(const T & v) { return v; }
59
65 template <typename T,
66 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
67 bool any_true(const T & v) {
68 bool b = false;
69 for (const auto & e : v)
70 b = b or bool(e);
71 return b;
72 }
73
74 template <typename T,
75 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
76 bool any_true(const T & v) { return v; }
77
78 template<std::size_t N>
79 bool any_true(const std::bitset<N> & b)
80 {
81 return b.any();
82 }
83
89 template <typename T,
90 typename std::enable_if<IsIterable<T>::value, int>::type = 0>
91 bool all_true(const T & v) {
92 bool b = true;
93 for (const auto & e : v)
94 b = b and bool(e);
95 return b;
96 }
97
98 template <typename T,
99 typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
100 bool all_true(const T & v) { return v; }
101
102 template<std::size_t N>
103 bool all_true(const std::bitset<N> & b)
104 {
105 return b.all();
106 }
107
108
109
110 namespace Impl
111 {
112
113 template <class T>
114 class IntegralRangeIterator
115 {
116 public:
117 typedef std::random_access_iterator_tag iterator_category;
118 typedef T value_type;
119 typedef std::make_signed_t<T> difference_type;
120 typedef const T *pointer;
121 typedef T reference;
122
123 constexpr IntegralRangeIterator() noexcept : value_(0) {}
124 constexpr explicit IntegralRangeIterator(value_type value) noexcept : value_(value) {}
125
126 pointer operator->() const noexcept { return &value_; }
127 constexpr reference operator*() const noexcept { return value_; }
128
129 constexpr reference operator[]( difference_type n ) const noexcept { return (value_ + n); }
130
131 constexpr bool operator==(const IntegralRangeIterator & other) const noexcept { return (value_ == other.value_); }
132 constexpr bool operator!=(const IntegralRangeIterator & other) const noexcept { return (value_ != other.value_); }
133
134 constexpr bool operator<(const IntegralRangeIterator & other) const noexcept { return (value_ <= other.value_); }
135 constexpr bool operator<=(const IntegralRangeIterator & other) const noexcept { return (value_ <= other.value_); }
136 constexpr bool operator>(const IntegralRangeIterator & other) const noexcept { return (value_ >= other.value_); }
137 constexpr bool operator>=(const IntegralRangeIterator & other) const noexcept { return (value_ >= other.value_); }
138
139 IntegralRangeIterator& operator++() noexcept { ++value_; return *this; }
140 IntegralRangeIterator operator++(int) noexcept { IntegralRangeIterator copy( *this ); ++(*this); return copy; }
141
142 IntegralRangeIterator& operator--() noexcept { --value_; return *this; }
143 IntegralRangeIterator operator--(int) noexcept { IntegralRangeIterator copy( *this ); --(*this); return copy; }
144
145 IntegralRangeIterator& operator+=(difference_type n) noexcept { value_ += n; return *this; }
146 IntegralRangeIterator& operator-=(difference_type n) noexcept { value_ -= n; return *this; }
147
148 friend constexpr IntegralRangeIterator operator+(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ + n); }
149 friend constexpr IntegralRangeIterator operator+(difference_type n, const IntegralRangeIterator &a) noexcept { return IntegralRangeIterator(a.value_ + n); }
150 friend constexpr IntegralRangeIterator operator-(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ - n); }
151
152 constexpr difference_type operator-(const IntegralRangeIterator &other) const noexcept { return (static_cast<difference_type>(value_) - static_cast<difference_type>(other.value_)); }
153
154 private:
155 value_type value_;
156 };
157
158 } // namespace Impl
159
160
161
170 template <class T>
172 {
173 public:
175 typedef T value_type;
177 typedef Impl::IntegralRangeIterator<T> iterator;
179 typedef std::make_unsigned_t<T> size_type;
180
182 constexpr IntegralRange(value_type from, value_type to) noexcept : from_(from), to_(to) {}
184 constexpr explicit IntegralRange(value_type to) noexcept : from_(0), to_(to) {}
186 constexpr IntegralRange(std::pair<value_type, value_type> range) noexcept : from_(range.first), to_(range.second) {}
187
189 constexpr iterator begin() const noexcept { return iterator(from_); }
191 constexpr iterator end() const noexcept { return iterator(to_); }
192
194 constexpr value_type operator[](const value_type &i) const noexcept { return (from_ + i); }
195
197 constexpr bool empty() const noexcept { return (from_ == to_); }
199 constexpr size_type size() const noexcept { return (static_cast<size_type>(to_) - static_cast<size_type>(from_)); }
200
201 private:
202 value_type from_, to_;
203 };
204
205
220 template <class T, T to, T from = 0>
222 {
223 template <T ofs, T... i>
224 static std::integer_sequence<T, (i+ofs)...> shift_integer_sequence(std::integer_sequence<T, i...>);
225
226 public:
228 typedef T value_type;
230 typedef Impl::IntegralRangeIterator<T> iterator;
232 typedef std::make_unsigned_t<T> size_type;
233
235 typedef decltype(shift_integer_sequence<from>(std::make_integer_sequence<T, to-from>())) integer_sequence;
236
238 constexpr StaticIntegralRange() noexcept = default;
239
241 constexpr operator IntegralRange<T>() const noexcept { return {from, to}; }
243 constexpr operator integer_sequence() const noexcept { return {}; }
244
246 static constexpr iterator begin() noexcept { return iterator(from); }
248 static constexpr iterator end() noexcept { return iterator(to); }
249
251 template <class U, U i>
252 constexpr auto operator[](const std::integral_constant<U, i> &) const noexcept
253 -> std::integral_constant<value_type, from + static_cast<value_type>(i)>
254 {
255 return {};
256 }
257
259 constexpr value_type operator[](const size_type &i) const noexcept { return (from + static_cast<value_type>(i)); }
260
262 static constexpr std::integral_constant<bool, from == to> empty() noexcept { return {}; }
264 static constexpr std::integral_constant<size_type, static_cast<size_type>(to) - static_cast<size_type>(from) > size() noexcept { return {}; }
265 };
266
276 template<class T, class U,
277 std::enable_if_t<std::is_same<std::decay_t<T>, std::decay_t<U>>::value, int> = 0,
278 std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
279 inline static IntegralRange<std::decay_t<T>> range(T &&from, U &&to) noexcept
280 {
281 return IntegralRange<std::decay_t<T>>(std::forward<T>(from), std::forward<U>(to));
282 }
283
284 template<class T, std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
285 inline static IntegralRange<std::decay_t<T>> range(T &&to) noexcept
286 {
287 return IntegralRange<std::decay_t<T>>(std::forward<T>(to));
288 }
289
290 template<class T, std::enable_if_t<std::is_enum<std::decay_t<T>>::value, int> = 0>
291 inline static IntegralRange<std::underlying_type_t<std::decay_t<T>>> range(T &&to) noexcept
292 {
293 return IntegralRange<std::underlying_type_t<std::decay_t<T>>>(std::forward<T>(to));
294 }
295
296 template<class T, T from, T to>
297 inline static StaticIntegralRange<T, to, from> range(std::integral_constant<T, from>, std::integral_constant<T, to>) noexcept
298 {
299 return {};
300 }
301
302 template<class T, T to>
303 inline static StaticIntegralRange<T, to> range(std::integral_constant<T, to>) noexcept
304 {
305 return {};
306 }
307
308
309
310 namespace Impl
311 {
312
313 // Helper class to mimic a pointer for proxy objects.
314 // This is needed to implement operator-> on an iterator
315 // using proxy-values. It stores the proxy value but
316 // provides operator-> like a pointer.
317 template<class ProxyType>
318 class PointerProxy
319 {
320 public:
321 PointerProxy(ProxyType&& p) : p_(p)
322 {}
323
324 ProxyType* operator->()
325 {
326 return &p_;
327 }
328
329 ProxyType p_;
330 };
331
332 // An iterator transforming a wrapped iterator using
333 // an unary function. It inherits the iterator-category
334 // of the underlying iterator.
335 template <class I, class F, class C = typename std::iterator_traits<I>::iterator_category>
336 class TransformedRangeIterator;
337
338
339
340 template <class I, class F>
341 class TransformedRangeIterator<I,F,std::forward_iterator_tag>
342 {
343 public:
344 using iterator_category = std::forward_iterator_tag;
345 using reference = decltype(std::declval<F>()(*(std::declval<I>())));
346 using value_type = std::decay_t<reference>;
347 using pointer = PointerProxy<value_type>;
348
349 // If we later want to allow standalone TransformedRangeIterators,
350 // we could customize the FunctionPointer to be a default-constructible,
351 // copy-assignable type storing a function but acting like a pointer
352 // to function.
353 using FunctionPointer = const F*;
354
355 constexpr TransformedRangeIterator(const I& it, FunctionPointer f) noexcept :
356 it_(it),
357 f_(f)
358 {}
359
360 // Explicitly initialize members. Using a plain
361 //
362 // constexpr TransformedRangeIterator() noexcept {}
363 //
364 // would default-initialize the members while
365 //
366 // constexpr TransformedRangeIterator() noexcept : it_(), f_() {}
367 //
368 // leads to value-initialization. This is a case where
369 // both are really different. If it_ is a raw pointer (i.e. POD)
370 // then default-initialization leaves it uninitialized while
371 // value-initialization zero-initializes it.
372 constexpr TransformedRangeIterator() noexcept :
373 it_(),
374 f_()
375 {}
376
377 // Dereferencing returns a value created by the function
378 constexpr reference operator*() const noexcept {
379 return (*f_)(*it_);
380 }
381
382 // Dereferencing returns a value created by the function
383 pointer operator->() const noexcept {
384 return (*f_)(*it_);
385 }
386
387 constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default;
388
389 constexpr bool operator==(const TransformedRangeIterator& other) const noexcept {
390 return (it_ == other.it_);
391 }
392
393 constexpr bool operator!=(const TransformedRangeIterator& other) const noexcept {
394 return (it_ != other.it_);
395 }
396
397 TransformedRangeIterator& operator++() noexcept {
398 ++it_;
399 return *this;
400 }
401
402 TransformedRangeIterator operator++(int) noexcept {
403 TransformedRangeIterator copy(*this);
404 ++(*this);
405 return copy;
406 }
407
408 protected:
409 I it_;
410 FunctionPointer f_;
411 };
412
413
414
415 template <class I, class F>
416 class TransformedRangeIterator<I,F,std::bidirectional_iterator_tag> :
417 public TransformedRangeIterator<I,F,std::forward_iterator_tag>
418 {
419 protected:
420 using Base = TransformedRangeIterator<I,F,std::forward_iterator_tag>;
421 using Base::it_;
422 using Base::f_;
423 public:
424 using iterator_category = std::bidirectional_iterator_tag;
425 using reference = typename Base::reference;
426 using value_type = typename Base::value_type;
427 using pointer = typename Base::pointer;
428
429 using FunctionPointer = typename Base::FunctionPointer;
430
431 using Base::Base;
432
433 // Member functions of the forward_iterator that need
434 // to be redefined because the base class methods return a
435 // forward_iterator.
436 constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default;
437
438 TransformedRangeIterator& operator++() noexcept {
439 ++it_;
440 return *this;
441 }
442
443 TransformedRangeIterator operator++(int) noexcept {
444 TransformedRangeIterator copy(*this);
445 ++(*this);
446 return copy;
447 }
448
449 // Additional member functions of bidirectional_iterator
450 TransformedRangeIterator& operator--() noexcept {
451 --(this->it_);
452 return *this;
453 }
454
455 TransformedRangeIterator operator--(int) noexcept {
456 TransformedRangeIterator copy(*this);
457 --(*this);
458 return copy;
459 }
460 };
461
462
463
464 template <class I, class F>
465 class TransformedRangeIterator<I,F,std::random_access_iterator_tag> :
466 public TransformedRangeIterator<I,F,std::bidirectional_iterator_tag>
467 {
468 protected:
469 using Base = TransformedRangeIterator<I,F,std::bidirectional_iterator_tag>;
470 using Base::it_;
471 using Base::f_;
472 public:
473 using iterator_category = std::random_access_iterator_tag;
474 using reference = typename Base::reference;
475 using value_type = typename Base::value_type;
476 using pointer = typename Base::pointer;
477 using difference_type = typename std::iterator_traits<I>::difference_type;
478
479 using FunctionPointer = typename Base::FunctionPointer;
480
481 using Base::Base;
482
483 // Member functions of the forward_iterator that need
484 // to be redefined because the base class methods return a
485 // forward_iterator.
486 constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default;
487
488 TransformedRangeIterator& operator++() noexcept {
489 ++it_;
490 return *this;
491 }
492
493 TransformedRangeIterator operator++(int) noexcept {
494 TransformedRangeIterator copy(*this);
495 ++(*this);
496 return copy;
497 }
498
499 // Member functions of the bidirectional_iterator that need
500 // to be redefined because the base class methods return a
501 // bidirectional_iterator.
502 TransformedRangeIterator& operator--() noexcept {
503 --(this->it_);
504 return *this;
505 }
506
507 TransformedRangeIterator operator--(int) noexcept {
508 TransformedRangeIterator copy(*this);
509 --(*this);
510 return copy;
511 }
512
513 // Additional member functions of random_access_iterator
514 TransformedRangeIterator& operator+=(difference_type n) noexcept {
515 it_ += n;
516 return *this;
517 }
518
519 TransformedRangeIterator& operator-=(difference_type n) noexcept {
520 it_ -= n;
521 return *this;
522 }
523
524 bool operator<(const TransformedRangeIterator& other) noexcept {
525 return it_<other.it_;
526 }
527
528 bool operator<=(const TransformedRangeIterator& other) noexcept {
529 return it_<=other.it_;
530 }
531
532 bool operator>(const TransformedRangeIterator& other) noexcept {
533 return it_>other.it_;
534 }
535
536 bool operator>=(const TransformedRangeIterator& other) noexcept {
537 return it_>=other.it_;
538 }
539
540 reference operator[](difference_type n) noexcept {
541 return (*f_)(*(it_+n));
542 }
543
544 friend
545 TransformedRangeIterator operator+(const TransformedRangeIterator& it, difference_type n) noexcept {
546 return TransformedRangeIterator(it.it_+n, it.f_);
547 }
548
549 friend
550 TransformedRangeIterator operator+(difference_type n, const TransformedRangeIterator& it) noexcept {
551 return TransformedRangeIterator(n+it.it_, it.f_);
552 }
553
554 friend
555 TransformedRangeIterator operator-(const TransformedRangeIterator& it, difference_type n) noexcept {
556 return TransformedRangeIterator(it.it_-n, it.f_);
557 }
558
559 friend
560 difference_type operator-(const TransformedRangeIterator& first, const TransformedRangeIterator& second) noexcept {
561 return first.it_-second.it_;
562 }
563 };
564
565
566 } // namespace Impl
567
568
569
599 template <class R, class F>
601 {
602 using RawConstIterator = std::decay_t<decltype(std::declval<const R>().begin())>;
603 using RawIterator = std::decay_t<decltype(std::declval<R>().begin())>;
604
605 public:
606
613 using const_iterator = Impl::TransformedRangeIterator<RawConstIterator, F>;
614
621 using iterator = Impl::TransformedRangeIterator<RawIterator, F>;
622
629 using RawRange = std::remove_reference_t<R>;
630
634 template<class RR>
635 constexpr TransformedRangeView(RR&& rawRange, const F& f) noexcept :
636 rawRange_(std::forward<RR>(rawRange)),
637 f_(f)
638 {}
639
648 constexpr const_iterator begin() const noexcept {
649 return const_iterator(rawRange_.begin(), &f_);
650 }
651
652 constexpr iterator begin() noexcept {
653 return iterator(rawRange_.begin(), &f_);
654 }
655
664 constexpr const_iterator end() const noexcept {
665 return const_iterator(rawRange_.end(), &f_);
666 }
667
668 constexpr iterator end() noexcept {
669 return iterator(rawRange_.end(), &f_);
670 }
671
682 template<class Dummy=R,
683 class = void_t<decltype(std::declval<Dummy>().size())>>
684 auto size() const
685 {
686 return rawRange_.size();
687 }
688
692 const RawRange& rawRange() const
693 {
694 return rawRange_;
695 }
696
701 {
702 return rawRange_;
703 }
704
705 private:
706 R rawRange_;
707 F f_;
708 };
709
735 template <class R, class F>
736 auto transformedRangeView(R&& range, const F& f)
737 {
738 return TransformedRangeView<R, F>(std::forward<R>(range), f);
739 }
740
741}
742
747#endif // DUNE_COMMON_RANGE_UTILITIES_HH
dynamic integer range for use in range-based for loops
Definition: rangeutilities.hh:172
constexpr iterator begin() const noexcept
obtain a random-access iterator to the first element
Definition: rangeutilities.hh:189
constexpr iterator end() const noexcept
obtain a random-access iterator past the last element
Definition: rangeutilities.hh:191
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition: rangeutilities.hh:179
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition: rangeutilities.hh:177
constexpr value_type operator[](const value_type &i) const noexcept
access specified element
Definition: rangeutilities.hh:194
constexpr bool empty() const noexcept
check whether the range is empty
Definition: rangeutilities.hh:197
constexpr IntegralRange(std::pair< value_type, value_type > range) noexcept
construct integer range std::pair
Definition: rangeutilities.hh:186
constexpr IntegralRange(value_type from, value_type to) noexcept
construct integer range [from, to)
Definition: rangeutilities.hh:182
constexpr size_type size() const noexcept
obtain number of elements in the range
Definition: rangeutilities.hh:199
constexpr IntegralRange(value_type to) noexcept
construct integer range [0, to)
Definition: rangeutilities.hh:184
T value_type
type of integers contained in the range
Definition: rangeutilities.hh:175
static integer range for use in range-based for loops
Definition: rangeutilities.hh:222
static constexpr iterator end() noexcept
obtain a random-access iterator past the last element
Definition: rangeutilities.hh:248
decltype(shift_integer_sequence< from >(std::make_integer_sequence< T, to-from >())) integer_sequence
type of corresponding std::integer_sequence
Definition: rangeutilities.hh:235
constexpr StaticIntegralRange() noexcept=default
default constructor
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition: rangeutilities.hh:232
T value_type
type of integers contained in the range
Definition: rangeutilities.hh:228
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:252
static constexpr std::integral_constant< bool, from==to > empty() noexcept
check whether the range is empty
Definition: rangeutilities.hh:262
static constexpr iterator begin() noexcept
obtain a random-access iterator to the first element
Definition: rangeutilities.hh:246
constexpr value_type operator[](const size_type &i) const noexcept
access specified element (dynamic version)
Definition: rangeutilities.hh:259
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition: rangeutilities.hh:230
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:264
A range transforming the values of another range on-the-fly.
Definition: rangeutilities.hh:601
const RawRange & rawRange() const
Export the wrapped untransformed range.
Definition: rangeutilities.hh:692
constexpr TransformedRangeView(RR &&rawRange, const F &f) noexcept
Construct from range and function.
Definition: rangeutilities.hh:635
Impl::TransformedRangeIterator< RawIterator, F > iterator
Iterator type.
Definition: rangeutilities.hh:621
constexpr const_iterator end() const noexcept
Obtain a iterator past the last element.
Definition: rangeutilities.hh:664
constexpr const_iterator begin() const noexcept
Obtain a iterator to the first element.
Definition: rangeutilities.hh:648
auto size() const
Obtain the size of the range.
Definition: rangeutilities.hh:684
std::remove_reference_t< R > RawRange
Export type of the wrapped untransformed range.
Definition: rangeutilities.hh:629
RawRange & rawRange()
Export the wrapped untransformed range.
Definition: rangeutilities.hh:700
Impl::TransformedRangeIterator< RawConstIterator, F > const_iterator
Const iterator type.
Definition: rangeutilities.hh:613
EnableIfInterOperable< T1, T2, bool >::type operator<(const RandomAccessIteratorFacade< T1, V1, R1, D > &lhs, const RandomAccessIteratorFacade< T2, V2, R2, D > &rhs)
Comparison operator.
Definition: iteratorfacades.hh:635
EnableIfInterOperable< T1, T2, bool >::type operator>(const RandomAccessIteratorFacade< T1, V1, R1, D > &lhs, const RandomAccessIteratorFacade< T2, V2, R2, D > &rhs)
Comparison operator.
Definition: iteratorfacades.hh:681
EnableIfInterOperable< T1, T2, bool >::type operator<=(const RandomAccessIteratorFacade< T1, V1, R1, D > &lhs, const RandomAccessIteratorFacade< T2, V2, R2, D > &rhs)
Comparison operator.
Definition: iteratorfacades.hh:658
EnableIfInterOperable< T1, T2, bool >::type operator==(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for equality.
Definition: iteratorfacades.hh:235
EnableIfInterOperable< T1, T2, bool >::type operator>=(const RandomAccessIteratorFacade< T1, V1, R1, D > &lhs, const RandomAccessIteratorFacade< T2, V2, R2, D > &rhs)
Comparison operator.
Definition: iteratorfacades.hh:703
EnableIfInterOperable< T1, T2, bool >::type operator!=(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for inequality.
Definition: iteratorfacades.hh:257
Dune namespace.
Definition: alignedallocator.hh:14
auto transformedRangeView(R &&range, const F &f)
Create a TransformedRangeView.
Definition: rangeutilities.hh:736
STL namespace.
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 12, 23:30, 2024)