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 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | /*! |
48 | Returns the key this iterator points to. |
49 | */ |
50 | QVariant 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 | */ |
62 | QVariantRef<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 | */ |
73 | QVariantRef<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 | */ |
83 | QVariantPointer<QAssociativeIterator> QAssociativeIterator::operator->() const |
84 | { |
85 | return QVariantPointer<QAssociativeIterator>(this); |
86 | } |
87 | |
88 | /*! |
89 | Returns the key this iterator points to. |
90 | */ |
91 | QVariant 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 | */ |
103 | QVariant 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 | */ |
115 | QVariant 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 | */ |
126 | QVariantConstPointer 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 | */ |
193 | QAssociativeIterable::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 | */ |
209 | QAssociativeIterable::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 | */ |
223 | bool 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 | */ |
238 | void 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 | */ |
250 | void 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 | */ |
264 | QVariant 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 | */ |
289 | void 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 | |
324 | QT_END_NAMESPACE |
325 | |