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#include "qresultstore.h"
5
6QT_BEGIN_NAMESPACE
7
8namespace QtPrivate {
9
10/*!
11 \internal
12
13 Finds result in \a store by \a index
14 */
15static ResultIteratorBase findResult(const QMap<int, ResultItem> &store, int index)
16{
17 if (store.isEmpty())
18 return ResultIteratorBase(store.end());
19 QMap<int, ResultItem>::const_iterator it = store.lowerBound(key: index);
20
21 // lowerBound returns either an iterator to the result or an iterator
22 // to the nearest greater index. If the latter happens it might be
23 // that the result is stored in a vector at the previous index.
24 if (it == store.end()) {
25 --it;
26 if (it.value().isVector() == false) {
27 return ResultIteratorBase(store.end());
28 }
29 } else {
30 if (it.key() > index) {
31 if (it == store.begin())
32 return ResultIteratorBase(store.end());
33 --it;
34 }
35 }
36
37 const int vectorIndex = index - it.key();
38
39 if (vectorIndex >= it.value().count())
40 return ResultIteratorBase(store.end());
41 else if (it.value().isVector() == false && vectorIndex != 0)
42 return ResultIteratorBase(store.end());
43 return ResultIteratorBase(it, vectorIndex);
44}
45
46/*!
47 \class QtPrivate::ResultItem
48 \internal
49 */
50
51/*!
52 \class QtPrivate::ResultIteratorBase
53 \internal
54 */
55
56/*!
57 \class QtPrivate::ResultStoreBase
58 \internal
59 */
60
61ResultIteratorBase::ResultIteratorBase()
62 : mapIterator(QMap<int, ResultItem>::const_iterator()), m_vectorIndex(0) { }
63ResultIteratorBase::ResultIteratorBase(QMap<int, ResultItem>::const_iterator _mapIterator, int _vectorIndex)
64 : mapIterator(_mapIterator), m_vectorIndex(_vectorIndex) { }
65
66int ResultIteratorBase::vectorIndex() const { return m_vectorIndex; }
67int ResultIteratorBase::resultIndex() const { return mapIterator.key() + m_vectorIndex; }
68
69ResultIteratorBase ResultIteratorBase::operator++()
70{
71 if (canIncrementVectorIndex()) {
72 ++m_vectorIndex;
73 } else {
74 ++mapIterator;
75 m_vectorIndex = 0;
76 }
77 return *this;
78}
79
80int ResultIteratorBase::batchSize() const
81{
82 return mapIterator.value().count();
83}
84
85void ResultIteratorBase::batchedAdvance()
86{
87 ++mapIterator;
88 m_vectorIndex = 0;
89}
90
91bool ResultIteratorBase::operator==(const ResultIteratorBase &other) const
92{
93 return (mapIterator == other.mapIterator && m_vectorIndex == other.m_vectorIndex);
94}
95
96bool ResultIteratorBase::operator!=(const ResultIteratorBase &other) const
97{
98 return !operator==(other);
99}
100
101bool ResultIteratorBase::isVector() const
102{
103 return mapIterator.value().isVector();
104}
105
106bool ResultIteratorBase::canIncrementVectorIndex() const
107{
108 return (m_vectorIndex + 1 < mapIterator.value().m_count);
109}
110
111bool ResultIteratorBase::isValid() const
112{
113 return mapIterator.value().isValid();
114}
115
116ResultStoreBase::ResultStoreBase()
117 : insertIndex(0), resultCount(0), m_filterMode(false), filteredResults(0) { }
118
119ResultStoreBase::~ResultStoreBase()
120{
121 // QFutureInterface's dtor must delete the contents of m_results.
122 Q_ASSERT(m_results.isEmpty());
123}
124
125void ResultStoreBase::setFilterMode(bool enable)
126{
127 m_filterMode = enable;
128}
129
130bool ResultStoreBase::filterMode() const
131{
132 return m_filterMode;
133}
134
135void ResultStoreBase::syncResultCount()
136{
137 ResultIteratorBase it = resultAt(index: resultCount);
138 while (it != end()) {
139 resultCount += it.batchSize();
140 it = resultAt(index: resultCount);
141 }
142}
143
144void ResultStoreBase::insertResultItemIfValid(int index, ResultItem &resultItem)
145{
146 if (resultItem.isValid()) {
147 m_results[index] = resultItem;
148 syncResultCount();
149 } else {
150 filteredResults += resultItem.count();
151 }
152}
153
154int ResultStoreBase::insertResultItem(int index, ResultItem &resultItem)
155{
156 int storeIndex;
157 if (m_filterMode && index != -1 && index > insertIndex) {
158 pendingResults[index] = resultItem;
159 storeIndex = index;
160 } else {
161 storeIndex = updateInsertIndex(index, count: resultItem.count());
162 insertResultItemIfValid(index: storeIndex - filteredResults, resultItem);
163 }
164 syncPendingResults();
165 return storeIndex;
166}
167
168bool ResultStoreBase::containsValidResultItem(int index) const
169{
170 // index might refer to either visible or pending result
171 const bool inPending = m_filterMode && index != -1 && index > insertIndex;
172 const auto &store = inPending ? pendingResults : m_results;
173 auto it = findResult(store, index);
174 return it != ResultIteratorBase(store.end()) && it.isValid();
175}
176
177void ResultStoreBase::syncPendingResults()
178{
179 // check if we can insert any of the pending results:
180 QMap<int, ResultItem>::iterator it = pendingResults.begin();
181 while (it != pendingResults.end()) {
182 int index = it.key();
183 if (index != resultCount + filteredResults)
184 break;
185
186 ResultItem result = it.value();
187 insertResultItemIfValid(index: index - filteredResults, resultItem&: result);
188 pendingResults.erase(it);
189 it = pendingResults.begin();
190 }
191}
192
193int ResultStoreBase::addResult(int index, const void *result)
194{
195 ResultItem resultItem(result, 0); // 0 means "not a vector"
196 return insertResultItem(index, resultItem);
197}
198
199int ResultStoreBase::addResults(int index, const void *results, int vectorSize, int totalCount)
200{
201 if (m_filterMode == false || vectorSize == totalCount) {
202 Q_ASSERT(vectorSize != 0);
203 ResultItem resultItem(results, vectorSize);
204 return insertResultItem(index, resultItem);
205 } else {
206 if (vectorSize > 0) {
207 ResultItem filteredIn(results, vectorSize);
208 insertResultItem(index, resultItem&: filteredIn);
209 }
210 ResultItem filteredAway(nullptr, totalCount - vectorSize);
211 return insertResultItem(index: index + vectorSize, resultItem&: filteredAway);
212 }
213}
214
215ResultIteratorBase ResultStoreBase::begin() const
216{
217 return ResultIteratorBase(m_results.begin());
218}
219
220ResultIteratorBase ResultStoreBase::end() const
221{
222 return ResultIteratorBase(m_results.end());
223}
224
225bool ResultStoreBase::hasNextResult() const
226{
227 return begin() != end();
228}
229
230ResultIteratorBase ResultStoreBase::resultAt(int index) const
231{
232 return findResult(store: m_results, index);
233}
234
235bool ResultStoreBase::contains(int index) const
236{
237 return (resultAt(index) != end());
238}
239
240int ResultStoreBase::count() const
241{
242 return resultCount;
243}
244
245// returns the insert index, calling this function with
246// index equal to -1 returns the next available index.
247int ResultStoreBase::updateInsertIndex(int index, int _count)
248{
249 if (index == -1) {
250 index = insertIndex;
251 insertIndex += _count;
252 } else {
253 insertIndex = qMax(a: index + _count, b: insertIndex);
254 }
255 return index;
256}
257
258} // namespace QtPrivate
259
260QT_END_NAMESPACE
261

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