1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QTCORE_RESULTSTORE_H
41#define QTCORE_RESULTSTORE_H
42
43#include <QtCore/qmap.h>
44#include <QtCore/qdebug.h>
45
46#include <utility>
47
48QT_REQUIRE_CONFIG(future);
49
50QT_BEGIN_NAMESPACE
51
52/*
53 ResultStore stores indexed results. Results can be added and retrieved
54 either individually batched in a QList. Retriveing results and checking
55 which indexes are in the store can be done either by iterating or by random
56 accees. In addition results kan be removed from the front of the store,
57 either individually or in batches.
58*/
59
60namespace QtPrivate {
61
62class ResultItem
63{
64public:
65 ResultItem(const void *_result, int _count) : m_count(_count), result(_result) { } // contruct with vector of results
66 ResultItem(const void *_result) : m_count(0), result(_result) { } // construct with result
67 ResultItem() : m_count(0), result(nullptr) { }
68 bool isValid() const { return result != nullptr; }
69 bool isVector() const { return m_count != 0; }
70 int count() const { return (m_count == 0) ? 1 : m_count; }
71 int m_count; // result is either a pointer to a result or to a vector of results,
72 const void *result; // if count is 0 it's a result, otherwise it's a vector.
73};
74
75class Q_CORE_EXPORT ResultIteratorBase
76{
77public:
78 ResultIteratorBase();
79 ResultIteratorBase(QMap<int, ResultItem>::const_iterator _mapIterator, int _vectorIndex = 0);
80 int vectorIndex() const;
81 int resultIndex() const;
82
83 ResultIteratorBase operator++();
84 int batchSize() const;
85 void batchedAdvance();
86 bool operator==(const ResultIteratorBase &other) const;
87 bool operator!=(const ResultIteratorBase &other) const;
88 bool isVector() const;
89 bool canIncrementVectorIndex() const;
90 bool isValid() const;
91
92protected:
93 QMap<int, ResultItem>::const_iterator mapIterator;
94 int m_vectorIndex;
95public:
96 template <typename T>
97 const T &value() const
98 {
99 return *pointer<T>();
100 }
101
102 template<typename T>
103 T &value()
104 {
105 return *pointer<T>();
106 }
107
108 template <typename T>
109 T *pointer()
110 {
111 const T *p = qAsConst(*this).pointer<T>();
112 return const_cast<T *>(p);
113 }
114
115 template <typename T>
116 const T *pointer() const
117 {
118 if (mapIterator.value().isVector())
119 return &(reinterpret_cast<const QList<T> *>(mapIterator.value().result)->at(m_vectorIndex));
120 else
121 return reinterpret_cast<const T *>(mapIterator.value().result);
122 }
123};
124
125class Q_CORE_EXPORT ResultStoreBase
126{
127public:
128 ResultStoreBase();
129 void setFilterMode(bool enable);
130 bool filterMode() const;
131 int addResult(int index, const void *result);
132 int addResults(int index, const void *results, int vectorSize, int logicalCount);
133 ResultIteratorBase begin() const;
134 ResultIteratorBase end() const;
135 bool hasNextResult() const;
136 ResultIteratorBase resultAt(int index) const;
137 bool contains(int index) const;
138 int count() const;
139 virtual ~ResultStoreBase();
140
141protected:
142 int insertResultItem(int index, ResultItem &resultItem);
143 void insertResultItemIfValid(int index, ResultItem &resultItem);
144 bool containsValidResultItem(int index) const;
145 void syncPendingResults();
146 void syncResultCount();
147 int updateInsertIndex(int index, int _count);
148
149 QMap<int, ResultItem> m_results;
150 int insertIndex; // The index where the next results(s) will be inserted.
151 int resultCount; // The number of consecutive results stored, starting at index 0.
152
153 bool m_filterMode;
154 QMap<int, ResultItem> pendingResults;
155 int filteredResults;
156
157 template <typename T>
158 static void clear(QMap<int, ResultItem> &store)
159 {
160 QMap<int, ResultItem>::const_iterator mapIterator = store.constBegin();
161 while (mapIterator != store.constEnd()) {
162 if (mapIterator.value().isVector())
163 delete reinterpret_cast<const QList<T> *>(mapIterator.value().result);
164 else
165 delete reinterpret_cast<const T *>(mapIterator.value().result);
166 ++mapIterator;
167 }
168 store.clear();
169 }
170
171public:
172 template <typename T>
173 int addResult(int index, const T *result)
174 {
175 if (containsValidResultItem(index)) // reject if already present
176 return -1;
177
178 if (result == nullptr)
179 return addResult(index, static_cast<void *>(nullptr));
180
181 return addResult(index, static_cast<void *>(new T(*result)));
182 }
183
184 template <typename T>
185 int moveResult(int index, T &&result)
186 {
187 if (containsValidResultItem(index)) // reject if already present
188 return -1;
189
190 return addResult(index, static_cast<void *>(new T(std::move_if_noexcept(result))));
191 }
192
193 template<typename T>
194 int addResults(int index, const QList<T> *results)
195 {
196 if (containsValidResultItem(index)) // reject if already present
197 return -1;
198
199 return addResults(index, new QList<T>(*results), results->count(), results->count());
200 }
201
202 template<typename T>
203 int addResults(int index, const QList<T> *results, int totalCount)
204 {
205 if (containsValidResultItem(index)) // reject if already present
206 return -1;
207
208 if (m_filterMode == true && results->count() != totalCount && 0 == results->count())
209 return addResults(index, nullptr, 0, totalCount);
210
211 return addResults(index, new QList<T>(*results), results->count(), totalCount);
212 }
213
214 int addCanceledResult(int index)
215 {
216 if (containsValidResultItem(index)) // reject if already present
217 return -1;
218
219 return addResult(index, static_cast<void *>(nullptr));
220 }
221
222 template <typename T>
223 int addCanceledResults(int index, int _count)
224 {
225 if (containsValidResultItem(index)) // reject if already present
226 return -1;
227
228 QList<T> empty;
229 return addResults(index, &empty, _count);
230 }
231
232 template <typename T>
233 void clear()
234 {
235 ResultStoreBase::clear<T>(m_results);
236 resultCount = 0;
237 insertIndex = 0;
238 ResultStoreBase::clear<T>(pendingResults);
239 filteredResults = 0;
240 }
241};
242
243} // namespace QtPrivate
244
245Q_DECLARE_TYPEINFO(QtPrivate::ResultItem, Q_PRIMITIVE_TYPE);
246
247
248QT_END_NAMESPACE
249
250#endif
251