1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QTCORE_RESULTSTORE_H
5#define QTCORE_RESULTSTORE_H
6
7#include <QtCore/qmap.h>
8
9#include <utility>
10
11QT_REQUIRE_CONFIG(future);
12
13QT_BEGIN_NAMESPACE
14
15/*
16 ResultStore stores indexed results. Results can be added and retrieved
17 either individually batched in a QList. Retriveing results and checking
18 which indexes are in the store can be done either by iterating or by random
19 access. In addition results can be removed from the front of the store,
20 either individually or in batches.
21*/
22
23namespace QtPrivate {
24
25class ResultItem
26{
27public:
28 ResultItem(const void *_result, int _count) : m_count(_count), result(_result) { } // construct with vector of results
29 ResultItem(const void *_result) : m_count(0), result(_result) { } // construct with result
30 ResultItem() : m_count(0), result(nullptr) { }
31 bool isValid() const { return result != nullptr; }
32 bool isVector() const { return m_count != 0; }
33 int count() const { return (m_count == 0) ? 1 : m_count; }
34 int m_count; // result is either a pointer to a result or to a vector of results,
35 const void *result; // if count is 0 it's a result, otherwise it's a vector.
36};
37
38class Q_CORE_EXPORT ResultIteratorBase
39{
40public:
41 ResultIteratorBase();
42 ResultIteratorBase(QMap<int, ResultItem>::const_iterator _mapIterator, int _vectorIndex = 0);
43 int vectorIndex() const;
44 int resultIndex() const;
45
46 ResultIteratorBase operator++();
47 int batchSize() const;
48 void batchedAdvance();
49 bool operator==(const ResultIteratorBase &other) const;
50 bool operator!=(const ResultIteratorBase &other) const;
51 bool isVector() const;
52 bool canIncrementVectorIndex() const;
53 bool isValid() const;
54
55protected:
56 QMap<int, ResultItem>::const_iterator mapIterator;
57 int m_vectorIndex;
58public:
59 template <typename T>
60 const T &value() const
61 {
62 return *pointer<T>();
63 }
64
65 template<typename T>
66 T &value()
67 {
68 return *pointer<T>();
69 }
70
71 template <typename T>
72 T *pointer()
73 {
74 const T *p = std::as_const(t&: *this).pointer<T>();
75 return const_cast<T *>(p);
76 }
77
78 template <typename T>
79 const T *pointer() const
80 {
81 if (mapIterator.value().isVector())
82 return &(reinterpret_cast<const QList<T> *>(mapIterator.value().result)->at(m_vectorIndex));
83 else
84 return reinterpret_cast<const T *>(mapIterator.value().result);
85 }
86};
87
88class Q_CORE_EXPORT ResultStoreBase final
89{
90public:
91 ResultStoreBase();
92 void setFilterMode(bool enable);
93 bool filterMode() const;
94 int addResult(int index, const void *result);
95 int addResults(int index, const void *results, int vectorSize, int logicalCount);
96 ResultIteratorBase begin() const;
97 ResultIteratorBase end() const;
98 bool hasNextResult() const;
99 ResultIteratorBase resultAt(int index) const;
100 bool contains(int index) const;
101 int count() const;
102 // ### Qt 7: 'virtual' isn't required, can be removed, along with renaming
103 // the class to ResultStore and changing the members below to be private.
104 virtual ~ResultStoreBase();
105
106protected:
107 int insertResultItem(int index, ResultItem &resultItem);
108 void insertResultItemIfValid(int index, ResultItem &resultItem);
109 bool containsValidResultItem(int index) const;
110 void syncPendingResults();
111 void syncResultCount();
112 int updateInsertIndex(int index, int _count);
113
114 QMap<int, ResultItem> m_results;
115 int insertIndex; // The index where the next results(s) will be inserted.
116 int resultCount; // The number of consecutive results stored, starting at index 0.
117
118 bool m_filterMode;
119 QMap<int, ResultItem> pendingResults;
120 int filteredResults;
121
122 template <typename T>
123 static void clear(QMap<int, ResultItem> &store)
124 {
125 QMap<int, ResultItem>::const_iterator mapIterator = store.constBegin();
126 while (mapIterator != store.constEnd()) {
127 if (mapIterator.value().isVector())
128 delete reinterpret_cast<const QList<T> *>(mapIterator.value().result);
129 else
130 delete reinterpret_cast<const T *>(mapIterator.value().result);
131 ++mapIterator;
132 }
133 store.clear();
134 }
135
136public:
137 template <typename T, typename...Args>
138 int emplaceResult(int index, Args&&...args)
139 {
140 if (containsValidResultItem(index)) // reject if already present
141 return -1;
142 return addResult(index, result: static_cast<void *>(new T(std::forward<Args>(args)...)));
143 }
144
145 template <typename T>
146 int addResult(int index, const T *result)
147 {
148 if (containsValidResultItem(index)) // reject if already present
149 return -1;
150
151 if (result == nullptr)
152 return addResult(index, result: static_cast<void *>(nullptr));
153
154 return addResult(index, result: static_cast<void *>(new T(*result)));
155 }
156
157 template <typename T>
158 int moveResult(int index, T &&result)
159 {
160 static_assert(!std::is_reference_v<T>, "trying to move from an lvalue!");
161
162 return emplaceResult<std::remove_cv_t<T>>(index, std::forward<T>(result));
163 }
164
165 template<typename T>
166 int addResults(int index, const QList<T> *results)
167 {
168 if (results->empty()) // reject if results are empty
169 return -1;
170
171 if (containsValidResultItem(index)) // reject if already present
172 return -1;
173
174 return addResults(index, new QList<T>(*results), results->size(), results->size());
175 }
176
177 template<typename T>
178 int addResults(int index, const QList<T> *results, int totalCount)
179 {
180 // reject if results are empty, and nothing is filtered away
181 if ((m_filterMode == false || results->size() == totalCount) && results->empty())
182 return -1;
183
184 if (containsValidResultItem(index)) // reject if already present
185 return -1;
186
187 if (m_filterMode == true && results->size() != totalCount && 0 == results->size())
188 return addResults(index, results: nullptr, vectorSize: 0, logicalCount: totalCount);
189
190 return addResults(index, new QList<T>(*results), results->size(), totalCount);
191 }
192
193 int addCanceledResult(int index)
194 {
195 if (containsValidResultItem(index)) // reject if already present
196 return -1;
197
198 return addResult(index, result: static_cast<void *>(nullptr));
199 }
200
201 template <typename T>
202 int addCanceledResults(int index, int _count)
203 {
204 if (containsValidResultItem(index)) // reject if already present
205 return -1;
206
207 QList<T> empty;
208 return addResults(index, &empty, _count);
209 }
210
211 template <typename T>
212 void clear()
213 {
214 ResultStoreBase::clear<T>(m_results);
215 resultCount = 0;
216 insertIndex = 0;
217 ResultStoreBase::clear<T>(pendingResults);
218 filteredResults = 0;
219 }
220};
221
222} // namespace QtPrivate
223
224Q_DECLARE_TYPEINFO(QtPrivate::ResultItem, Q_PRIMITIVE_TYPE);
225
226
227QT_END_NAMESPACE
228
229#endif
230

source code of qtbase/src/corelib/thread/qresultstore.h