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

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