]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdbsupport/intrusive_list.h
gdb, gdbserver, gdbsupport: remove includes of early headers
[thirdparty/binutils-gdb.git] / gdbsupport / intrusive_list.h
CommitLineData
bf809310 1/* Intrusive double linked list for GDB, the GNU debugger.
1d506c26 2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
bf809310
PA
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifndef GDBSUPPORT_INTRUSIVE_LIST_H
20#define GDBSUPPORT_INTRUSIVE_LIST_H
21
22#define INTRUSIVE_LIST_UNLINKED_VALUE ((T *) -1)
23
24/* A list node. The elements put in an intrusive_list either inherit
25 from this, or have a field of this type. */
26template<typename T>
50b032eb 27class intrusive_list_node
bf809310 28{
50b032eb 29public:
bf809310
PA
30 bool is_linked () const
31 {
32 return next != INTRUSIVE_LIST_UNLINKED_VALUE;
33 }
34
50b032eb 35private:
bf809310
PA
36 T *next = INTRUSIVE_LIST_UNLINKED_VALUE;
37 T *prev = INTRUSIVE_LIST_UNLINKED_VALUE;
50b032eb
PA
38
39 template<typename T2, typename AsNode>
40 friend struct intrusive_list_iterator;
41
42 template<typename T2, typename AsNode>
43 friend struct intrusive_list_reverse_iterator;
44
45 template<typename T2, typename AsNode>
46 friend struct intrusive_list;
bf809310
PA
47};
48
49/* Follows a couple types used by intrusive_list as template parameter to find
50 the intrusive_list_node for a given element. One for lists where the
51 elements inherit intrusive_list_node, and another for elements that keep the
52 node as member field. */
53
54/* For element types that inherit from intrusive_list_node. */
55
56template<typename T>
57struct intrusive_base_node
58{
59 static intrusive_list_node<T> *as_node (T *elem)
60 { return elem; }
61};
62
63/* For element types that keep the node as member field. */
64
65template<typename T, intrusive_list_node<T> T::*MemberNode>
66struct intrusive_member_node
67{
68 static intrusive_list_node<T> *as_node (T *elem)
69 { return &(elem->*MemberNode); }
70};
71
72/* Common code for forward and reverse iterators. */
73
74template<typename T, typename AsNode, typename SelfType>
75struct intrusive_list_base_iterator
76{
77 using self_type = SelfType;
78 using iterator_category = std::bidirectional_iterator_tag;
79 using value_type = T;
80 using pointer = T *;
81 using const_pointer = const T *;
82 using reference = T &;
83 using const_reference = const T &;
84 using difference_type = ptrdiff_t;
85 using size_type = size_t;
86 using node_type = intrusive_list_node<T>;
87
88 /* Create an iterator pointing to ELEM. */
1f08aca9 89 explicit intrusive_list_base_iterator (pointer elem)
bf809310
PA
90 : m_elem (elem)
91 {}
92
93 /* Create a past-the-end iterator. */
94 intrusive_list_base_iterator ()
95 : m_elem (nullptr)
96 {}
97
98 reference operator* () const
99 { return *m_elem; }
100
101 pointer operator-> () const
102 { return m_elem; }
103
104 bool operator== (const self_type &other) const
105 { return m_elem == other.m_elem; }
106
107 bool operator!= (const self_type &other) const
108 { return m_elem != other.m_elem; }
109
110protected:
1f08aca9 111 static node_type *as_node (pointer elem)
bf809310
PA
112 { return AsNode::as_node (elem); }
113
114 /* A past-end-the iterator points to the list's head. */
115 pointer m_elem;
116};
117
118/* Forward iterator for an intrusive_list. */
119
120template<typename T, typename AsNode = intrusive_base_node<T>>
121struct intrusive_list_iterator
122 : public intrusive_list_base_iterator
123 <T, AsNode, intrusive_list_iterator<T, AsNode>>
124{
125 using base = intrusive_list_base_iterator
126 <T, AsNode, intrusive_list_iterator<T, AsNode>>;
127 using self_type = typename base::self_type;
128 using node_type = typename base::node_type;
129
130 /* Inherit constructor and M_NODE visibility from base. */
131 using base::base;
132 using base::m_elem;
133
134 self_type &operator++ ()
135 {
136 node_type *node = this->as_node (m_elem);
137 m_elem = node->next;
138 return *this;
139 }
140
141 self_type operator++ (int)
142 {
143 self_type temp = *this;
144 node_type *node = this->as_node (m_elem);
145 m_elem = node->next;
146 return temp;
147 }
148
149 self_type &operator-- ()
150 {
151 node_type *node = this->as_node (m_elem);
152 m_elem = node->prev;
153 return *this;
154 }
155
156 self_type operator-- (int)
157 {
158 self_type temp = *this;
159 node_type *node = this->as_node (m_elem);
160 m_elem = node->prev;
161 return temp;
162 }
163};
164
165/* Reverse iterator for an intrusive_list. */
166
167template<typename T, typename AsNode = intrusive_base_node<T>>
168struct intrusive_list_reverse_iterator
169 : public intrusive_list_base_iterator
170 <T, AsNode, intrusive_list_reverse_iterator<T, AsNode>>
171{
172 using base = intrusive_list_base_iterator
173 <T, AsNode, intrusive_list_reverse_iterator<T, AsNode>>;
174 using self_type = typename base::self_type;
175
176 /* Inherit constructor and M_NODE visibility from base. */
177 using base::base;
178 using base::m_elem;
179 using node_type = typename base::node_type;
180
181 self_type &operator++ ()
182 {
183 node_type *node = this->as_node (m_elem);
184 m_elem = node->prev;
185 return *this;
186 }
187
188 self_type operator++ (int)
189 {
190 self_type temp = *this;
191 node_type *node = this->as_node (m_elem);
192 m_elem = node->prev;
193 return temp;
194 }
195
196 self_type &operator-- ()
197 {
198 node_type *node = this->as_node (m_elem);
199 m_elem = node->next;
200 return *this;
201 }
202
203 self_type operator-- (int)
204 {
205 self_type temp = *this;
206 node_type *node = this->as_node (m_elem);
207 m_elem = node->next;
208 return temp;
209 }
210};
211
212/* An intrusive double-linked list.
213
214 T is the type of the elements to link. The type T must either:
215
216 - inherit from intrusive_list_node<T>
217 - have an intrusive_list_node<T> member
218
219 AsNode is a type with an as_node static method used to get a node from an
220 element. If elements inherit from intrusive_list_node<T>, use the default
221 intrusive_base_node<T>. If elements have an intrusive_list_node<T> member,
222 use:
223
224 intrusive_member_node<T, &T::member>
225
226 where `member` is the name of the member. */
227
228template <typename T, typename AsNode = intrusive_base_node<T>>
229class intrusive_list
230{
231public:
232 using value_type = T;
233 using pointer = T *;
234 using const_pointer = const T *;
235 using reference = T &;
236 using const_reference = const T &;
237 using difference_type = ptrdiff_t;
238 using size_type = size_t;
239 using iterator = intrusive_list_iterator<T, AsNode>;
240 using reverse_iterator = intrusive_list_reverse_iterator<T, AsNode>;
241 using const_iterator = const intrusive_list_iterator<T, AsNode>;
242 using const_reverse_iterator
243 = const intrusive_list_reverse_iterator<T, AsNode>;
244 using node_type = intrusive_list_node<T>;
245
246 intrusive_list () = default;
247
248 ~intrusive_list ()
249 {
250 clear ();
251 }
252
253 intrusive_list (intrusive_list &&other)
254 : m_front (other.m_front),
255 m_back (other.m_back)
256 {
257 other.m_front = nullptr;
258 other.m_back = nullptr;
259 }
260
261 intrusive_list &operator= (intrusive_list &&other)
262 {
263 m_front = other.m_front;
264 m_back = other.m_back;
265 other.m_front = nullptr;
266 other.m_back = nullptr;
267
268 return *this;
269 }
270
271 void swap (intrusive_list &other)
272 {
273 std::swap (m_front, other.m_front);
274 std::swap (m_back, other.m_back);
275 }
276
277 iterator iterator_to (reference value)
278 {
279 return iterator (&value);
280 }
281
282 const_iterator iterator_to (const_reference value)
283 {
284 return const_iterator (&value);
285 }
286
287 reference front ()
288 {
289 gdb_assert (!this->empty ());
290 return *m_front;
291 }
292
293 const_reference front () const
294 {
295 gdb_assert (!this->empty ());
296 return *m_front;
297 }
298
299 reference back ()
300 {
301 gdb_assert (!this->empty ());
302 return *m_back;
303 }
304
305 const_reference back () const
306 {
307 gdb_assert (!this->empty ());
308 return *m_back;
309 }
310
311 void push_front (reference elem)
312 {
313 intrusive_list_node<T> *elem_node = as_node (&elem);
314
315 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
316 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
317
318 if (this->empty ())
319 this->push_empty (elem);
320 else
321 this->push_front_non_empty (elem);
322 }
323
324 void push_back (reference elem)
325 {
326 intrusive_list_node<T> *elem_node = as_node (&elem);
327
328 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
329 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
330
331 if (this->empty ())
332 this->push_empty (elem);
333 else
334 this->push_back_non_empty (elem);
335 }
336
337 /* Inserts ELEM before POS. */
338 void insert (const_iterator pos, reference elem)
339 {
340 if (this->empty ())
341 return this->push_empty (elem);
342
343 if (pos == this->begin ())
344 return this->push_front_non_empty (elem);
345
346 if (pos == this->end ())
347 return this->push_back_non_empty (elem);
348
349 intrusive_list_node<T> *elem_node = as_node (&elem);
1f08aca9 350 pointer pos_elem = &*pos;
bf809310 351 intrusive_list_node<T> *pos_node = as_node (pos_elem);
1f08aca9 352 pointer prev_elem = pos_node->prev;
bf809310
PA
353 intrusive_list_node<T> *prev_node = as_node (prev_elem);
354
355 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
356 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
357
358 elem_node->prev = prev_elem;
359 prev_node->next = &elem;
360 elem_node->next = pos_elem;
361 pos_node->prev = &elem;
362 }
363
8b6a69b2
SM
364 /* Move elements from LIST at the end of the current list. */
365 void splice (intrusive_list &&other)
366 {
367 if (other.empty ())
368 return;
369
370 if (this->empty ())
371 {
372 *this = std::move (other);
373 return;
374 }
375
376 /* [A ... B] + [C ... D] */
1f08aca9 377 pointer b_elem = m_back;
8b6a69b2 378 node_type *b_node = as_node (b_elem);
1f08aca9 379 pointer c_elem = other.m_front;
8b6a69b2 380 node_type *c_node = as_node (c_elem);
1f08aca9 381 pointer d_elem = other.m_back;
8b6a69b2
SM
382
383 b_node->next = c_elem;
384 c_node->prev = b_elem;
385 m_back = d_elem;
386
387 other.m_front = nullptr;
388 other.m_back = nullptr;
389 }
390
bf809310
PA
391 void pop_front ()
392 {
393 gdb_assert (!this->empty ());
394 erase_element (*m_front);
395 }
396
397 void pop_back ()
398 {
399 gdb_assert (!this->empty ());
400 erase_element (*m_back);
401 }
402
403private:
404 /* Push ELEM in the list, knowing the list is empty. */
1f08aca9 405 void push_empty (reference elem)
bf809310
PA
406 {
407 gdb_assert (this->empty ());
408
409 intrusive_list_node<T> *elem_node = as_node (&elem);
410
411 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
412 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
413
414 m_front = &elem;
415 m_back = &elem;
416 elem_node->prev = nullptr;
417 elem_node->next = nullptr;
418 }
419
420 /* Push ELEM at the front of the list, knowing the list is not empty. */
1f08aca9 421 void push_front_non_empty (reference elem)
bf809310
PA
422 {
423 gdb_assert (!this->empty ());
424
425 intrusive_list_node<T> *elem_node = as_node (&elem);
426 intrusive_list_node<T> *front_node = as_node (m_front);
427
428 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
429 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
430
431 elem_node->next = m_front;
432 front_node->prev = &elem;
433 elem_node->prev = nullptr;
434 m_front = &elem;
435 }
436
437 /* Push ELEM at the back of the list, knowing the list is not empty. */
1f08aca9 438 void push_back_non_empty (reference elem)
bf809310
PA
439 {
440 gdb_assert (!this->empty ());
441
442 intrusive_list_node<T> *elem_node = as_node (&elem);
443 intrusive_list_node<T> *back_node = as_node (m_back);
444
445 gdb_assert (elem_node->next == INTRUSIVE_LIST_UNLINKED_VALUE);
446 gdb_assert (elem_node->prev == INTRUSIVE_LIST_UNLINKED_VALUE);
447
448 elem_node->prev = m_back;
449 back_node->next = &elem;
450 elem_node->next = nullptr;
451 m_back = &elem;
452 }
453
1f08aca9 454 void erase_element (reference elem)
bf809310
PA
455 {
456 intrusive_list_node<T> *elem_node = as_node (&elem);
457
458 gdb_assert (elem_node->prev != INTRUSIVE_LIST_UNLINKED_VALUE);
459 gdb_assert (elem_node->next != INTRUSIVE_LIST_UNLINKED_VALUE);
460
461 if (m_front == &elem)
462 {
463 gdb_assert (elem_node->prev == nullptr);
464 m_front = elem_node->next;
465 }
466 else
467 {
468 gdb_assert (elem_node->prev != nullptr);
469 intrusive_list_node<T> *prev_node = as_node (elem_node->prev);
470 prev_node->next = elem_node->next;
471 }
472
473 if (m_back == &elem)
474 {
475 gdb_assert (elem_node->next == nullptr);
476 m_back = elem_node->prev;
477 }
478 else
479 {
480 gdb_assert (elem_node->next != nullptr);
481 intrusive_list_node<T> *next_node = as_node (elem_node->next);
482 next_node->prev = elem_node->prev;
483 }
484
485 elem_node->next = INTRUSIVE_LIST_UNLINKED_VALUE;
486 elem_node->prev = INTRUSIVE_LIST_UNLINKED_VALUE;
487 }
488
489public:
490 /* Remove the element pointed by I from the list. The element
491 pointed by I is not destroyed. */
492 iterator erase (const_iterator i)
493 {
494 iterator ret = i;
495 ++ret;
496
497 erase_element (*i);
498
499 return ret;
500 }
501
502 /* Erase all the elements. The elements are not destroyed. */
503 void clear ()
504 {
505 while (!this->empty ())
506 pop_front ();
507 }
508
509 /* Erase all the elements. Disposer::operator()(pointer) is called
510 for each of the removed elements. */
511 template<typename Disposer>
512 void clear_and_dispose (Disposer disposer)
513 {
514 while (!this->empty ())
515 {
516 pointer p = &front ();
517 pop_front ();
518 disposer (p);
519 }
520 }
521
522 bool empty () const
523 {
524 return m_front == nullptr;
525 }
526
527 iterator begin () noexcept
528 {
529 return iterator (m_front);
530 }
531
532 const_iterator begin () const noexcept
533 {
534 return const_iterator (m_front);
535 }
536
537 const_iterator cbegin () const noexcept
538 {
539 return const_iterator (m_front);
540 }
541
542 iterator end () noexcept
543 {
544 return {};
545 }
546
547 const_iterator end () const noexcept
548 {
549 return {};
550 }
551
552 const_iterator cend () const noexcept
553 {
554 return {};
555 }
556
557 reverse_iterator rbegin () noexcept
558 {
559 return reverse_iterator (m_back);
560 }
561
562 const_reverse_iterator rbegin () const noexcept
563 {
564 return const_reverse_iterator (m_back);
565 }
566
567 const_reverse_iterator crbegin () const noexcept
568 {
569 return const_reverse_iterator (m_back);
570 }
571
572 reverse_iterator rend () noexcept
573 {
574 return {};
575 }
576
577 const_reverse_iterator rend () const noexcept
578 {
579 return {};
580 }
581
582 const_reverse_iterator crend () const noexcept
583 {
584 return {};
585 }
586
587private:
1f08aca9 588 static node_type *as_node (pointer elem)
bf809310
PA
589 {
590 return AsNode::as_node (elem);
591 }
592
1f08aca9
SM
593 pointer m_front = nullptr;
594 pointer m_back = nullptr;
bf809310
PA
595};
596
597#endif /* GDBSUPPORT_INTRUSIVE_LIST_H */