Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssginvasivelinkedlist_p.h
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6
7#ifndef QSSGINVASIVELINKEDLIST_H
8#define QSSGINVASIVELINKEDLIST_H
9
10//
11// W A R N I N G
12// -------------
13//
14// This file is not part of the Qt API. It exists purely as an
15// implementation detail. This header file may change from version to
16// version without notice, or even be removed.
17//
18// We mean it.
19//
20
21#include <QtQuick3DUtils/private/qtquick3dutilsglobal_p.h>
22
23QT_BEGIN_NAMESPACE
24
25#ifdef QT_DEBUG
26#define QSSG_VERIFY_NODE(X) if (!(X)) qCritical("Node links are not null!");
27#else
28#define QSSG_VERIFY_NODE(X) Q_UNUSED((X));
29#endif
30
31// Used for singly linked list where
32// items have either no head or tail ptr.
33template<typename T>
34struct QSSGNullOp
35{
36 static void set(T &, T *) {}
37 static T *get(const T &) { return nullptr; }
38};
39
40template <typename T, T *T::*n>
42{
43 static inline T *get(T &o) { return o.*n; }
44 static inline const T *get(const T &o) { return o.*n; }
45 static inline void set(T &o, T *next) { o.*n = next; }
46};
47
48template <typename T, T *T::*p>
50{
51 static inline T *get(T &o) { return o.*p; }
52 static inline const T *get(const T &o) { return o.*p; }
53 static inline void set(T &o, T *prev) { o.*p = prev; }
54};
55
56// Base linked list without an included head or tail member.
57template<typename T, typename HeadOp, typename TailOp>
59{
60 inline T *tail(T *inObj) { return inObj ? TailOp::get(inObj) : nullptr; }
61 inline T *head(T *inObj) { return inObj ? HeadOp::get(inObj) : nullptr; }
62 inline const T *tail(const T *inObj) { return inObj ? TailOp::get(inObj) : nullptr; }
63 inline const T *head(const T *inObj) { return inObj ? HeadOp::get(inObj) : nullptr; }
64
65 void remove(T &inObj)
66 {
67 T *theHead = HeadOp::get(inObj);
68 T *theTail = TailOp::get(inObj);
69 if (theHead)
70 TailOp::set(*theHead, theTail);
71 if (theTail)
72 HeadOp::set(*theTail, theHead);
73 HeadOp::set(inObj, nullptr);
74 TailOp::set(inObj, nullptr);
75 }
76
77 void insert_after(T &inPosition, T &inObj)
78 {
79 T *theHead = &inPosition;
80 T *theTail = TailOp::get(inPosition);
81 insert_unsafe(theHead, theTail, inObj);
82 }
83
84 void insert_before(T &inPosition, T &inObj)
85 {
86 T *theHead = HeadOp::get(inPosition);
87 T *theTail = &inPosition;
88 insert_unsafe(theHead, theTail, inObj);
89 }
90
91 // The name here is intentionally named "unsafe" to discourage use
92 // with out knowing what it implies to call this function.
93 // In most cases this will be used to insert before and after a neighboring pair
94 // (see: insert_before()/_after), but it can also be convenient if you want to split
95 // up a list and retain the chain for the removed section.
96 void insert_unsafe(T *inHead, T *inTail, T &inObj)
97 {
98 if (inHead)
99 TailOp::set(*inHead, &inObj);
100 if (inTail)
101 HeadOp::set(*inTail, &inObj);
102 HeadOp::set(inObj, inHead);
103 TailOp::set(inObj, inTail);
104 }
105};
106
107template<typename T, typename TailOp>
109{
112 explicit QSSGLinkedListIterator(T *inObj = nullptr) : m_obj(inObj) {}
113
114 inline bool operator!=(const Iterator &inIter) const { return m_obj != inIter.m_obj; }
115 inline bool operator==(const Iterator &inIter) const { return m_obj == inIter.m_obj; }
116
118 {
119 if (m_obj)
120 m_obj = TailOp::get(*m_obj);
121 return *this;
122 }
123
125 {
126 Iterator retval(*this);
127 ++(*this);
128 return retval;
129 }
130
131 T &operator*() { return *m_obj; }
132 T *operator->() { return m_obj; }
133};
134
135template<typename T, T *T::*Next>
137{
143 T *m_head = nullptr;
144
145 inline T &front() const { return *m_head; }
146
147 void push_front(T &inObj)
148 {
149 if (m_head != nullptr)
150 BaseList::insert_before(*m_head, inObj);
151 m_head = &inObj;
152 }
153
154 void push_back(T &inObj)
155 {
156 // The next pointer of the tail must be null.
157 // We assert because if the inObj actually points somewhere then it's
158 // likely that we: Crash at some later point, we loop, or we broke the links
159 // in another list.
160 QSSG_VERIFY_NODE(TailOp::get(inObj) == nullptr);
161
162 if (m_head == nullptr) {
163 m_head = &inObj;
164 } else {
165 T *lastObj = nullptr;
166 for (iterator iter = begin(), endIter = end(); iter != endIter; ++iter)
167 lastObj = &(*iter);
168
169 Q_ASSERT(lastObj);
170 if (lastObj)
171 TailOp::set(*lastObj, &inObj);
172 }
173 TailOp::set(inObj, nullptr);
174 }
175
176 void remove(T &inObj)
177 {
178 if (m_head == &inObj) {
179 m_head = TailOp::get(inObj);
180 BaseList::remove(inObj);
181 } else if (m_head) {
182 // We need to find the node pointing to inObj
183 T *head = m_head;
184 T *tail = TailOp::get(*head);
185 while (head && tail != &inObj) {
186 head = TailOp::get(*head);
187 tail = head ? TailOp::get(*head) : nullptr;
188 }
189
190 if (head && tail == &inObj) {
191 T *oldTail = TailOp::get(inObj);
192 TailOp::set(inObj, nullptr); // deteach from the list
193 TailOp::set(*head, oldTail); // insert old tail to head of inObj
194 }
195 }
196 }
197
198 /*!
199 * \brief removeAll removes all nodes and re-sets their tail to null.
200 */
202 {
203 for (auto it = begin(), e = end(); it != e;)
204 remove(*(it++));
205 }
206
207 /*!
208 * \brief clear will set the head of the list to null.
209 * Note that the nodes are not updated in this case!
210 */
211 void clear()
212 {
213 m_head = nullptr;
214 }
215
216 inline bool isEmpty() const { return m_head == nullptr; }
217
218 inline iterator begin() { return iterator(m_head); }
219 inline iterator end() { return iterator(nullptr); }
220 inline const_iterator begin() const { return iterator(m_head); }
221 inline const_iterator end() const { return iterator(nullptr); }
222};
223
224template<typename T, T *T::*Previous, T *T::*Next>
226{
235
236 T *m_head = nullptr;
237 T *m_tail = nullptr;
238
239 inline T &front() const
240 {
241 Q_ASSERT(m_head);
242 return *m_head;
243 }
244 inline T &back() const
245 {
246 Q_ASSERT(m_tail);
247 return *m_tail;
248 }
249
250 inline T *front_ptr() const { return m_head; }
251 inline T *back_ptr() const { return m_tail; }
252
253 void push_front(T &inObj)
254 {
255 // The prev pointer of the head must be null.
256 // If the inObj actually points somewhere then it's likely that we're going to:
257 // Crash at some later point, loop, or that the we just broke the another list.
258 QSSG_VERIFY_NODE(HeadOp::get(inObj) == nullptr);
259
260 if (m_head != nullptr)
261 BaseList::insert_before(*m_head, inObj);
262 else
263 HeadOp::set(inObj, nullptr);
264
265 m_head = &inObj;
266
267 if (m_tail == nullptr)
268 m_tail = &inObj;
269 }
270
271 void push_back(T &inObj)
272 {
273 // The next pointer of the tail must be null.
274 // We assert because if the inObj actually points somewhere then it's
275 // likely that we: Crash at some later point, we loop, or we broke the links
276 // in another list.
277 QSSG_VERIFY_NODE(TailOp::get(inObj) == nullptr);
278
279 if (m_tail != nullptr)
280 BaseList::insert_after(*m_tail, inObj);
281 else
282 TailOp::set(inObj, nullptr);
283
284 m_tail = &inObj;
285
286 if (m_head == nullptr)
287 m_head = &inObj;
288 }
289
290 void remove(T &inObj)
291 {
292 if (m_head == &inObj)
293 m_head = TailOp::get(inObj);
294 if (m_tail == &inObj)
295 m_tail = HeadOp::get(inObj);
296
297 BaseList::remove(inObj);
298 }
299
300 /*!
301 * \brief removeAll removes all nodes and re-sets their head and tail to null.
302 */
304 {
305 for (auto it = begin(), e = end(); it != e;)
306 remove(*(it++));
307 }
308
309 /*!
310 * \brief clear will set the head and tail of the list to null.
311 * Note that the nodes are not updated in this case!
312 */
313 void clear()
314 {
315 m_head = m_tail = nullptr;
316 }
317
318 inline bool isEmpty() const { return m_head == nullptr; }
319
320 inline iterator begin() { return iterator(m_head); }
321 inline iterator end() { return iterator(nullptr); }
322
323 inline const_iterator begin() const { return iterator(m_head); }
324 inline const_iterator end() const { return iterator(nullptr); }
325
326 inline reverse_iterator rbegin() { return reverse_iterator(m_tail); }
327 inline reverse_iterator rend() { return reverse_iterator(nullptr); }
328
329 inline const_reverse_iterator rbegin() const { return reverse_iterator(m_tail); }
330 inline const_reverse_iterator rend() const { return reverse_iterator(nullptr); }
331};
332
333QT_END_NAMESPACE
334
335#endif // QSSGINVASIVELINKEDLIST_H
#define QSSG_VERIFY_NODE(X)
void insert_before(T &inPosition, T &inObj)
const T * head(const T *inObj)
const T * tail(const T *inObj)
void insert_after(T &inPosition, T &inObj)
void insert_unsafe(T *inHead, T *inTail, T &inObj)
const_reverse_iterator rbegin() const
void clear()
clear will set the head and tail of the list to null.
void removeAll()
removeAll removes all nodes and re-sets their head and tail to null.
const_reverse_iterator rend() const
void clear()
clear will set the head of the list to null.
void removeAll()
removeAll removes all nodes and re-sets their tail to null.
bool operator==(const Iterator &inIter) const
QSSGLinkedListIterator(T *inObj=nullptr)
bool operator!=(const Iterator &inIter) const
QSSGLinkedListIterator< T, TailOp > Iterator
static void set(T &o, T *next)
static const T * get(const T &o)
static const T * get(const T &o)
static void set(T &o, T *prev)