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/qsequentialiterable.h>
41#include <QtCore/qvariant.h>
42
43#include <QtCore/private/qiterable_p.h>
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 \class QSequentialIterable
49 \since 5.2
50 \inmodule QtCore
51 \brief The QSequentialIterable class is an iterable interface for a container in a QVariant.
52
53 This class allows several methods of accessing the values of a container held within
54 a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can
55 be converted to a QVariantList.
56
57 \snippet code/src_corelib_kernel_qvariant.cpp 9
58
59 The container itself is not copied before iterating over it.
60
61 \sa QVariant
62*/
63
64/*!
65 \typedef QSequentialIterable::RandomAccessIterator
66 Exposes an iterator using std::random_access_iterator_tag.
67*/
68
69/*!
70 \typedef QSequentialIterable::BidirectionalIterator
71 Exposes an iterator using std::bidirectional_iterator_tag.
72*/
73
74/*!
75 \typedef QSequentialIterable::ForwardIterator
76 Exposes an iterator using std::forward_iterator_tag.
77*/
78
79/*!
80 \typedef QSequentialIterable::InputIterator
81 Exposes an iterator using std::input_iterator_tag.
82*/
83
84/*!
85 \typedef QSequentialIterable::RandomAccessConstIterator
86 Exposes a const_iterator using std::random_access_iterator_tag.
87*/
88
89/*!
90 \typedef QSequentialIterable::BidirectionalConstIterator
91 Exposes a const_iterator using std::bidirectional_iterator_tag.
92*/
93
94/*!
95 \typedef QSequentialIterable::ForwardConstIterator
96 Exposes a const_iterator using std::forward_iterator_tag.
97*/
98
99/*!
100 \typedef QSequentialIterable::InputConstIterator
101 Exposes a const_iterator using std::input_iterator_tag.
102*/
103
104/*!
105 Adds \a value to the container, at \a position, if possible.
106 */
107void QSequentialIterable::addValue(const QVariant &value, Position position)
108{
109 QtPrivate::QVariantTypeCoercer coercer;
110 const void *valuePtr = coercer.coerce(value, metaContainer().valueMetaType());
111
112 switch (position) {
113 case AtBegin:
114 if (metaContainer().canAddValueAtBegin())
115 metaContainer().addValueAtBegin(mutableIterable(), valuePtr);
116 break;
117 case AtEnd:
118 if (metaContainer().canAddValueAtEnd())
119 metaContainer().addValueAtEnd(mutableIterable(), valuePtr);
120 break;
121 case Unspecified:
122 if (metaContainer().canAddValue())
123 metaContainer().addValue(mutableIterable(), valuePtr);
124 break;
125 }
126}
127
128/*!
129 Removes a value from the container, at \a position, if possible.
130 */
131void QSequentialIterable::removeValue(Position position)
132{
133 switch (position) {
134 case AtBegin:
135 if (metaContainer().canRemoveValueAtBegin())
136 metaContainer().removeValueAtBegin(mutableIterable());
137 break;
138 case AtEnd:
139 if (metaContainer().canRemoveValueAtEnd())
140 metaContainer().removeValueAtEnd(mutableIterable());
141 break;
142 case Unspecified:
143 if (metaContainer().canRemoveValue())
144 metaContainer().removeValue(mutableIterable());
145 break;
146 }
147}
148
149QMetaType QSequentialIterable::valueMetaType() const
150{
151 return QMetaType(metaContainer().valueMetaType());
152}
153
154/*!
155 Returns the value at position \a idx in the container.
156*/
157QVariant QSequentialIterable::at(qsizetype idx) const
158{
159 QVariant v(valueMetaType());
160 void *dataPtr;
161 if (valueMetaType() == QMetaType::fromType<QVariant>())
162 dataPtr = &v;
163 else
164 dataPtr = v.data();
165
166 const QMetaSequence meta = metaContainer();
167 if (meta.canGetValueAtIndex()) {
168 meta.valueAtIndex(m_iterable.constPointer(), idx, dataPtr);
169 } else if (meta.canGetValueAtConstIterator()) {
170 void *iterator = meta.constBegin(m_iterable.constPointer());
171 meta.advanceConstIterator(iterator, idx);
172 meta.valueAtConstIterator(iterator, dataPtr);
173 meta.destroyConstIterator(iterator);
174 }
175
176 return v;
177}
178
179/*!
180 Sets the element at position \a idx in the container to \a value.
181*/
182void QSequentialIterable::set(qsizetype idx, const QVariant &value)
183{
184 QtPrivate::QVariantTypeCoercer coercer;
185 const void *dataPtr = coercer.coerce(value, metaContainer().valueMetaType());
186
187 const QMetaSequence meta = metaContainer();
188 if (meta.canSetValueAtIndex()) {
189 meta.setValueAtIndex(m_iterable.mutablePointer(), idx, dataPtr);
190 } else if (meta.canSetValueAtIterator()) {
191 void *iterator = meta.begin(m_iterable.mutablePointer());
192 meta.advanceIterator(iterator, idx);
193 meta.setValueAtIterator(iterator, dataPtr);
194 meta.destroyIterator(iterator);
195 }
196}
197
198/*!
199 \class QSequentialIterable::const_iterator
200 \since 5.2
201 \inmodule QtCore
202 \brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant.
203
204 A QSequentialIterable::const_iterator can only be created by a QSequentialIterable instance,
205 and can be used in a way similar to other stl-style iterators.
206
207 \snippet code/src_corelib_kernel_qvariant.cpp 9
208
209 \sa QSequentialIterable
210*/
211
212/*!
213 \class QSequentialIterable::iterator
214 \since 6.0
215 \inmodule QtCore
216 \brief The QSequentialIterable::iterator allows iteration over a container in a QVariant.
217
218 A QSequentialIterable::iterator can only be created by a QSequentialIterable instance,
219 and can be used in a way similar to other stl-style iterators.
220
221 \sa QSequentialIterable
222*/
223
224/*!
225 Returns the current item, converted to a QVariantRef.
226*/
227QVariantRef<QSequentialIterator> QSequentialIterator::operator*() const
228{
229 return QVariantRef<QSequentialIterator>(this);
230}
231
232/*!
233 Returns the current item, converted to a QVariantPointer.
234*/
235QVariantPointer<QSequentialIterator> QSequentialIterator::operator->() const
236{
237 return QVariantPointer<QSequentialIterator>(this);
238}
239
240/*!
241 Returns the current item, converted to a QVariant.
242*/
243QVariant QSequentialConstIterator::operator*() const
244{
245 return QIterablePrivate::retrieveElement(metaContainer().valueMetaType(), [this](void *dataPtr) {
246 metaContainer().valueAtConstIterator(constIterator(), dataPtr);
247 });
248}
249
250/*!
251 Returns the current item, converted to a QVariantConstPointer.
252*/
253QVariantConstPointer QSequentialConstIterator::operator->() const
254{
255 return QVariantConstPointer(operator*());
256}
257
258QT_END_NAMESPACE
259