1 /* Intrusive double linked list for GDB, the GNU debugger. 2 Copyright (C) 2021-2023 Free Software Foundation, Inc. 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. */ 26 template<typename T> 27 class intrusive_list_node 28 { 29 public: 30 bool is_linked () const 31 { 32 return next != INTRUSIVE_LIST_UNLINKED_VALUE; 33 } 34 35 private: 36 T *next = INTRUSIVE_LIST_UNLINKED_VALUE; 37 T *prev = INTRUSIVE_LIST_UNLINKED_VALUE; 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; 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 56 template<typename T> 57 struct 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 65 template<typename T, intrusive_list_node<T> T::*MemberNode> 66 struct 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 74 template<typename T, typename AsNode, typename SelfType> 75 struct 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. */ 89 explicit intrusive_list_base_iterator (T *elem) 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 110 protected: 111 static node_type *as_node (T *elem) 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 120 template<typename T, typename AsNode = intrusive_base_node<T>> 121 struct 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 167 template<typename T, typename AsNode = intrusive_base_node<T>> 168 struct 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 228 template <typename T, typename AsNode = intrusive_base_node<T>> 229 class intrusive_list 230 { 231 public: 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); 350 T *pos_elem = &*pos; 351 intrusive_list_node<T> *pos_node = as_node (pos_elem); 352 T *prev_elem = pos_node->prev; 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 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] */ 377 T *b_elem = m_back; 378 node_type *b_node = as_node (b_elem); 379 T *c_elem = other.m_front; 380 node_type *c_node = as_node (c_elem); 381 T *d_elem = other.m_back; 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 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 403 private: 404 /* Push ELEM in the list, knowing the list is empty. */ 405 void push_empty (T &elem) 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. */ 421 void push_front_non_empty (T &elem) 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. */ 438 void push_back_non_empty (T &elem) 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 454 void erase_element (T &elem) 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 489 public: 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 587 private: 588 static node_type *as_node (T *elem) 589 { 590 return AsNode::as_node (elem); 591 } 592 593 T *m_front = nullptr; 594 T *m_back = nullptr; 595 }; 596 597 #endif /* GDBSUPPORT_INTRUSIVE_LIST_H */ 598