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

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