Akonadi

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

KDE's Doxygen guidelines are available online.