dune-common  2.11
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 
15 
23 namespace Dune
24 {
25 
36  template <typename T,
37  typename std::enable_if<IsIterable<T>::value, int>::type = 0>
38  typename T::value_type
39  max_value(const T & v) {
40  using std::max_element;
41  return *max_element(v.begin(), v.end());
42  }
43 
44  template <typename T,
45  typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
46  const T & max_value(const T & v) { return v; }
47 
53  template <typename T,
54  typename std::enable_if<IsIterable<T>::value, int>::type = 0>
55  typename T::value_type
56  min_value(const T & v) {
57  using std::min_element;
58  return *min_element(v.begin(), v.end());
59  }
60 
61  template <typename T,
62  typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
63  const T & min_value(const T & v) { return v; }
64 
70  template <typename T,
71  typename std::enable_if<IsIterable<T>::value, int>::type = 0>
72  bool any_true(const T & v) {
73  bool b = false;
74  for (const auto & e : v)
75  b = b or bool(e);
76  return b;
77  }
78 
79  template <typename T,
80  typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
81  bool any_true(const T & v) { return v; }
82 
83  template<std::size_t N>
84  bool any_true(const std::bitset<N> & b)
85  {
86  return b.any();
87  }
88 
94  template <typename T,
95  typename std::enable_if<IsIterable<T>::value, int>::type = 0>
96  bool all_true(const T & v) {
97  bool b = true;
98  for (const auto & e : v)
99  b = b and bool(e);
100  return b;
101  }
102 
103  template <typename T,
104  typename std::enable_if<!IsIterable<T>::value, int>::type = 0>
105  bool all_true(const T & v) { return v; }
106 
107  template<std::size_t N>
108  bool all_true(const std::bitset<N> & b)
109  {
110  return b.all();
111  }
112 
113 
114 
115  namespace Impl
116  {
117 
118  template <class T>
119  class IntegralRangeIterator
120  {
121  public:
122  typedef std::random_access_iterator_tag iterator_category;
123  typedef T value_type;
124  typedef std::make_signed_t<T> difference_type;
125  typedef const T *pointer;
126  typedef T reference;
127 
128  constexpr IntegralRangeIterator() noexcept : value_(0) {}
129  constexpr explicit IntegralRangeIterator(value_type value) noexcept : value_(value) {}
130 
131  pointer operator->() const noexcept { return &value_; }
132  constexpr reference operator*() const noexcept { return value_; }
133 
134  constexpr reference operator[]( difference_type n ) const noexcept { return (value_ + n); }
135 
136  constexpr auto operator<=>(const IntegralRangeIterator & other) const noexcept = default;
137 
138  IntegralRangeIterator& operator++() noexcept { ++value_; return *this; }
139  IntegralRangeIterator operator++(int) noexcept { IntegralRangeIterator copy( *this ); ++(*this); return copy; }
140 
141  IntegralRangeIterator& operator--() noexcept { --value_; return *this; }
142  IntegralRangeIterator operator--(int) noexcept { IntegralRangeIterator copy( *this ); --(*this); return copy; }
143 
144  IntegralRangeIterator& operator+=(difference_type n) noexcept { value_ += n; return *this; }
145  IntegralRangeIterator& operator-=(difference_type n) noexcept { value_ -= n; return *this; }
146 
147  friend constexpr IntegralRangeIterator operator+(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ + n); }
148  friend constexpr IntegralRangeIterator operator+(difference_type n, const IntegralRangeIterator &a) noexcept { return IntegralRangeIterator(a.value_ + n); }
149  friend constexpr IntegralRangeIterator operator-(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ - n); }
150 
151  constexpr difference_type operator-(const IntegralRangeIterator &other) const noexcept { return (static_cast<difference_type>(value_) - static_cast<difference_type>(other.value_)); }
152 
153  private:
154  value_type value_;
155  };
156 
157  } // namespace Impl
158 
159 
160 
169  template <class T>
171  {
172  public:
174  typedef T value_type;
176  typedef Impl::IntegralRangeIterator<T> iterator;
178  typedef std::make_unsigned_t<T> size_type;
179 
181  constexpr IntegralRange(value_type from, value_type to) noexcept : from_(from), to_(to) {}
183  constexpr explicit IntegralRange(value_type to) noexcept : from_(0), to_(to) {}
185  constexpr IntegralRange(std::pair<value_type, value_type> range) noexcept : from_(range.first), to_(range.second) {}
186 
188  constexpr iterator begin() const noexcept { return iterator(from_); }
190  constexpr iterator end() const noexcept { return iterator(to_); }
191 
193  constexpr value_type operator[](const value_type &i) const noexcept { return (from_ + i); }
194 
196  constexpr bool empty() const noexcept { return (from_ == to_); }
198  constexpr size_type size() const noexcept { return (static_cast<size_type>(to_) - static_cast<size_type>(from_)); }
199 
201  constexpr bool contains(value_type index) const noexcept { return from_ <= index && index < to_; }
202 
203  private:
204  value_type from_, to_;
205  };
206 
207 
222  template <class T, T to, T from = 0>
224  {
225  template <T ofs, T... i>
226  static std::integer_sequence<T, (i+ofs)...> shift_integer_sequence(std::integer_sequence<T, i...>);
227 
228  public:
230  typedef T value_type;
232  typedef Impl::IntegralRangeIterator<T> iterator;
234  typedef std::make_unsigned_t<T> size_type;
235 
237  typedef decltype(shift_integer_sequence<from>(std::make_integer_sequence<T, to-from>())) integer_sequence;
238 
240  constexpr StaticIntegralRange() noexcept = default;
241 
243  constexpr operator IntegralRange<T>() const noexcept { return {from, to}; }
245  constexpr operator integer_sequence() const noexcept { return {}; }
246 
248  static constexpr integer_sequence to_integer_sequence() noexcept { return {}; }
249 
251  static constexpr iterator begin() noexcept { return iterator(from); }
253  static constexpr iterator end() noexcept { return iterator(to); }
254 
256  template <class U, U i>
257  constexpr auto operator[](const std::integral_constant<U, i> &) const noexcept
258  -> std::integral_constant<value_type, from + static_cast<value_type>(i)>
259  {
260  return {};
261  }
262 
264  constexpr value_type operator[](const size_type &i) const noexcept { return (from + static_cast<value_type>(i)); }
265 
267  static constexpr std::integral_constant<bool, from == to> empty() noexcept { return {}; }
269  static constexpr std::integral_constant<size_type, static_cast<size_type>(to) - static_cast<size_type>(from) > size() noexcept { return {}; }
270 
272  static constexpr bool contains(value_type index) noexcept { return from <= index && index < to; }
273 
274  };
275 
285  template<class T, class U,
286  std::enable_if_t<std::is_same<std::decay_t<T>, std::decay_t<U>>::value, int> = 0,
287  std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
288  constexpr static IntegralRange<std::decay_t<T>> range(T &&from, U &&to) noexcept
289  {
290  return IntegralRange<std::decay_t<T>>(std::forward<T>(from), std::forward<U>(to));
291  }
292 
293  template<class T, std::enable_if_t<std::is_integral<std::decay_t<T>>::value, int> = 0>
294  constexpr static IntegralRange<std::decay_t<T>> range(T &&to) noexcept
295  {
296  return IntegralRange<std::decay_t<T>>(std::forward<T>(to));
297  }
298 
299  template<class T, std::enable_if_t<std::is_enum<std::decay_t<T>>::value, int> = 0>
301  {
302  return IntegralRange<std::underlying_type_t<std::decay_t<T>>>(std::forward<T>(to));
303  }
304 
305  template<class T, T from, T to>
306  constexpr static StaticIntegralRange<T, to, from> range(std::integral_constant<T, from>, std::integral_constant<T, to>) noexcept
307  {
308  return {};
309  }
310 
311  template<class T, T to>
312  constexpr static StaticIntegralRange<T, to> range(std::integral_constant<T, to>) noexcept
313  {
314  return {};
315  }
316 
317 
318 
323 
328 
329  namespace Impl
330  {
331 
332 
333 
334  // An iterator transforming a wrapped iterator using
335  // an unary function. It inherits the iterator-category
336  // of the underlying iterator.
337  //
338  // \tparam I Type of the underlying iterator
339  // \tparam F Type of transformation function that can either be applied directly or after dereferencing
340  // \tparam TT Type of transformation (ValueTransformationTag or IteratorTransformationTag)
341  // \tparam C An iterator category tag, defaults to the one of I
342  template <class I, class F, class TT, class C = typename std::iterator_traits<I>::iterator_category>
343  class TransformedRangeIterator;
344 
345  template<class I, class F, class TT, class C>
346  struct TransformationRangeIteratorTraits
347  {
348  template<class FF>
349  static decltype(auto) transform(FF&& f, const I& it) {
350  if constexpr (std::is_same_v<TT,IteratorTransformationTag>)
351  {
352  if constexpr (Dune::IsCallable<FF(const I&)>::value)
353  return f(it);
354  else
355  return (*f)(it);
356  }
357  else
358  {
359  if constexpr (Dune::IsCallable<FF(decltype(*it))>::value)
360  return f(*it);
361  else
362  return (*f)(*it);
363  }
364  }
365 
366  using reference = decltype(transform(std::declval<F>(), std::declval<I>()));
367  using value_type = Dune::AutonomousValue<reference>;
368  using pointer = std::conditional_t<std::is_lvalue_reference_v<reference>, value_type*, ProxyArrowResult<reference>>;
369  using difference_type = typename std::iterator_traits<I>::difference_type;
370  using Facade = Dune::IteratorFacade<TransformedRangeIterator<I,F,TT,C>, C, value_type, reference, pointer, difference_type>;
371  };
372 
373 
374  template <class I, class F, class TT, class C>
375  class TransformedRangeIterator :
376  public TransformationRangeIteratorTraits<I,F, TT, C>::Facade
377  {
378  using Traits = TransformationRangeIteratorTraits<I,F, TT, C>;
379  using Facade = typename Traits::Facade;
380 
381  static constexpr bool isBidirectional = std::is_convertible_v<C, std::bidirectional_iterator_tag>;
382  static constexpr bool isRandomAccess = std::is_convertible_v<C, std::random_access_iterator_tag>;
383 
384  public:
385 
386  using Function = F;
387  using reference = typename Facade::reference;
388  using difference_type = typename Facade::difference_type;
389 
390  template<class II, class FF>
391  constexpr TransformedRangeIterator(II&& it, FF&& f) noexcept :
392  it_(std::forward<II>(it)),
393  f_(std::forward<FF>(f))
394  {}
395 
396  template<class II,
397  disableCopyMove<TransformedRangeIterator,II> =0,
398  std::enable_if_t<std::is_convertible_v<II, I> and std::is_default_constructible_v<F>, int> =0>
399  constexpr TransformedRangeIterator(II&& it) noexcept :
400  it_(std::forward<II>(it)),
401  f_()
402  {}
403 
404  template<class FF,
405  disableCopyMove<TransformedRangeIterator,FF> =0,
406  std::enable_if_t<std::is_convertible_v<FF, F> and std::is_default_constructible_v<I>, int> =0>
407  constexpr TransformedRangeIterator(FF&& f) noexcept :
408  it_(),
409  f_(std::forward<FF>(f))
410  {}
411 
412  // Explicitly initialize members. Using a plain
413  //
414  // constexpr TransformedRangeIterator() noexcept {}
415  //
416  // would default-initialize the members while
417  //
418  // constexpr TransformedRangeIterator() noexcept : it_(), f_() {}
419  //
420  // leads to value-initialization. This is a case where
421  // both are really different. If it_ is a raw pointer (i.e. POD)
422  // then default-initialization leaves it uninitialized while
423  // value-initialization zero-initializes it.
424  constexpr TransformedRangeIterator() noexcept :
425  it_(),
426  f_()
427  {}
428 
429  // Dereferencing returns a value created by the function
430  constexpr reference operator*() const noexcept {
431  return Traits::transform(f_, it_);
432  }
433 
434  protected:
435 
437 
438  // Export base iterator, such that equalilty comparison,
439  // differences, and inequality comparisons are automatically
440  // forwarded to the base iterator by the facade.
441  const I& baseIterator() const noexcept {
442  return it_;
443  }
444 
445  I& baseIterator() noexcept {
446  return it_;
447  }
448 
449  I it_;
450  Function f_;
451  };
452 
453  } // namespace Impl
454 
455 
456 
493  template <class R, class F, class T=ValueTransformationTag>
495  {
496  using RawConstIterator = std::decay_t<decltype(std::declval<const R>().begin())>;
497  using RawIterator = std::decay_t<decltype(std::declval<R>().begin())>;
498 
499  public:
500 
507  using const_iterator = Impl::TransformedRangeIterator<RawConstIterator, const F*, T>;
508 
515  using iterator = Impl::TransformedRangeIterator<RawIterator, F*, T>;
516 
523  using RawRange = std::remove_reference_t<R>;
524 
528  template<class RR, class FF>
529  constexpr TransformedRangeView(RR&& rawRange, FF&& f) noexcept :
530  rawRange_(std::forward<RR>(rawRange)),
531  f_(std::forward<FF>(f))
532  {
533  static_assert(std::is_same_v<T, ValueTransformationTag> or std::is_same_v<T, IteratorTransformationTag>,
534  "The TransformationType passed to TransformedRangeView has to be either ValueTransformationTag or IteratorTransformationTag.");
535  }
536 
545  constexpr const_iterator begin() const noexcept {
546  return const_iterator(rawRange_.begin(), &f_);
547  }
548 
549  constexpr iterator begin() noexcept {
550  return iterator(rawRange_.begin(), &f_);
551  }
552 
561  constexpr const_iterator end() const noexcept {
562  return const_iterator(rawRange_.end(), &f_);
563  }
564 
565  constexpr iterator end() noexcept {
566  return iterator(rawRange_.end(), &f_);
567  }
568 
572  template<class It=const_iterator,
573  std::enable_if_t<std::is_same_v<typename It::iterator_category,std::random_access_iterator_tag>, int> = 0>
574  constexpr decltype(auto) operator[](std::size_t i) const noexcept
575  {
576  return this->begin()[i];
577  }
578 
582  template<class It=iterator,
583  std::enable_if_t<std::is_same_v<typename It::iterator_category,std::random_access_iterator_tag>, int> = 0>
584  constexpr decltype(auto) operator[](std::size_t i) noexcept
585  {
586  return this->begin()[i];
587  }
588 
599  template<class Range=R,
600  class = std::void_t<decltype(std::declval<const Range>().size())>>
601  auto size() const noexcept
602  {
603  return rawRange_.size();
604  }
605 
609  constexpr bool empty() const noexcept
610  {
611  return rawRange_.begin() == rawRange_.end();
612  }
613 
617  const RawRange& rawRange() const noexcept
618  {
619  return rawRange_;
620  }
621 
625  RawRange& rawRange() noexcept
626  {
627  return rawRange_;
628  }
629 
630  private:
631  R rawRange_;
632  F f_;
633  };
634 
663  template <class R, class F>
664  auto transformedRangeView(R&& range, F&& f)
665  {
666  return TransformedRangeView<R, std::decay_t<F>, ValueTransformationTag>(std::forward<R>(range), std::forward<F>(f));
667  }
668 
696  template <class R, class F>
698  {
699  return TransformedRangeView<R, std::decay_t<F>, IteratorTransformationTag>(std::forward<R>(range), std::forward<F>(f));
700  }
701 
702 
715  template<class Range>
716  auto sparseRange(Range&& range) {
717  return Dune::iteratorTransformedRangeView(std::forward<Range>(range), [](auto&& it) {
718  return std::tuple<decltype(*it), decltype(it.index())>(*it, it.index());
719  });
720  }
721 
726 }
727 
728 #endif // DUNE_COMMON_RANGE_UTILITIES_HH
static constexpr bool contains(value_type index) noexcept
check whether given index is within range [from, to)
Definition: rangeutilities.hh:272
A range transforming the values of another range on-the-fly.
Definition: rangeutilities.hh:494
decltype(shift_integer_sequence< from >(std::make_integer_sequence< T, to-from >())) typedef integer_sequence
type of corresponding std::integer_sequence
Definition: rangeutilities.hh:237
constexpr iterator end() const noexcept
obtain a random-access iterator past the last element
Definition: rangeutilities.hh:190
constexpr iterator begin() const noexcept
obtain a random-access iterator to the first element
Definition: rangeutilities.hh:188
T max_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:494
constexpr const_iterator begin() const noexcept
Obtain a iterator to the first element.
Definition: rangeutilities.hh:545
auto sparseRange(Range &&range)
Allow structured-binding for-loops for sparse iterators.
Definition: rangeutilities.hh:716
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:269
constexpr value_type operator[](const value_type &i) const noexcept
access specified element
Definition: rangeutilities.hh:193
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition: rangeutilities.hh:234
constexpr iterator end() noexcept
Definition: rangeutilities.hh:565
This file implements iterator facade classes for writing stl conformant iterators.
T value_type
type of integers contained in the range
Definition: rangeutilities.hh:230
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition: rangeutilities.hh:176
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:257
bigunsignedint< k > operator+(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:558
Check if a type is callable with ()-operator and given arguments.
Definition: typetraits.hh:162
bool all_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:512
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:572
auto iteratorTransformedRangeView(R &&range, F &&f)
Create a TransformedRangeView using an iterator transformation.
Definition: rangeutilities.hh:697
constexpr IntegralRange(value_type from, value_type to) noexcept
construct integer range [from, to)
Definition: rangeutilities.hh:181
constexpr value_type operator[](const size_type &i) const noexcept
access specified element (dynamic version)
Definition: rangeutilities.hh:264
const RawRange & rawRange() const noexcept
Export the wrapped untransformed range.
Definition: rangeutilities.hh:617
static constexpr iterator begin() noexcept
obtain a random-access iterator to the first element
Definition: rangeutilities.hh:251
I i
Definition: hybridmultiindex.hh:328
bool any_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:506
static integer range for use in range-based for loops
Definition: rangeutilities.hh:223
Dune namespace
Definition: alignedallocator.hh:12
auto transformedRangeView(R &&range, F &&f)
Create a TransformedRangeView.
Definition: rangeutilities.hh:664
RawRange & rawRange() noexcept
Export the wrapped untransformed range.
Definition: rangeutilities.hh:625
constexpr bool empty() const noexcept
Checks whether the range is empty.
Definition: rangeutilities.hh:609
constexpr size_type size() const noexcept
obtain number of elements in the range
Definition: rangeutilities.hh:198
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:288
This class encapsulates access of IteratorFacade.
Definition: iteratorfacades.hh:785
bigunsignedint< k > operator-(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:565
constexpr IntegralRange(std::pair< value_type, value_type > range) noexcept
construct integer range std::pair
Definition: rangeutilities.hh:185
Tag to enable iterator based transformations in TransformedRangeView.
Definition: rangeutilities.hh:327
std::make_unsigned_t< T > size_type
unsigned integer type corresponding to value_type
Definition: rangeutilities.hh:178
constexpr iterator begin() noexcept
Definition: rangeutilities.hh:549
T min_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:500
std::remove_reference_t< R > RawRange
Export type of the wrapped untransformed range.
Definition: rangeutilities.hh:523
Impl::TransformedRangeIterator< RawIterator, F *, T > iterator
Iterator type.
Definition: rangeutilities.hh:515
auto size() const noexcept
Obtain the size of the range.
Definition: rangeutilities.hh:601
static constexpr iterator end() noexcept
obtain a random-access iterator past the last element
Definition: rangeutilities.hh:253
Impl::IntegralRangeIterator< T > iterator
type of iterator
Definition: rangeutilities.hh:232
dynamic integer range for use in range-based for loops
Definition: rangeutilities.hh:170
CRTP-Mixing class for stl conformant iterators of given iterator category.
Definition: iteratorfacades.hh:1052
constexpr TransformedRangeView(RR &&rawRange, FF &&f) noexcept
Construct from range and function.
Definition: rangeutilities.hh:529
constexpr const_iterator end() const noexcept
Obtain a iterator past the last element.
Definition: rangeutilities.hh:561
constexpr bool contains(value_type index) const noexcept
check whether given index is within range [from, to)
Definition: rangeutilities.hh:201
STL namespace.
typename AutonomousValueType< T >::type AutonomousValue
Type free of internal references that T can be converted to.
Definition: typetraits.hh:566
Traits for type conversions and type information.
Tag to enable value based transformations in TransformedRangeView.
Definition: rangeutilities.hh:322
T value_type
type of integers contained in the range
Definition: rangeutilities.hh:174
static constexpr std::integral_constant< bool, from==to > empty() noexcept
check whether the range is empty
Definition: rangeutilities.hh:267
Impl::TransformedRangeIterator< RawConstIterator, const F *, T > const_iterator
Const iterator type.
Definition: rangeutilities.hh:507
static constexpr integer_sequence to_integer_sequence() noexcept
return corresponding std::integer_sequence
Definition: rangeutilities.hh:248
constexpr IntegralRange(value_type to) noexcept
construct integer range [0, to)
Definition: rangeutilities.hh:183
constexpr bool empty() const noexcept
check whether the range is empty
Definition: rangeutilities.hh:196