Akonadi

akranges.h
1 /*
2  SPDX-FileCopyrightText: 2018-2019 Daniel Vr├ítil <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "akhelpers.h"
10 #include "aktraits.h"
11 
12 #include <QMap>
13 #include <QSet>
14 #include <QVector>
15 
16 #include <algorithm>
17 #include <functional>
18 #include <iterator>
19 #include <type_traits>
20 #include <utility>
21 
22 namespace AkRanges
23 {
24 namespace detail
25 {
26 template<typename RangeLike, typename OutContainer, AK_REQUIRES(AkTraits::isAppendable<OutContainer>)> OutContainer copyContainer(const RangeLike &range)
27 {
28  OutContainer rv;
29  rv.reserve(range.size());
30  for (auto &&v : range) {
31  rv.push_back(std::move(v));
32  }
33  return rv;
34 }
35 
36 template<typename RangeLike, typename OutContainer, AK_REQUIRES(AkTraits::isInsertable<OutContainer>)> OutContainer copyContainer(const RangeLike &range)
37 {
38  OutContainer rv;
39  rv.reserve(range.size());
40  for (const auto &v : range) {
41  rv.insert(v); // Qt containers lack move-enabled insert() overload
42  }
43  return rv;
44 }
45 
46 template<typename RangeList, typename OutContainer> OutContainer copyAssocContainer(const RangeList &range)
47 {
48  OutContainer rv;
49  for (const auto &v : range) {
50  rv.insert(v.first, v.second); // Qt containers lack move-enabled insert() overload
51  }
52  return rv;
53 }
54 
55 template<typename Iterator> struct IteratorTrait {
56  using iterator_category = typename Iterator::iterator_category;
57  using value_type = typename Iterator::value_type;
58  using difference_type = typename Iterator::difference_type;
59  using pointer = typename Iterator::pointer;
60  using reference = typename Iterator::reference;
61 };
62 
63 // Without QT_STRICT_ITERATORS QVector and QList iterators do not satisfy STL
64 // iterator concepts since they are nothing more but typedefs to T* - for those
65 // we need to provide custom traits.
66 template<typename Iterator> struct IteratorTrait<Iterator *> {
67  // QTypedArrayData::iterator::iterator_category
68  using iterator_category = std::random_access_iterator_tag;
69  using value_type = Iterator;
70 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
71  using difference_type = int;
72 #else
73  using difference_type = qsizetype;
74 #endif
75  using pointer = Iterator *;
76  using reference = Iterator &;
77 };
78 
79 template<typename Iterator> struct IteratorTrait<const Iterator *> {
80  using iterator_category = std::random_access_iterator_tag;
81  using value_type = Iterator;
82 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
83  using difference_type = int;
84 #else
85  using difference_type = qsizetype;
86 #endif
87  using pointer = const Iterator *;
88  using reference = const Iterator &;
89 };
90 
91 template<typename IterImpl, typename RangeLike, typename Iterator = typename RangeLike::const_iterator> struct IteratorBase {
92 public:
93  using iterator_category = typename IteratorTrait<Iterator>::iterator_category;
94  using value_type = typename IteratorTrait<Iterator>::value_type;
95  using difference_type = typename IteratorTrait<Iterator>::difference_type;
96  using pointer = typename IteratorTrait<Iterator>::pointer;
97  using reference = typename IteratorTrait<Iterator>::reference;
98 
99  IteratorBase(const IteratorBase<IterImpl, RangeLike> &other)
100  : mIter(other.mIter)
101  , mRange(other.mRange)
102  {
103  }
104 
105  IterImpl &operator++()
106  {
107  ++static_cast<IterImpl *>(this)->mIter;
108  return *static_cast<IterImpl *>(this);
109  }
110 
111  IterImpl operator++(int)
112  {
113  auto ret = *static_cast<IterImpl *>(this);
114  ++static_cast<IterImpl *>(this)->mIter;
115  return ret;
116  }
117 
118  bool operator==(const IterImpl &other) const
119  {
120  return mIter == other.mIter;
121  }
122 
123  bool operator!=(const IterImpl &other) const
124  {
125  return !(*static_cast<const IterImpl *>(this) == other);
126  }
127 
128  bool operator<(const IterImpl &other) const
129  {
130  return mIter < other.mIter;
131  }
132 
133  auto operator-(const IterImpl &other) const
134  {
135  return mIter - other.mIter;
136  }
137 
138  auto operator*() const
139  {
140  return *mIter;
141  }
142 
143 protected:
144  IteratorBase(const Iterator &iter, const RangeLike &range)
145  : mIter(iter)
146  , mRange(range)
147  {
148  }
149  IteratorBase(const Iterator &iter, RangeLike &&range)
150  : mIter(iter)
151  , mRange(std::move(range))
152  {
153  }
154 
155  Iterator mIter;
156  RangeLike mRange;
157 };
158 
159 template<typename RangeLike, typename TransformFn, typename Iterator = typename RangeLike::const_iterator>
160 struct TransformIterator : public IteratorBase<TransformIterator<RangeLike, TransformFn>, RangeLike> {
161 private:
162  template<typename... T> struct ResultOf;
163 
164  template<typename R, typename... Args> struct ResultOf<R(Args...)> {
165  using type = R;
166  };
167 
168  template<typename... Ts> using FuncHelper = decltype(std::invoke(std::declval<Ts>()...))(Ts...);
169  using IteratorValueType = typename ResultOf<FuncHelper<TransformFn, typename IteratorTrait<Iterator>::value_type>>::type;
170 
171 public:
172  using value_type = IteratorValueType;
173  using pointer = IteratorValueType *; // FIXME: preserve const-ness
174  using reference = const IteratorValueType &; // FIXME: preserve const-ness
175 
176  TransformIterator(const Iterator &iter, const TransformFn &fn, const RangeLike &range)
177  : IteratorBase<TransformIterator<RangeLike, TransformFn>, RangeLike>(iter, range)
178  , mFn(fn)
179  {
180  }
181 
182  auto operator*() const
183  {
184  return std::invoke(mFn, *this->mIter);
185  }
186 
187 private:
188  TransformFn mFn;
189 };
190 
191 template<typename RangeLike, typename Predicate, typename Iterator = typename RangeLike::const_iterator>
192 class FilterIterator : public IteratorBase<FilterIterator<RangeLike, Predicate>, RangeLike>
193 {
194 public:
195  // Filter iterator is just an InputIterator (for complexity reasons).
196  // It actually makes it more efficient with STL algos like std::find()
197  using iterator_category = std::input_iterator_tag;
198 
199  FilterIterator(const Iterator &iter, const Iterator &end, const Predicate &predicate, const RangeLike &range)
200  : IteratorBase<FilterIterator, RangeLike>(iter, range)
201  , mPredicate(predicate)
202  , mEnd(end)
203  {
204  while (this->mIter != mEnd && !std::invoke(mPredicate, *this->mIter)) {
205  ++this->mIter;
206  }
207  }
208 
209  auto &operator++()
210  {
211  if (this->mIter != mEnd) {
212  do {
213  ++this->mIter;
214  } while (this->mIter != mEnd && !std::invoke(mPredicate, *this->mIter));
215  }
216  return *this;
217  }
218 
219  auto operator++(int)
220  {
221  auto it = *this;
222  ++(*this);
223  return it;
224  }
225 
226 private:
227  Predicate mPredicate;
228  Iterator mEnd;
229 };
230 
231 template<typename Container, int Pos, typename Iterator = typename Container::const_key_value_iterator>
232 class AssociativeContainerIterator : public IteratorBase<AssociativeContainerIterator<Container, Pos>, Container, Iterator>
233 {
234 public:
235  using value_type = std::remove_const_t<std::remove_reference_t<typename std::tuple_element<Pos, typename Iterator::value_type>::type>>;
236  using pointer = std::add_pointer_t<value_type>;
237  using reference = std::add_lvalue_reference_t<value_type>;
238 
239  AssociativeContainerIterator(const Iterator &iter, const Container &container)
240  : IteratorBase<AssociativeContainerIterator<Container, Pos>, Container, Iterator>(iter, container)
241  {
242  }
243 
244  auto operator*() const
245  {
246  return std::get<Pos>(*this->mIter);
247  }
248 };
249 
250 template<typename Container> using AssociativeContainerKeyIterator = AssociativeContainerIterator<Container, 0>;
251 template<typename Container> using AssociativeContainerValueIterator = AssociativeContainerIterator<Container, 1>;
252 
253 template<typename Iterator> struct Range {
254 public:
255  using iterator = Iterator;
256  using const_iterator = Iterator;
257  using value_type = typename detail::IteratorTrait<Iterator>::value_type;
258 
259  Range(Iterator &&begin, Iterator &&end)
260  : mBegin(std::move(begin))
261  , mEnd(std::move(end))
262  {
263  }
264 
265  Iterator begin() const
266  {
267  return mBegin;
268  }
269 
270  Iterator cbegin() const
271  {
272  return mBegin;
273  }
274 
275  Iterator end() const
276  {
277  return mEnd;
278  }
279 
280  Iterator cend() const
281  {
282  return mEnd;
283  }
284 
285  auto size() const
286  {
287  return std::distance(mBegin, mEnd);
288  }
289 
290 private:
291  Iterator mBegin;
292  Iterator mEnd;
293 };
294 
295 template<typename T> using IsRange = typename std::is_same<T, Range<typename T::iterator>>;
296 
297 // Tags
298 
299 template<template<typename> class Cont> struct ToTag_ {
300  template<typename T> using OutputContainer = Cont<T>;
301 };
302 
303 template<template<typename, typename> class Cont> struct ToAssocTag_ {
304  template<typename Key, typename Value> using OuputContainer = Cont<Key, Value>;
305 };
306 
307 struct ValuesTag_ {
308 };
309 struct KeysTag_ {
310 };
311 
312 template<typename UnaryOperation> struct TransformTag_ {
313  UnaryOperation mFn;
314 };
315 
316 template<typename UnaryPredicate> struct FilterTag_ {
317  UnaryPredicate mFn;
318 };
319 
320 template<typename UnaryOperation> struct ForEachTag_ {
321  UnaryOperation mFn;
322 };
323 
324 template<typename UnaryPredicate> struct AllTag_ {
325  UnaryPredicate mFn;
326 };
327 
328 template<typename UnaryPredicate> struct AnyTag_ {
329  UnaryPredicate mFn;
330 };
331 
332 template<typename UnaryPredicate> struct NoneTag_ {
333  UnaryPredicate mFn;
334 };
335 
336 } // namespace detail
337 } // namespace AkRanges
338 
339 // Generic operator| for To_<> converter
340 template<typename RangeLike, template<typename> class OutContainer, typename T = typename RangeLike::value_type>
341 auto operator|(const RangeLike &range, AkRanges::detail::ToTag_<OutContainer>) -> OutContainer<T>
342 {
343  using namespace AkRanges::detail;
344  return copyContainer<RangeLike, OutContainer<T>>(range);
345 }
346 
347 // Specialization for case when InContainer and OutContainer are identical
348 // Create a copy, but for Qt container this is very cheap due to implicit sharing.
349 template<template<typename> class InContainer, typename T> auto operator|(const InContainer<T> &in, AkRanges::detail::ToTag_<InContainer>) -> InContainer<T>
350 {
351  return in;
352 }
353 
354 // Generic operator| for ToAssoc_<> converter
355 template<typename RangeLike, template<typename, typename> class OutContainer, typename T = typename RangeLike::value_type>
356 auto operator|(const RangeLike &range, AkRanges::detail::ToAssocTag_<OutContainer>) -> OutContainer<typename T::first_type, typename T::second_type>
357 {
358  using namespace AkRanges::detail;
359  return copyAssocContainer<RangeLike, OutContainer<typename T::first_type, typename T::second_type>>(range);
360 }
361 
362 // Generic operator| for transform()
363 template<typename RangeLike, typename UnaryOperation> auto operator|(const RangeLike &range, AkRanges::detail::TransformTag_<UnaryOperation> t)
364 {
365  using namespace AkRanges::detail;
366  using OutIt = TransformIterator<RangeLike, UnaryOperation>;
367  return Range<OutIt>(OutIt(std::cbegin(range), t.mFn, range), OutIt(std::cend(range), t.mFn, range));
368 }
369 
370 // Generic operator| for filter()
371 template<typename RangeLike, typename UnaryPredicate> auto operator|(const RangeLike &range, AkRanges::detail::FilterTag_<UnaryPredicate> p)
372 {
373  using namespace AkRanges::detail;
374  using OutIt = FilterIterator<RangeLike, UnaryPredicate>;
375  return Range<OutIt>(OutIt(std::cbegin(range), std::cend(range), p.mFn, range), OutIt(std::cend(range), std::cend(range), p.mFn, range));
376 }
377 
378 // Generic operator| for foreach()
379 template<typename RangeLike, typename UnaryOperation> auto operator|(const RangeLike &range, AkRanges::detail::ForEachTag_<UnaryOperation> op)
380 {
381  std::for_each(std::cbegin(range), std::cend(range), [op = std::move(op)](const auto &val) mutable {
382  std::invoke(op.mFn, val);
383  });
384  return range;
385 }
386 
387 // Generic operator| for all
388 template<typename RangeLike, typename UnaryPredicate> auto operator|(const RangeLike &range, AkRanges::detail::AllTag_<UnaryPredicate> p)
389 {
390  return std::all_of(std::cbegin(range), std::cend(range), p.mFn);
391 }
392 
393 // Generic operator| for any
394 template<typename RangeLike, typename PredicateFn> auto operator|(const RangeLike &range, AkRanges::detail::AnyTag_<PredicateFn> p)
395 {
396  return std::any_of(std::cbegin(range), std::cend(range), p.mFn);
397 }
398 
399 // Generic operator| for none
400 template<typename RangeLike, typename UnaryPredicate> auto operator|(const RangeLike &range, AkRanges::detail::NoneTag_<UnaryPredicate> p)
401 {
402  return std::none_of(std::cbegin(range), std::cend(range), p.mFn);
403 }
404 
405 // Generic operator| for keys
406 template<typename AssocContainer> auto operator|(const AssocContainer &in, AkRanges::detail::KeysTag_)
407 {
408  using namespace AkRanges::detail;
409  using OutIt = AssociativeContainerKeyIterator<AssocContainer>;
410  return Range<OutIt>(OutIt(in.constKeyValueBegin(), in), OutIt(in.constKeyValueEnd(), in));
411 }
412 
413 // Generic operator| for values
414 template<typename AssocContainer> auto operator|(const AssocContainer &in, AkRanges::detail::ValuesTag_)
415 {
416  using namespace AkRanges::detail;
417  using OutIt = AssociativeContainerValueIterator<AssocContainer>;
418  return Range<OutIt>(OutIt(in.constKeyValueBegin(), in), OutIt(in.constKeyValueEnd(), in));
419 }
420 
421 namespace AkRanges
422 {
423 namespace Actions
424 {
425 /// Non-lazily convert given range or container to QVector
426 static constexpr auto toQVector = detail::ToTag_<QVector>{};
427 /// Non-lazily convert given range or container to QSet
428 static constexpr auto toQSet = detail::ToTag_<QSet>{};
429 /// Non-lazily convert given range or container to QList
430 static constexpr auto toQList = detail::ToTag_<QList>{};
431 /// Non-lazily convert given range or container of pairs to QMap
432 static constexpr auto toQMap = detail::ToAssocTag_<QMap>{};
433 /// Non-lazily convert given range or container of pairs to QHash
434 static constexpr auto toQHash = detail::ToAssocTag_<QHash>{};
435 
436 /// Non-lazily call UnaryOperation for each element of the container or range
437 template<typename UnaryOperation> detail::ForEachTag_<UnaryOperation> forEach(UnaryOperation &&op)
438 {
439  return detail::ForEachTag_<UnaryOperation>{std::forward<UnaryOperation>(op)};
440 }
441 
442 /// Non-lazily check that all elements in the range satisfy given predicate
443 template<typename UnaryPredicate> detail::AllTag_<UnaryPredicate> all(UnaryPredicate &&pred)
444 {
445  return detail::AllTag_<UnaryPredicate>{std::forward<UnaryPredicate>(pred)};
446 }
447 
448 /// Non-lazily check that at least one element in range satisfies the given predicate
449 template<typename UnaryPredicate> detail::AnyTag_<UnaryPredicate> any(UnaryPredicate &&pred)
450 {
451  return detail::AnyTag_<UnaryPredicate>{std::forward<UnaryPredicate>(pred)};
452 }
453 
454 /// Non-lazily check that none of the elements in the range satisfies the given predicate
455 template<typename UnaryPredicate> detail::NoneTag_<UnaryPredicate> none(UnaryPredicate &&pred)
456 {
457  return detail::NoneTag_<UnaryPredicate>{std::forward<UnaryPredicate>(pred)};
458 }
459 
460 } // namespace Action
461 
462 namespace Views
463 {
464 /// Lazily extract values from an associative container
465 static constexpr auto values = detail::ValuesTag_{};
466 /// Lazily extract keys from an associative container
467 static constexpr auto keys = detail::KeysTag_{};
468 
469 /// Lazily transform each element of a range or container using given transformation
470 template<typename UnaryOperation> detail::TransformTag_<UnaryOperation> transform(UnaryOperation &&op)
471 {
472  return detail::TransformTag_<UnaryOperation>{std::forward<UnaryOperation>(op)};
473 }
474 
475 /// Lazily filters a range or container by applying given predicate on each element
476 template<typename UnaryPredicate> detail::FilterTag_<UnaryPredicate> filter(UnaryPredicate &&pred)
477 {
478  return detail::FilterTag_<UnaryPredicate>{std::forward<UnaryPredicate>(pred)};
479 }
480 
481 /// Create a range, a view on a container from the given pair fo iterators
482 template<typename Iterator1, typename Iterator2, typename It = std::remove_reference_t<Iterator1>> detail::Range<It> range(Iterator1 begin, Iterator2 end)
483 {
484  return detail::Range<It>(std::move(begin), std::move(end));
485 }
486 
487 } // namespace View
488 
489 } // namespace AkRanges
490 
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QVector< const char * > &params=QVector< const char * >())
const QList< QKeySequence > & begin()
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
bool operator!=(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
QFuture< void > filter(Sequence &sequence, KeepFunctor filterFunction)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT CopyJob * move(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
A glue between Qt and the standard library.
const QList< QKeySequence > & end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:45 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.