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 | |
9 | QT_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 | */ |
71 | void 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 | */ |
95 | void 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 | |
113 | QMetaType QSequentialIterable::valueMetaType() const |
114 | { |
115 | return QMetaType(metaContainer().valueMetaType()); |
116 | } |
117 | |
118 | /*! |
119 | Returns the value at position \a idx in the container. |
120 | */ |
121 | QVariant 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 | */ |
146 | void 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 | */ |
184 | QVariantRef<QSequentialIterator> QSequentialIterator::operator*() const |
185 | { |
186 | return QVariantRef<QSequentialIterator>(this); |
187 | } |
188 | |
189 | /*! |
190 | Returns the current item, converted to a QVariantPointer. |
191 | */ |
192 | QVariantPointer<QSequentialIterator> QSequentialIterator::operator->() const |
193 | { |
194 | return QVariantPointer<QSequentialIterator>(this); |
195 | } |
196 | |
197 | /*! |
198 | Returns the current item, converted to a QVariant. |
199 | */ |
200 | QVariant 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 | */ |
210 | QVariantConstPointer QSequentialConstIterator::operator->() const |
211 | { |
212 | return QVariantConstPointer(operator*()); |
213 | } |
214 | |
215 | QT_END_NAMESPACE |
216 | |