Akonadi

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

KDE's Doxygen guidelines are available online.