MeVisLab Toolbox Reference
mlContainerHelpers.h
Go to the documentation of this file.
1 /*************************************************************************************
2 **
3 ** Copyright 2021, MeVis Medical Solutions AG
4 **
5 ** The user may use this file in accordance with the license agreement provided with
6 ** the Software or, alternatively, in accordance with the terms contained in a
7 ** written agreement between the user and MeVis Medical Solutions AG.
8 **
9 ** For further information use the contact form at https://www.mevislab.de/contact
10 **
11 **************************************************************************************/
12 
13 #pragma once
14 
15 #include "mlUtilsSystem.h"
16 #include <algorithm>
17 #include <iterator>
18 
19 ML_UTILS_START_NAMESPACE
25  template <class T>
26  struct Is
27  {
28  T d_;
29  template <typename U>
30  constexpr bool in(U a) {
31  return a == d_;
32  }
33 
34  template <class Arg, class... Args>
35  constexpr bool in(Arg a, Args... args) {
36  return in(a) || in(args...);
37  }
38  };
39 
40  template <class T>
41  constexpr Is<T> is(T d) {
42  return Is<T>{d};
43  }
44 
45 
63  template <class T, class R, typename I, I (T::*Count)() const, R *(T::*Access)(I) const>
65  {
66  const T* _object;
67 
68  public:
69  using value_type = R *;
70 
71  explicit ContainerProxy(const T &object)
72  : _object(&object)
73  {
74  }
75 
76  ContainerProxy(const ContainerProxy &) = default;
80 
81  class iterator
82  {
83  public:
84  using iterator_category = std::bidirectional_iterator_tag;
86  using difference_type = ptrdiff_t;
88  using const_pointer = const pointer;
90  using const_reference = const reference;
91 
92  iterator(const ContainerProxy &proxy, I index)
93  : _index{index}
94  , _proxy{&proxy}
95  {
96  }
97 
98  iterator(const iterator &) = default;
99  iterator &operator=(const iterator &) = default;
100  iterator(iterator &&) = default;
101  iterator &operator=(iterator &&) = default;
102 
103  I index() const { return _index; }
104 
106  {
107  return (_proxy->_object->*Access)(_index);
108  }
109 
111  {
112  return operator*();
113  }
114 
116  {
117  _index += 1;
118  return *this;
119  }
120 
122  {
123  iterator tmp = *this;
124  ++*this;
125  return tmp;
126  }
127 
129  {
130  _index -= 1;
131  return *this;
132  }
133 
135  {
136  iterator tmp = *this;
137  --*this;
138  return tmp;
139  }
140 
141  friend bool operator==(const iterator &x, const iterator &y)
142  {
143  return x._proxy == y._proxy && x._index == y._index;
144  }
145 
146  friend bool operator!=(const iterator &x, const iterator &y)
147  {
148  return !(x == y);
149  }
150 
151 
152  private:
153  I _index;
154  const ContainerProxy *_proxy;
155  };
156 
157  using const_iterator = const iterator;
158 
159  iterator begin() const
160  {
161  return iterator(*this, 0);
162  }
163 
164  iterator end() const
165  {
166  return iterator(*this, (_object->*Count)());
167  }
168 
170  {
171  return begin();
172  }
173 
175  {
176  return end();
177  }
178  };
179 
180 /*
181  * Checks if the provided second range is a rotation of the first range. Hereby it uses the predicate
182  * p for comparision the values from the two ranges
183  * If it is a rotation then it returns the rotation point of the second range
184  * If it is not a rotation or both ranges are empty then it returns the end of the second range
185  * \range1 The first range
186  * \range2 The second range
187  * \p The predicate that is used to compare two values
188  */
189  template <typename Range1, typename Range2, typename BinaryPredicate>
190  constexpr typename Range2::const_iterator is_rotated(const Range1 &range1, const Range2 &range2,
191  BinaryPredicate p)
192  {
193  if (std::size(range1) != std::size(range2))
194  {
195  return std::end(range2);
196  }
197  if (std::size(range1) == 0)
198  {
199  return std::end(range2);
200  }
201  const auto itFind2 = std::find_if(std::begin(range2), std::end(range2),
202  [p, &range1](const auto &v) { return p(*begin(range1), v); });
203 
204  if (itFind2 == std::end(range2))
205  {
206  return std::end(range2);
207  }
208  auto resultIts =
209  std::mismatch(itFind2, std::end(range2), std::begin(range1), std::end(range1), p);
210  if (resultIts.first != std::end(range2))
211  {
212  return std::end(range2);
213  }
214  resultIts = std::mismatch(std::begin(range2), itFind2, resultIts.second, std::end(range1), p);
215  if (resultIts.first != itFind2)
216  {
217  return std::end(range2);
218  }
219  return itFind2;
220  }
221 
222  /*
223  * Checks if the provided second range is a rotation of the first range
224  * If it is a rotation then it returns the rotation point of the second range
225  * If it is not a rotation or both ranges are empty then it returns the end of the second range
226  * \range1 The first range
227  * \range2 The second range
228  */
229  template <typename Range1, typename Range2>
230  constexpr typename Range2::const_iterator is_rotated(const Range1 &range1, const Range2 &range2)
231  {
232  if (std::size(range1) != std::size(range2))
233  {
234  return std::end(range2);
235  }
236  if (std::size(range1) == 0)
237  {
238  return std::end(range2);
239  }
240  const auto itFind2 = std::find(std::begin(range2), std::end(range2), *begin(range1));
241 
242  if (itFind2 == std::end(range2))
243  {
244  return std::end(range2);
245  }
246  auto resultIts = std::mismatch(itFind2, std::end(range2), std::begin(range1), std::end(range1));
247  if (resultIts.first != std::end(range2))
248  {
249  return std::end(range2);
250  }
251  resultIts = std::mismatch(std::begin(range2), itFind2, resultIts.second, std::end(range1));
252  if (resultIts.first != itFind2)
253  {
254  return std::end(range2);
255  }
256  return itFind2;
257  }
258 
259 
260 ML_UTILS_END_NAMESPACE
@ R
Definition: SoKeyGrabber.h:69
@ T
Definition: SoKeyGrabber.h:71
@ U
Definition: SoKeyGrabber.h:72
@ I
Definition: SoKeyGrabber.h:60
friend bool operator==(const iterator &x, const iterator &y)
friend bool operator!=(const iterator &x, const iterator &y)
std::bidirectional_iterator_tag iterator_category
iterator(iterator &&)=default
iterator(const iterator &)=default
iterator & operator=(iterator &&)=default
typename ContainerProxy::value_type value_type
iterator & operator=(const iterator &)=default
iterator(const ContainerProxy &proxy, I index)
This template implements a proxy for container that contain a collection of items that are normally a...
ContainerProxy(const T &object)
iterator begin() const
const_iterator cend() const
ContainerProxy & operator=(ContainerProxy &&)=default
ContainerProxy & operator=(const ContainerProxy &)=default
ContainerProxy(ContainerProxy &&)=default
const_iterator cbegin() const
ContainerProxy(const ContainerProxy &)=default
iterator end() const
T operator*(const FloatingPointVector< T, size, DataContainer > &a, const FloatingPointVector< T, size, DataContainer > &b)
Dot product, returns a.dot(b).
constexpr Range2::const_iterator is_rotated(const Range1 &range1, const Range2 &range2)
constexpr Is< T > is(T d)
In combination with the in function it returns true, if a passed values is one of a set of possible v...
constexpr bool in(Arg a, Args... args)
constexpr bool in(U a)