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#ifndef QASSOCIATIVEITERABLE_H
41#define QASSOCIATIVEITERABLE_H
42
43#include <QtCore/qiterable.h>
44#include <QtCore/qvariant.h>
45
46QT_BEGIN_NAMESPACE
47
48class Q_CORE_EXPORT QAssociativeIterator : public QIterator<QMetaAssociation>
49{
50public:
51 using key_type = QVariant;
52 using mapped_type = QVariant;
53 using reference = QVariantRef<QAssociativeIterator>;
54 using pointer = QVariantPointer<QAssociativeIterator>;
55
56 QAssociativeIterator(QIterator &&it)
57 : QIterator(std::move(it))
58 {}
59
60 QVariant key() const;
61 QVariantRef<QAssociativeIterator> value() const;
62
63 QVariantRef<QAssociativeIterator> operator*() const;
64 QVariantPointer<QAssociativeIterator> operator->() const;
65};
66
67class Q_CORE_EXPORT QAssociativeConstIterator : public QConstIterator<QMetaAssociation>
68{
69public:
70 using key_type = QVariant;
71 using mapped_type = QVariant;
72 using reference = const QVariant &;
73 using pointer = QVariantConstPointer;
74
75 QAssociativeConstIterator(QConstIterator &&it)
76 : QConstIterator(std::move(it))
77 {}
78
79 QVariant key() const;
80 QVariant value() const;
81
82 QVariant operator*() const;
83 QVariantConstPointer operator->() const;
84};
85
86class Q_CORE_EXPORT QAssociativeIterable : public QIterable<QMetaAssociation>
87{
88public:
89 using iterator = QTaggedIterator<QAssociativeIterator, void>;
90 using const_iterator = QTaggedIterator<QAssociativeConstIterator, void>;
91
92 using RandomAccessIterator = QTaggedIterator<iterator, std::random_access_iterator_tag>;
93 using BidirectionalIterator = QTaggedIterator<iterator, std::bidirectional_iterator_tag>;
94 using ForwardIterator = QTaggedIterator<iterator, std::forward_iterator_tag>;
95 using InputIterator = QTaggedIterator<iterator, std::input_iterator_tag>;
96
97 using RandomAccessConstIterator = QTaggedIterator<const_iterator, std::random_access_iterator_tag>;
98 using BidirectionalConstIterator = QTaggedIterator<const_iterator, std::bidirectional_iterator_tag>;
99 using ForwardConstIterator = QTaggedIterator<const_iterator, std::forward_iterator_tag>;
100 using InputConstIterator = QTaggedIterator<const_iterator, std::input_iterator_tag>;
101
102 template<class T>
103 QAssociativeIterable(const T *p)
104 : QIterable(QMetaAssociation::fromContainer<T>(), p)
105 {
106 }
107
108 template<class T>
109 QAssociativeIterable(T *p)
110 : QIterable(QMetaAssociation::fromContainer<T>(), p)
111 {
112 }
113
114 QAssociativeIterable()
115 : QIterable(QMetaAssociation(), nullptr)
116 {
117 }
118
119 template<typename Pointer>
120 QAssociativeIterable(const QMetaAssociation &metaAssociation, Pointer iterable)
121 : QIterable(metaAssociation, iterable)
122 {
123 }
124
125 QAssociativeIterable(const QMetaAssociation &metaAssociation, const QMetaType &metaType,
126 void *iterable)
127 : QIterable(metaAssociation, metaType.alignOf(), iterable)
128 {
129 }
130
131 QAssociativeIterable(const QMetaAssociation &metaAssociation, const QMetaType &metaType,
132 const void *iterable)
133 : QIterable(metaAssociation, metaType.alignOf(), iterable)
134 {
135 }
136
137 QAssociativeIterable(QIterable<QMetaAssociation> &&other) : QIterable(std::move(other)) {}
138
139 QAssociativeIterable &operator=(QIterable<QMetaAssociation> &&other)
140 {
141 QIterable::operator=(std::move(other));
142 return *this;
143 }
144
145 const_iterator begin() const { return constBegin(); }
146 const_iterator end() const { return constEnd(); }
147
148 const_iterator constBegin() const { return const_iterator(QIterable::constBegin()); }
149 const_iterator constEnd() const { return const_iterator(QIterable::constEnd()); }
150
151 iterator mutableBegin() { return iterator(QIterable::mutableBegin()); }
152 iterator mutableEnd() { return iterator(QIterable::mutableEnd()); }
153
154 const_iterator find(const QVariant &key) const;
155 const_iterator constFind(const QVariant &key) const { return find(key); }
156 iterator mutableFind(const QVariant &key);
157
158 bool containsKey(const QVariant &key);
159 void insertKey(const QVariant &key);
160 void removeKey(const QVariant &key);
161
162 QVariant value(const QVariant &key) const;
163 void setValue(const QVariant &key, const QVariant &mapped);
164};
165
166template<>
167inline QVariantRef<QAssociativeIterator>::operator QVariant() const
168{
169 if (m_pointer == nullptr)
170 return QVariant();
171
172 const auto metaAssociation = m_pointer->metaContainer();
173 const QMetaType metaType(metaAssociation.mappedMetaType());
174 if (!metaType.isValid())
175 return m_pointer->key();
176
177 QVariant v(metaType);
178 metaAssociation.mappedAtIterator(m_pointer->constIterator(),
179 metaType == QMetaType::fromType<QVariant>() ? &v : v.data());
180 return v;
181}
182
183template<>
184inline QVariantRef<QAssociativeIterator> &QVariantRef<QAssociativeIterator>::operator=(
185 const QVariant &value)
186{
187 if (m_pointer == nullptr)
188 return *this;
189
190 const auto metaAssociation = m_pointer->metaContainer();
191 const QMetaType metaType(metaAssociation.mappedMetaType());
192 if (metaType.isValid()) {
193 QtPrivate::QVariantTypeCoercer coercer;
194 metaAssociation.setMappedAtIterator(m_pointer->constIterator(),
195 coercer.coerce(value, metaType));
196 }
197
198 return *this;
199}
200
201Q_DECLARE_TYPEINFO(QAssociativeIterable, Q_MOVABLE_TYPE);
202Q_DECLARE_TYPEINFO(QAssociativeIterable::iterator, Q_MOVABLE_TYPE);
203Q_DECLARE_TYPEINFO(QAssociativeIterable::const_iterator, Q_MOVABLE_TYPE);
204
205QT_END_NAMESPACE
206
207#endif // QASSOCIATIVEITERABLE_H
208