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

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