1// Copyright (C) 2024 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#ifndef QPROTOBUFREPEATEDITERATOR_H
5#define QPROTOBUFREPEATEDITERATOR_H
6
7#include <QtProtobuf/qprotobufmessage.h>
8#include <QtProtobuf/qtprotobuftypes.h>
9#include <QtProtobuf/qtprotobufexports.h>
10
11#include <QtCore/qhash.h>
12#include <QtCore/qlist.h>
13
14QT_BEGIN_NAMESPACE
15
16class QProtobufMessage;
17class QProtobufRepeatedIterator;
18
19namespace QtProtobufPrivate {
20template <typename T, QtProtobuf::if_protobuf_message<T> = true>
21class ListIterator
22{
23public:
24 ~ListIterator() = default;
25
26 bool hasNext() const noexcept { return m_it != m_list->end(); }
27 QProtobufMessage *next()
28 {
29 Q_ASSERT(m_it != m_list->end());
30 return &*m_it++;
31 }
32
33 QProtobufMessage *addNext() { return &m_list->emplace_back(); }
34
35 /* protobuf allows having elements in the repeated fields that are failed to deserialize */
36 void push() noexcept { }
37
38private:
39 Q_DISABLE_COPY_MOVE(ListIterator)
40
41 friend class QT_PREPEND_NAMESPACE(QProtobufRepeatedIterator);
42
43 explicit ListIterator(QList<T> &list) : m_list(&list), m_it(m_list->begin()) { }
44 QList<T> *m_list = nullptr;
45 typename QList<T>::Iterator m_it;
46};
47
48template <typename K, typename V, QtProtobuf::if_protobuf_map<K, V> = true>
49class MapIterator
50{
51 using MapEntry = QProtobufMapEntry<K, V>;
52 static_assert(!std::is_pointer_v<typename MapEntry::KeyType>, "Map key must not be message");
53
54public:
55 ~MapIterator() { delete m_mapEntry; }
56
57 bool hasNext() const noexcept { return m_it != m_hash->end(); }
58 QProtobufMessage *next()
59 {
60 Q_ASSERT(m_it != m_hash->end());
61 m_mapEntry->setKey(m_it.key());
62 if constexpr (std::is_pointer_v<typename MapEntry::ValueType>)
63 m_mapEntry->setValue(&m_it.value());
64 else
65 m_mapEntry->setValue(m_it.value());
66 ++m_it;
67 return m_mapEntry;
68 }
69
70 QProtobufMessage *addNext()
71 {
72 m_mapEntry->setKey({});
73 m_mapEntry->setValue({});
74 return m_mapEntry;
75 }
76 void push()
77 {
78 auto it = m_hash->emplace(m_mapEntry->key());
79 if constexpr (std::is_pointer_v<typename MapEntry::ValueType>)
80 *it = std::move(*m_mapEntry->value());
81 else
82 *it = m_mapEntry->value();
83 }
84
85private:
86 Q_DISABLE_COPY_MOVE(MapIterator)
87
88 friend class QT_PREPEND_NAMESPACE(QProtobufRepeatedIterator);
89
90 explicit MapIterator(QHash<K, V> &hash)
91 : m_hash(&hash), m_it(m_hash->begin()), m_mapEntry(new MapEntry)
92 {
93 }
94 QHash<K, V> *m_hash = nullptr;
95 typename QHash<K, V>::Iterator m_it;
96 MapEntry *m_mapEntry;
97};
98}
99
100class QProtobufRepeatedIterator
101{
102 enum class Operation { HasNext, Next, AddNext, Push, Deleter };
103 using ImplFn = void (*)(Operation op, void *data, void **args, void *ret);
104
105 template <typename T>
106 static constexpr ImplFn MakeImpl()
107 {
108 return [](Operation op, void *data, void **, void *ret) {
109 switch (op) {
110 case Operation::HasNext:
111 *static_cast<bool *>(ret) = static_cast<const T *>(data)->hasNext();
112 break;
113 case Operation::Next:
114 *static_cast<QProtobufMessage **>(ret) = static_cast<T *>(data)->next();
115 break;
116 case Operation::AddNext:
117 *static_cast<QProtobufMessage **>(ret) = static_cast<T *>(data)->addNext();
118 break;
119 case Operation::Push:
120 static_cast<T *>(data)->push();
121 break;
122 case Operation::Deleter:
123 static_cast<T *>(data)->~T();
124 break;
125 }
126 };
127 }
128public:
129 QProtobufRepeatedIterator() = default;
130 ~QProtobufRepeatedIterator()
131 {
132 if (m_impl)
133 m_impl(Operation::Deleter, &m_data, nullptr, nullptr);
134 }
135
136 QProtobufRepeatedIterator(QProtobufRepeatedIterator &&other) noexcept
137 : m_data(std::exchange(obj&: other.m_data, new_val: {})), m_impl(std::exchange(obj&: other.m_impl, new_val: nullptr))
138 {
139 }
140 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QProtobufRepeatedIterator)
141 void swap(QProtobufRepeatedIterator &other) noexcept
142 {
143 std::swap(a&: m_data, b&: other.m_data);
144 qt_ptr_swap(lhs&: m_impl, rhs&: other.m_impl);
145 };
146
147 [[nodiscard]] bool isValid() const noexcept { return m_impl != nullptr; }
148
149 [[nodiscard]] bool hasNext() const noexcept
150 {
151 bool ret = false;
152 if (m_impl)
153 m_impl(Operation::HasNext, &m_data, nullptr, &ret);
154 return ret;
155 }
156
157 [[nodiscard]] QProtobufMessage *next()
158 {
159 Q_ASSERT(m_impl);
160
161 QProtobufMessage *ret;
162 m_impl(Operation::Next, &m_data, nullptr, &ret);
163 return ret;
164 }
165
166 [[nodiscard]] QProtobufMessage *addNext()
167 {
168 Q_ASSERT(m_impl);
169
170 QProtobufMessage *ret;
171 m_impl(Operation::AddNext, &m_data, nullptr, &ret);
172 return ret;
173 }
174
175 void push()
176 {
177 Q_ASSERT(m_impl);
178
179 m_impl(Operation::Push, &m_data, nullptr, nullptr);
180 }
181
182 template<typename T>
183 static QProtobufRepeatedIterator fromList(QList<T> &list)
184 {
185 return QProtobufRepeatedIterator(list);
186 }
187
188 template<typename K, typename V>
189 static QProtobufRepeatedIterator fromHash(QHash<K, V> &hash)
190 {
191 return QProtobufRepeatedIterator(hash);
192 }
193
194private:
195 Q_DISABLE_COPY(QProtobufRepeatedIterator)
196
197 template<typename K, typename V, typename Iterator = QtProtobufPrivate::MapIterator<K, V>>
198 explicit QProtobufRepeatedIterator(QHash<K, V> &data) noexcept : m_impl(MakeImpl<Iterator>())
199 {
200 ::new (static_cast<void *>(&m_data)) Iterator(data);
201 }
202
203 template<typename T, typename Iterator = QtProtobufPrivate::ListIterator<T>>
204 explicit QProtobufRepeatedIterator(QList<T> &data) noexcept : m_impl(MakeImpl<Iterator>())
205 {
206 ::new (static_cast<void *>(&m_data)) Iterator(data);
207 }
208
209 mutable struct { alignas(sizeof(void *)) unsigned char data[sizeof(void *) * 4]; } m_data;
210 ImplFn m_impl = nullptr;
211
212 static_assert(sizeof(QHash<int, int>::const_iterator) <= sizeof(m_data));
213 static_assert(alignof(decltype(m_data)) == alignof(void *));
214};
215
216QT_END_NAMESPACE
217
218#endif // QPROTOBUFREPEATEDITERATOR_H
219

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgrpc/src/protobuf/qprotobufrepeatediterator.h