swift
range.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #ifndef SWIFT_MISC_RANGE_H
7 #define SWIFT_MISC_RANGE_H
8 
9 #include <algorithm>
10 #include <iterator>
11 #include <type_traits>
12 
13 #include <QDebug>
14 #include <QtGlobal>
15 
16 #include "misc/algorithm.h"
17 #include "misc/iterator.h"
18 #include "misc/predicates.h"
19 #include "misc/typetraits.h"
20 
21 namespace swift::misc
22 {
23  template <class>
24  class CRange;
25 
31  template <class Derived>
32  class CRangeBase
33  {
34  public:
36  template <class F>
37  inline auto transform(F function) const;
38 
40  template <class Predicate>
41  inline auto findBy(Predicate p) const;
42 
48  template <class K0, class V0, class... KeysValues>
49  inline auto findBy(K0 k0, V0 v0, KeysValues... keysValues) const;
50 
53  template <class Predicate>
54  const auto &findFirstBy(Predicate p) const
55  {
56  return findBy(p).front();
57  }
58 
61  template <class K, class V>
62  const auto &findFirstBy(K key, V value) const
63  {
64  return findBy(key, value).front();
65  }
66 
69  template <class Predicate, class Value>
70  auto findFirstByOrDefault(Predicate p, const Value &def) const
71  {
72  return findBy(p).frontOrDefault(def);
73  }
74 
77  template <class Predicate>
78  auto findFirstByOrDefault(Predicate p) const
79  {
80  return findBy(p).frontOrDefault();
81  }
82 
85  template <class K, class V, class Value>
86  auto findFirstByOrDefault(K key, V value, const Value &def) const
87  {
88  return findBy(key, value).frontOrDefault(def);
89  }
90 
93  template <class T, class K, class V>
94  auto findFirstByOrDefault(K T::*key, V value) const
95  {
96  return findBy(key, value).frontOrDefault();
97  }
98 
100  template <class Predicate>
101  bool containsBy(Predicate p) const
102  {
103  return std::any_of(derived().cbegin(), derived().cend(), p);
104  }
105 
108  template <class T>
109  bool contains(const T &object) const
110  {
111  return derived().find(object) != derived().cend();
112  }
113 
119  template <class K0, class V0, class... KeysValues>
120  bool contains(K0 k0, V0 v0, KeysValues... keysValues) const
121  {
122  return containsBy(swift::misc::predicates::MemberEqual(k0, v0, keysValues...));
123  }
124 
126  template <class T, class Predicate>
127  bool equalsBy(const T &other, Predicate c) const
128  {
129  if (equalPointers(&derived(), &other)) { return true; }
130  return std::equal(derived().begin(), derived().end(), other.begin(), other.end(), c);
131  }
132 
134  template <class T, class Key0, class... Keys>
135  bool equalsByKeys(const T &other, Key0 k0, Keys... keys) const
136  {
137  return equalsBy(other, swift::misc::predicates::EqualsByMembers(k0, keys...));
138  }
139 
141  template <class T>
142  T randomElement() const
143  {
144  return this->randomElements(1).front();
145  }
146 
148  Derived randomElements(int n) const
149  {
150  Derived result;
151  swift::misc::copyRandomElements(derived().begin(), derived().end(), std::inserter(result, result.end()), n);
152  return result;
153  }
154 
156  Derived sampleElements(int n) const
157  {
158  Derived result;
159  swift::misc::copySampleElements(derived().begin(), derived().end(), std::inserter(result, result.end()), n);
160  return result;
161  }
162 
163  protected:
165  template <typename T, typename U>
166  static bool equalPointers(const T *a, const U *b)
167  {
168  if constexpr (TIsEqualityComparable<const T *, const U *>::value) { return a == b; }
169  else { return false; }
170  }
171 
172  private:
173  Derived &derived() { return static_cast<Derived &>(*this); }
174  const Derived &derived() const { return static_cast<const Derived &>(*this); }
175  };
176 
188  template <class I>
189  class CRange : public CRangeBase<CRange<I>>
190  {
191  public:
194  typedef typename std::iterator_traits<I>::value_type value_type;
195  typedef typename std::iterator_traits<I>::reference reference;
196  typedef typename std::iterator_traits<I>::difference_type difference_type;
197  typedef const value_type &const_reference;
200  typedef I iterator;
201  typedef I const_iterator;
202  typedef std::reverse_iterator<I> reverse_iterator;
203  typedef std::reverse_iterator<I> const_reverse_iterator;
205 
207  CRange(I begin, I end) : m_begin(begin), m_end(end) { check(&begin, &end); }
208 
211  const_iterator begin() const { return m_begin; }
212  const_iterator cbegin() const { return m_begin; }
213  const_iterator end() const { return m_end; }
214  const_iterator cend() const { return m_end; }
216 
224 
227  {
228  static_assert(std::is_same_v<decltype(*rbegin()), decltype(*begin())>, "");
229  return { rbegin(), rend() };
230  }
231 
233  template <class T, class = std::enable_if_t<std::is_convertible_v<value_type, typename T::value_type>>>
234  operator T() const
235  {
236  return to<T>();
237  }
238 
241  template <class T>
242  T to() const
243  {
244  T container;
245  std::copy(begin(), end(), Iterators::makeInsertIterator(container));
246  return container;
247  }
248  template <template <class...> class T>
249  auto to() const
250  {
251  return to<T<value_type>>();
252  }
254 
257  bool empty() const { return begin() == end(); }
258  bool isEmpty() const { return empty(); }
260 
262  size_type size() const { return std::distance(begin(), end()); }
263 
266  {
267  Q_ASSERT(!empty());
268  return *begin();
269  }
270 
273  {
274  static const value_type def {};
275  return empty() ? def : *begin();
276  }
277 
279  value_type frontOrDefault(value_type def) const { return empty() ? def : *begin(); }
280 
281  private:
282  I m_begin;
283  I m_end;
284 
285  void check(...) {}
286  template <class I2, class F>
287  void check(Iterators::ConditionalIterator<I2, F> *begin, Iterators::ConditionalIterator<I2, F> *end)
288  {
289  begin->checkEnd(*end);
290  }
291  };
292 
294 
297  template <class I>
298  QDebug operator<<(QDebug d, const CRange<I> &range)
299  {
300  for (const auto &v : range) { d << v; }
301  return d;
302  }
303  template <class I>
304  QNoDebug operator<<(QNoDebug d, const CRange<I> &)
305  {
306  return d;
307  }
309 
315  template <class I, class I2>
316  auto makeRange(I begin, I2 end) -> CRange<I>
317  {
318  return { begin, static_cast<I>(end) };
319  }
320 
322 
325  template <class T>
326  auto makeRange(T &container) -> CRange<decltype(container.begin())>
327  {
328  return { container.begin(), container.end() };
329  }
330  template <class T>
331  auto makeRange(const T &container) -> CRange<decltype(container.begin())>
332  {
333  return { container.begin(), container.end() };
334  }
336 
340  template <class T>
341  auto makeConstRange(const T &container) -> CRange<decltype(container.cbegin())>
342  {
343  return { container.cbegin(), container.cend() };
344  }
345 
347 
352  template <class T>
353  auto makeKeysRange(const T &container)
354  {
355  return makeRange(container.keyBegin(), container.keyEnd());
356  }
357  template <class T>
358  void makeKeysRange(T &container)
359  {
360  container.detach(); // http://doc.qt.io/qt-5/containers.html#implicit-sharing-iterator-problem
361  return makeRange(container.keyValueBegin(), container.keyValueEnd());
362  }
364 
366 
373  template <class T>
374  auto makePairsRange(const T &container)
375  {
376  return makeRange(container.keyValueBegin(), container.keyValueEnd());
377  }
378  template <class T>
379  auto makePairsRange(T &container)
380  {
381  container.detach(); // http://doc.qt.io/qt-5/containers.html#implicit-sharing-iterator-problem
382  return makeRange(container.keyValueBegin(), container.keyValueEnd());
383  }
385 
389  template <class T>
390  void makeKeysRange(const T &&container) = delete;
391 
395  template <class T>
396  void makePairsRange(const T &&container) = delete;
397 
398  /*
399  * Member functions of CRangeBase template defined out of line, because they depend on CRange etc.
400  */
401  template <class Derived>
402  template <class F>
403  auto CRangeBase<Derived>::transform(F function) const
404  {
405  return makeRange(Iterators::makeTransformIterator(derived().cbegin(), function), derived().cend());
406  }
407 
408  template <class Derived>
409  template <class Predicate>
410  auto CRangeBase<Derived>::findBy(Predicate p) const
411  {
412  return makeRange(Iterators::makeConditionalIterator(derived().cbegin(), derived().cend(), p), derived().cend());
413  }
414 
415  template <class Derived>
416  template <class K0, class V0, class... KeysValues>
417  auto CRangeBase<Derived>::findBy(K0 k0, V0 v0, KeysValues... keysValues) const
418  {
419  return findBy(swift::misc::predicates::MemberEqual(k0, v0, keysValues...));
420  }
421 
422 } // namespace swift::misc
423 
424 #endif // SWIFT_MISC_RANGE_H
Any container class with begin and end iterators can inherit from this CRTP class to gain some useful...
Definition: range.h:33
Derived sampleElements(int n) const
Copy n elements from the container, randomly selected but evenly distributed.
Definition: range.h:156
bool equalsByKeys(const T &other, Key0 k0, Keys... keys) const
Return true if this container equals another container, considering only the given element members.
Definition: range.h:135
auto findFirstByOrDefault(Predicate p) const
Return a copy of the first element for which a given predicate returns true, or a default value if th...
Definition: range.h:78
Derived randomElements(int n) const
Copy n elements from the container at random.
Definition: range.h:148
bool equalsBy(const T &other, Predicate c) const
Return true if this container equals another container according to the given element equality predic...
Definition: range.h:127
auto findFirstByOrDefault(K key, V value, const Value &def) const
Return a copy of the first element matching some particular key/value pair(s), or a default value if ...
Definition: range.h:86
auto findBy(Predicate p) const
Return a copy containing only those elements for which a given predicate returns true.
Definition: range.h:410
static bool equalPointers(const T *a, const U *b)
Efficiently compare addresses of two objects. Return false if types are not compatible.
Definition: range.h:166
auto findFirstByOrDefault(K T::*key, V value) const
Return a copy of the first element matching some particular key/value pair(s), or a default value if ...
Definition: range.h:94
auto findFirstByOrDefault(Predicate p, const Value &def) const
Return a copy of the first element for which a given predicate returns true, or a default value if th...
Definition: range.h:70
bool containsBy(Predicate p) const
Return true if there is an element for which a given predicate returns true.
Definition: range.h:101
const auto & findFirstBy(Predicate p) const
Return a reference to the first element for which a given predicate returns true. Undefined if there ...
Definition: range.h:54
T randomElement() const
Pick one random element.
Definition: range.h:142
bool contains(K0 k0, V0 v0, KeysValues... keysValues) const
Return a copy containing only those elements matching some particular key/value pair(s).
Definition: range.h:120
const auto & findFirstBy(K key, V value) const
Return a reference to the first element matching some particular key/value pair(s)....
Definition: range.h:62
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
Definition: range.h:109
auto transform(F function) const
Return a new container generated by applying some transformation function to all elements of this one...
Definition: range.h:403
auto findBy(K0 k0, V0 v0, KeysValues... keysValues) const
Return a copy containing only those elements matching some particular key/value pair(s).
Definition: range.h:417
A range is a conceptual container which does not contain any elements of its own, but is constructed ...
Definition: range.h:190
value_type frontOrDefault(value_type def) const
Returns the element at the beginning of the range, or a default value if the range is empty.
Definition: range.h:279
std::iterator_traits< I >::value_type value_type
STL compatibility.
Definition: range.h:194
std::reverse_iterator< I > const_reverse_iterator
STL compatibility.
Definition: range.h:203
const_iterator cbegin() const
Begin and end iterators.
Definition: range.h:212
I iterator
STL compatibility.
Definition: range.h:200
CRange< const_reverse_iterator > reverse() const
Create a range from reverse iterators.
Definition: range.h:226
CRange(I begin, I end)
Constructor.
Definition: range.h:207
const_reverse_iterator crbegin() const
Reverse begin and end iterators.
Definition: range.h:220
const_reverse_iterator crend() const
Reverse begin and end iterators.
Definition: range.h:222
I const_iterator
STL compatibility.
Definition: range.h:201
std::reverse_iterator< I > reverse_iterator
STL compatibility.
Definition: range.h:202
difference_type size_type
STL compatibility.
Definition: range.h:199
size_type size() const
Returns the number of elements in the range.
Definition: range.h:262
T to() const
Explicit conversion to any container of value_type which supports push_back. This will copy elements.
Definition: range.h:242
auto to() const
Explicit conversion to any container of value_type which supports push_back. This will copy elements.
Definition: range.h:249
bool empty() const
Returns true if the range is empty.
Definition: range.h:257
const_iterator end() const
Begin and end iterators.
Definition: range.h:213
const_iterator begin() const
Begin and end iterators.
Definition: range.h:211
value_type key_type
STL compatibility.
Definition: range.h:198
const_reverse_iterator rend() const
Reverse begin and end iterators.
Definition: range.h:221
std::iterator_traits< I >::reference reference
STL compatibility.
Definition: range.h:195
bool isEmpty() const
Returns true if the range is empty.
Definition: range.h:258
const_reverse_iterator rbegin() const
Reverse begin and end iterators.
Definition: range.h:219
std::iterator_traits< I >::difference_type difference_type
STL compatibility.
Definition: range.h:196
const value_type & const_reference
STL compatibility.
Definition: range.h:197
const_reference frontOrDefault() const
Returns the element at the beginning of the range, or a default value if the range is empty.
Definition: range.h:272
const_reference front() const
Returns the element at the beginning of the range. Undefined if the range is empty.
Definition: range.h:265
const_iterator cend() const
Begin and end iterators.
Definition: range.h:214
auto makeTransformIterator(I iterator, F function) -> TransformIterator< I, F >
Construct a TransformIterator of the appropriate type from deduced template function arguments.
Definition: iterator.h:343
auto makeInsertIterator(T &container)
Return an insert iterator appropriate to the container type (uses push_back or insert).
Definition: iterator.h:88
auto makeConditionalIterator(I iterator, I end, F predicate) -> ConditionalIterator< I, F >
Construct a ConditionalIterator of the appropriate type from deduced template function arguments.
Definition: iterator.h:352
auto EqualsByMembers(Ts... vs)
Returns a predicate that returns true if its arguments compare equal to each other,...
Definition: predicates.h:96
auto MemberEqual(Ts... vs)
Predicate which tests whether some member functions return some values.
Definition: predicates.h:26
Free functions in swift::misc.
T::const_iterator begin(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:332
auto makeKeysRange(const T &container)
Returns a const CRange for iterating over the keys of a Qt associative container.
Definition: range.h:353
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
Definition: range.h:316
auto makeConstRange(const T &container) -> CRange< decltype(container.cbegin())>
Returns a const CRange constructed from the cbegin and cend iterators of the given container.
Definition: range.h:341
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:338
QDebug operator<<(QDebug d, const CRange< I > &range)
Streaming operators for CRange to qDebug.
Definition: range.h:298
void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
Split the range [in,end) into n equal chunks and use the random number generator rng to choose one el...
Definition: algorithm.h:80
void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
Use the random number generator rng to choose n elements from the range [in,end) and copy them to out...
Definition: algorithm.h:54
auto makePairsRange(const T &container)
Returns a const CRange for iterating over the keys and values of a Qt associative container.
Definition: range.h:374
Trait which is true if the expression a == b is valid when a and b are instances of T and U.
Definition: typetraits.h:164