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 
24 namespace 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
decltype(shift_integer_sequence< from >(std::make_integer_sequence< T, to-from >())) typedef integer_sequence
type of corresponding std::integer_sequence
Definition: rangeutilities.hh:235
static constexpr iterator end() noexcept
obtain a random-access iterator past the last element
Definition: rangeutilities.hh:248
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 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
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
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
RawRange & rawRange()
Export the wrapped untransformed range.
Definition: rangeutilities.hh:700
std::remove_reference_t< R > RawRange
Export type of the wrapped untransformed range.
Definition: rangeutilities.hh:629
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: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: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:703
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
Dune namespace.
Definition: alignedallocator.hh:14
constexpr bool operator!=(const DebugAllocator< T > &, const DebugAllocator< T > &)
check whether allocators are not equivalent
Definition: debugallocator.hh:318
auto transformedRangeView(R &&range, const F &f)
Create a TransformedRangeView.
Definition: rangeutilities.hh:736
constexpr bool operator==(const DebugAllocator< T > &, const DebugAllocator< T > &)
check whether allocators are equivalent
Definition: debugallocator.hh:310
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 8, 22:30, 2024)