dinit-ll.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #ifndef DINIT_LL_INCLUDED
  2. #define DINIT_LL_INCLUDED 1
  3. // Simple single- and doubly-linked list implementation, where the contained element includes the
  4. // list node. This allows a single item to be a member of several different kinds of list, without
  5. // requiring dynamic allocation of nodes for the different lists.
  6. //
  7. // To accomplish this without abstraction penalty, the function to retrieve the list node from the
  8. // element is specified as the second template parameter.
  9. // Doubly-linked list node:
  10. template <typename T>
  11. struct lld_node
  12. {
  13. T * next = nullptr;
  14. T * prev = nullptr;
  15. };
  16. // Singly-linked list node:
  17. template <typename T>
  18. struct lls_node
  19. {
  20. T * next = nullptr;
  21. };
  22. // Doubly-linked list implementation. The list is circular, so 'first->prev' yields the tail of
  23. // the list, though we still need to special-case the empty list (where first == nullptr).
  24. // next/prev pointers in a node are set to nullptr when the node is not linked into a list
  25. // (and are never equal to nullptr when the node is linked into a list).
  26. template <typename T, lld_node<T> &(*E)(T *)>
  27. class dlist
  28. {
  29. T * first;
  30. // E extractor;
  31. public:
  32. dlist() noexcept : first(nullptr) { }
  33. bool is_queued(T *e) noexcept
  34. {
  35. auto &node = E(e);
  36. return node.next != nullptr;
  37. }
  38. void append(T *e) noexcept
  39. {
  40. auto &node = E(e);
  41. if (first == nullptr) {
  42. first = e;
  43. node.next = e;
  44. node.prev = e;
  45. }
  46. else {
  47. node.next = first;
  48. node.prev = E(first).prev;
  49. E(E(first).prev).next = e;
  50. E(first).prev = e;
  51. }
  52. }
  53. T * tail() noexcept
  54. {
  55. if (first == nullptr) {
  56. return nullptr;
  57. }
  58. else {
  59. return E(first).prev;
  60. }
  61. }
  62. bool is_empty() noexcept
  63. {
  64. return first == nullptr;
  65. }
  66. T * pop_front() noexcept
  67. {
  68. auto r = first;
  69. auto &first_node = E(first);
  70. if (first_node.next == first) {
  71. // Only one node in the queue:
  72. first_node.next = nullptr;
  73. first_node.prev = nullptr;
  74. first = nullptr;
  75. }
  76. else {
  77. // Unlink first node:
  78. auto &node = E(first_node.next);
  79. node.prev = first_node.prev;
  80. E(node.prev).next = first_node.next;
  81. first = first_node.next;
  82. // Return original first node:
  83. first_node.next = nullptr;
  84. first_node.prev = nullptr;
  85. }
  86. return r;
  87. }
  88. void unlink(T *record) noexcept
  89. {
  90. auto &node = E(record);
  91. if (first == record) {
  92. first = node.next;
  93. if (first == record) {
  94. // unlinking the only node in the list:
  95. first = nullptr;
  96. }
  97. }
  98. E(node.next).prev = node.prev;
  99. E(node.prev).next = node.next;
  100. node.next = nullptr;
  101. node.prev = nullptr;
  102. }
  103. };
  104. // Singly-linked list implementation.
  105. template <typename T, lls_node<T> &(*E)(T *)>
  106. class slist
  107. {
  108. T * first;
  109. public:
  110. slist() noexcept : first(nullptr) { }
  111. bool is_queued(T *e) noexcept
  112. {
  113. auto &node = E(e);
  114. return node.next != nullptr || first == e;
  115. }
  116. void insert(T *e) noexcept
  117. {
  118. auto &node = E(e);
  119. node.next = first;
  120. first = e;
  121. }
  122. bool is_empty() noexcept
  123. {
  124. return first == nullptr;
  125. }
  126. T * pop_front() noexcept
  127. {
  128. T * r = first;
  129. auto &node = E(r);
  130. first = node.next;
  131. node.next = nullptr;
  132. return r;
  133. }
  134. };
  135. #endif