tb_linklist.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_linklist.h"
  6. namespace tb {
  7. // == TBLinkListIterator ====================================================================================
  8. TBLinkListIterator::TBLinkListIterator(TBLinkList *linklist, TBLink *current_link, bool forward)
  9. : m_linklist(linklist)
  10. , m_current_link(current_link)
  11. , m_forward(forward)
  12. {
  13. Register();
  14. }
  15. TBLinkListIterator::TBLinkListIterator(const TBLinkListIterator &iter)
  16. : m_linklist(iter.m_linklist)
  17. , m_current_link(iter.m_current_link)
  18. , m_forward(iter.m_forward)
  19. {
  20. Register();
  21. }
  22. TBLinkListIterator::~TBLinkListIterator()
  23. {
  24. Unregister();
  25. }
  26. void TBLinkListIterator::Register()
  27. {
  28. m_prev = nullptr;
  29. m_next = m_linklist->first_iterator;
  30. if (m_linklist->first_iterator)
  31. m_linklist->first_iterator->m_prev = this;
  32. m_linklist->first_iterator = this;
  33. }
  34. void TBLinkListIterator::Unregister()
  35. {
  36. if (!m_linklist) // Already unregistered
  37. return;
  38. if (m_prev)
  39. m_prev->m_next = m_next;
  40. if (m_next)
  41. m_next->m_prev = m_prev;
  42. if (m_linklist->first_iterator == this)
  43. m_linklist->first_iterator = m_next;
  44. }
  45. void TBLinkListIterator::UnregisterAndClear()
  46. {
  47. Unregister();
  48. m_linklist = nullptr;
  49. m_current_link = nullptr;
  50. m_prev = nullptr;
  51. m_next = nullptr;
  52. }
  53. const TBLinkListIterator& TBLinkListIterator::operator = (const TBLinkListIterator &iter)
  54. {
  55. if (m_linklist != iter.m_linklist)
  56. {
  57. // Change where we are registered if we change linklist.
  58. Unregister();
  59. m_linklist = iter.m_linklist;
  60. Register();
  61. }
  62. m_linklist = iter.m_linklist;
  63. m_current_link = iter.m_current_link;
  64. m_forward = iter.m_forward;
  65. return *this;
  66. }
  67. void TBLinkListIterator::Reset()
  68. {
  69. if (m_linklist)
  70. m_current_link = m_forward ? m_linklist->first : m_linklist->last;
  71. else
  72. m_current_link = nullptr;
  73. }
  74. TBLink *TBLinkListIterator::GetAndStep()
  75. {
  76. if (!m_current_link)
  77. return nullptr;
  78. TBLink *current = m_current_link;
  79. m_current_link = m_forward ? m_current_link->next : m_current_link->prev;
  80. return current;
  81. }
  82. void TBLinkListIterator::RemoveLink(TBLink *link)
  83. {
  84. // If the current link is being removed, step away from it
  85. if (m_current_link == link)
  86. GetAndStep();
  87. }
  88. // == TBLinkList ============================================================================================
  89. TBLinkList::~TBLinkList()
  90. {
  91. RemoveAll();
  92. // Make sure any live iterators for this linklist are cleared!
  93. while (first_iterator)
  94. first_iterator->UnregisterAndClear();
  95. }
  96. void TBLinkList::AddFirst(TBLink *link)
  97. {
  98. assert(!link->linklist); // Link is already in some list!
  99. link->linklist = this;
  100. link->next = first;
  101. if (first)
  102. first->prev = link;
  103. first = link;
  104. if (!last)
  105. last = link;
  106. }
  107. void TBLinkList::AddLast(TBLink *link)
  108. {
  109. assert(!link->linklist); // Link is already in some list!
  110. link->linklist = this;
  111. link->prev = last;
  112. if (last)
  113. last->next = link;
  114. last = link;
  115. if (!first)
  116. first = link;
  117. }
  118. void TBLinkList::AddBefore(TBLink *link, TBLink *reference)
  119. {
  120. assert(reference->linklist == this); // Reference is not added to this list!
  121. link->linklist = this;
  122. link->prev = reference->prev;
  123. link->next = reference;
  124. if (reference->prev)
  125. reference->prev->next = link;
  126. else
  127. first = link;
  128. reference->prev = link;
  129. }
  130. void TBLinkList::AddAfter(TBLink *link, TBLink *reference)
  131. {
  132. assert(reference->linklist == this); // Reference is not added to this list!
  133. link->linklist = this;
  134. link->prev = reference;
  135. link->next = reference->next;
  136. if (reference->next)
  137. reference->next->prev = link;
  138. else
  139. last = link;
  140. reference->next = link;
  141. }
  142. void TBLinkList::Remove(TBLink *link)
  143. {
  144. assert(link->linklist == this); // Link is not added to this list!
  145. // Go through iterators and make sure there are no pointers
  146. // to the link we remove.
  147. TBLinkListIterator *iter = first_iterator;
  148. while (iter)
  149. {
  150. iter->RemoveLink(link);
  151. iter = iter->m_next;
  152. }
  153. // Remove the link
  154. if (link->next)
  155. link->next->prev = link->prev;
  156. if (link->prev)
  157. link->prev->next = link->next;
  158. if (first == link)
  159. first = link->next;
  160. if (last == link)
  161. last = link->prev;
  162. link->linklist = nullptr;
  163. link->prev = nullptr;
  164. link->next = nullptr;
  165. }
  166. void TBLinkList::RemoveAll()
  167. {
  168. // Reset all iterators.
  169. TBLinkListIterator *iter = first_iterator;
  170. while (iter)
  171. {
  172. iter->m_current_link = nullptr;
  173. iter = iter->m_next;
  174. }
  175. // Remove all links
  176. TBLink *link = first;
  177. while (link)
  178. {
  179. TBLink *next = link->next;
  180. link->linklist = nullptr;
  181. link->prev = nullptr;
  182. link->next = nullptr;
  183. link = next;
  184. }
  185. first = nullptr;
  186. last = nullptr;
  187. }
  188. int TBLinkList::CountLinks() const
  189. {
  190. int count = 0;
  191. for (TBLink *link = first; link; link = link->next)
  192. count++;
  193. return count;
  194. }
  195. }; // namespace tb