intrusive_list.h 14 KB

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