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#include <QtCore/qassociativeiterable.h>
41#include <QtCore/qvariant.h>
42
43#include <QtCore/private/qiterable_p.h>
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 Returns the key this iterator points to.
49*/
50QVariant QAssociativeIterator::key() const
51{
52 return QIterablePrivate::retrieveElement(
53 metaContainer().keyMetaType(), [this](void *dataPtr) {
54 metaContainer().keyAtIterator(constIterator(), dataPtr);
55 });
56}
57
58/*!
59 Returns the mapped value this iterator points to. If the container does not
60 provide a mapped value (for example a set), returns an invalid QVariantRef.
61*/
62QVariantRef<QAssociativeIterator> QAssociativeIterator::value() const
63{
64 const QMetaType mappedMetaType(metaContainer().mappedMetaType());
65 return QVariantRef<QAssociativeIterator>(mappedMetaType.isValid() ? this : nullptr);
66}
67
68/*!
69 Returns the current item, converted to a QVariantRef. The resulting
70 QVariantRef resolves to the mapped value if there is one, or to the key
71 value if not.
72*/
73QVariantRef<QAssociativeIterator> QAssociativeIterator::operator*() const
74{
75 return QVariantRef<QAssociativeIterator>(this);
76}
77
78/*!
79 Returns the current item, converted to a QVariantPointer. The resulting
80 QVariantPointer resolves to the mapped value if there is one, or to the key
81 value if not.
82*/
83QVariantPointer<QAssociativeIterator> QAssociativeIterator::operator->() const
84{
85 return QVariantPointer<QAssociativeIterator>(this);
86}
87
88/*!
89 Returns the key this iterator points to.
90*/
91QVariant QAssociativeConstIterator::key() const
92{
93 return QIterablePrivate::retrieveElement(
94 metaContainer().keyMetaType(), [this](void *dataPtr) {
95 metaContainer().keyAtConstIterator(constIterator(), dataPtr);
96 });
97}
98
99/*!
100 Returns the mapped value this iterator points to, or an invalid QVariant if
101 there is no mapped value.
102*/
103QVariant QAssociativeConstIterator::value() const
104{
105 return QIterablePrivate::retrieveElement(
106 metaContainer().mappedMetaType(), [this](void *dataPtr) {
107 metaContainer().mappedAtConstIterator(constIterator(), dataPtr);
108 });
109}
110
111/*!
112 Returns the current item, converted to a QVariant. The returned value is the
113 mapped value at the current iterator if there is one, or otherwise the key.
114*/
115QVariant QAssociativeConstIterator::operator*() const
116{
117 const QMetaType mappedMetaType(metaContainer().mappedMetaType());
118 return mappedMetaType.isValid() ? value() : key();
119}
120
121/*!
122 Returns the current item, converted to a QVariantConstPointer. The
123 QVariantConstPointer will resolve to the mapped value at the current
124 iterator if there is one, or otherwise the key.
125*/
126QVariantConstPointer QAssociativeConstIterator::operator->() const
127{
128 return QVariantConstPointer(operator*());
129}
130
131/*!
132 \class QAssociativeIterable
133 \since 5.2
134 \inmodule QtCore
135 \brief The QAssociativeIterable class is an iterable interface for an associative container in a QVariant.
136
137 This class allows several methods of accessing the elements of an associative container held within
138 a QVariant. An instance of QAssociativeIterable can be extracted from a QVariant if it can
139 be converted to a QVariantHash or QVariantMap or if a custom mutable view has been registered.
140
141 \snippet code/src_corelib_kernel_qvariant.cpp 10
142
143 The container itself is not copied before iterating over it.
144
145 \sa QVariant
146*/
147
148/*!
149 \typedef QAssociativeIterable::RandomAccessIterator
150 Exposes an iterator using std::random_access_iterator_tag.
151*/
152
153/*!
154 \typedef QAssociativeIterable::BidirectionalIterator
155 Exposes an iterator using std::bidirectional_iterator_tag.
156*/
157
158/*!
159 \typedef QAssociativeIterable::ForwardIterator
160 Exposes an iterator using std::forward_iterator_tag.
161*/
162
163/*!
164 \typedef QAssociativeIterable::InputIterator
165 Exposes an iterator using std::input_iterator_tag.
166*/
167
168/*!
169 \typedef QAssociativeIterable::RandomAccessConstIterator
170 Exposes a const_iterator using std::random_access_iterator_tag.
171*/
172
173/*!
174 \typedef QAssociativeIterable::BidirectionalConstIterator
175 Exposes a const_iterator using std::bidirectional_iterator_tag.
176*/
177
178/*!
179 \typedef QAssociativeIterable::ForwardConstIterator
180 Exposes a const_iterator using std::forward_iterator_tag.
181*/
182
183/*!
184 \typedef QAssociativeIterable::InputConstIterator
185 Exposes a const_iterator using std::input_iterator_tag.
186*/
187
188/*!
189 Retrieves a const_iterator pointing to the element at the given \a key, or
190 the end of the container if that key does not exist. If the \a key isn't
191 convertible to the expected type, the end of the container is returned.
192 */
193QAssociativeIterable::const_iterator QAssociativeIterable::find(const QVariant &key) const
194{
195 const QMetaAssociation meta = metaContainer();
196 QtPrivate::QVariantTypeCoercer coercer;
197 if (const void *keyData = coercer.convert(key, meta.keyMetaType())) {
198 return const_iterator(QConstIterator(this, meta.createConstIteratorAtKey(
199 constIterable(), keyData)));
200 }
201 return constEnd();
202}
203
204/*!
205 Retrieves an iterator pointing to the element at the given \a key, or
206 the end of the container if that key does not exist. If the \a key isn't
207 convertible to the expected type, the end of the container is returned.
208 */
209QAssociativeIterable::iterator QAssociativeIterable::mutableFind(const QVariant &key)
210{
211 const QMetaAssociation meta = metaContainer();
212 QtPrivate::QVariantTypeCoercer coercer;
213 if (const void *keyData = coercer.convert(key, meta.keyMetaType()))
214 return iterator(QIterator(this, meta.createIteratorAtKey(mutableIterable(), keyData)));
215 return mutableEnd();
216}
217
218/*!
219 Returns \c true if the container has an entry with the given \a key, or
220 \c false otherwise. If the \a key isn't convertible to the expected type,
221 \c false is returned.
222 */
223bool QAssociativeIterable::containsKey(const QVariant &key)
224{
225 QtPrivate::QVariantTypeCoercer keyCoercer;
226 QMetaAssociation meta = metaContainer();
227 if (const void *keyData = keyCoercer.convert(key, meta.keyMetaType()))
228 return meta.containsKey(constIterable(), keyData);
229 return false;
230}
231
232/*!
233 Inserts a new entry with the given \a key, or resets the mapped value of
234 any existing entry with the given \a key to the default constructed
235 mapped value. The \a key is coerced to the expected type: If it isn't
236 convertible, a default value is inserted.
237 */
238void QAssociativeIterable::insertKey(const QVariant &key)
239{
240 QMetaAssociation meta = metaContainer();
241 QtPrivate::QVariantTypeCoercer keyCoercer;
242 meta.insertKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()));
243}
244
245/*!
246 Removes the entry with the given \a key from the container. The \a key is
247 coerced to the expected type: If it isn't convertible, the default value
248 is removed.
249 */
250void QAssociativeIterable::removeKey(const QVariant &key)
251{
252 QMetaAssociation meta = metaContainer();
253 QtPrivate::QVariantTypeCoercer keyCoercer;
254 meta.removeKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()));
255}
256
257
258/*!
259 Retrieves the mapped value at the given \a key, or a default-constructed
260 QVariant of the mapped type, if the key does not exist. If the \a key is not
261 convertible to the key type, the mapped value associated with the
262 default-constructed key is returned.
263 */
264QVariant QAssociativeIterable::value(const QVariant &key) const
265{
266 const QMetaAssociation meta = metaContainer();
267 const QMetaType mappedMetaType = meta.mappedMetaType();
268
269 QtPrivate::QVariantTypeCoercer coercer;
270 const void *keyData = coercer.coerce(key, meta.keyMetaType());
271
272 if (mappedMetaType == QMetaType::fromType<QVariant>()) {
273 QVariant result;
274 meta.mappedAtKey(constIterable(), keyData, &result);
275 return result;
276 }
277
278 QVariant result(mappedMetaType);
279 meta.mappedAtKey(constIterable(), keyData, result.data());
280 return result;
281}
282
283/*!
284 Sets the mapped value associated with \a key to \a mapped, if possible.
285 Inserts a new entry if none exists yet, for the given \a key. If the \a key
286 is not convertible to the key type, the value for the default-constructed
287 key type is overwritten.
288 */
289void QAssociativeIterable::setValue(const QVariant &key, const QVariant &mapped)
290{
291 QtPrivate::QVariantTypeCoercer keyCoercer;
292 QtPrivate::QVariantTypeCoercer mappedCoercer;
293 QMetaAssociation meta = metaContainer();
294 meta.setMappedAtKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()),
295 mappedCoercer.coerce(mapped, meta.mappedMetaType()));
296}
297
298/*!
299 \class QAssociativeIterable::const_iterator
300 \since 5.2
301 \inmodule QtCore
302 \brief The QAssociativeIterable::const_iterator allows iteration over a container in a QVariant.
303
304 A QAssociativeIterable::const_iterator can only be created by a QAssociativeIterable instance,
305 and can be used in a way similar to other stl-style iterators.
306
307 \snippet code/src_corelib_kernel_qvariant.cpp 10
308
309 \sa QAssociativeIterable
310*/
311
312/*!
313 \class QAssociativeIterable::iterator
314 \since 6.0
315 \inmodule QtCore
316 \brief The QAssociativeIterable::iterator allows iteration over a container in a QVariant.
317
318 A QAssociativeIterable::iterator can only be created by a QAssociativeIterable instance,
319 and can be used in a way similar to other stl-style iterators.
320
321 \sa QAssociativeIterable
322*/
323
324QT_END_NAMESPACE
325