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

source code of qtbase/src/corelib/kernel/qassociativeiterable.cpp