intrusive_list.tpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //
  2. // intrusive_list.tpp.h
  3. // intrusive_list
  4. //
  5. // Created by Sam Jaffe on 1/7/17.
  6. //
  7. #pragma once
  8. template <typename T>
  9. constexpr intrusive_list<T>::intrusive_list( node_type T::*node ) :
  10. node_(node) {
  11. }
  12. template <typename T>
  13. intrusive_list<T>::intrusive_list( std::initializer_list<pointer> ilist, node_type T::*node ) :
  14. node_(node) {
  15. assign(ilist);
  16. }
  17. template <typename T>
  18. intrusive_list<T>::~intrusive_list() {
  19. clear();
  20. }
  21. template <typename T>
  22. intrusive_list<T>& intrusive_list<T>::operator=( intrusive_list&& other ) {
  23. if ( this == & other ) return *this;
  24. clear(); // other than this, default
  25. node_ = other.node_;
  26. size_ = other.size_;
  27. head_ = other.head_;
  28. other.head_ = &other.end_;
  29. }
  30. template <typename T>
  31. inline intrusive_list<T>& intrusive_list<T>::operator=( std::initializer_list<pointer> ilist ) {
  32. assign(ilist);
  33. }
  34. template <typename T>
  35. void intrusive_list<T>::assign( std::initializer_list<pointer> ilist ) {
  36. clear();
  37. for (pointer p : ilist) {
  38. push_back(p);
  39. }
  40. }
  41. template <typename T>
  42. inline typename intrusive_list<T>::pointer intrusive_list<T>::front() {
  43. return head_->get();
  44. }
  45. template <typename T>
  46. inline typename intrusive_list<T>::const_pointer intrusive_list<T>::front() const {
  47. return head_->get();
  48. }
  49. template <typename T>
  50. inline typename intrusive_list<T>::pointer intrusive_list<T>::back() {
  51. return end_.prev_->get();
  52. }
  53. template <typename T>
  54. inline typename intrusive_list<T>::const_pointer intrusive_list<T>::back() const {
  55. return end_.prev_->get();
  56. }
  57. template <typename T>
  58. inline typename intrusive_list<T>::iterator intrusive_list<T>::begin() noexcept {
  59. return iterator{head_};
  60. }
  61. template <typename T>
  62. inline typename intrusive_list<T>::const_iterator intrusive_list<T>::begin() const noexcept {
  63. return const_iterator{head_};
  64. }
  65. template <typename T>
  66. inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cbegin() const noexcept {
  67. return const_iterator{head_};
  68. }
  69. template <typename T>
  70. inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept {
  71. return iterator{tail_};
  72. }
  73. template <typename T>
  74. inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const noexcept {
  75. return const_iterator{tail_};
  76. }
  77. template <typename T>
  78. inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cend() const noexcept {
  79. return const_iterator{tail_};
  80. }
  81. template <typename T>
  82. inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rbegin() {
  83. return reverse_iterator{end()};
  84. }
  85. template <typename T>
  86. inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rbegin() const noexcept {
  87. return const_reverse_iterator{end()};
  88. }
  89. template <typename T>
  90. inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::crbegin() const noexcept {
  91. return const_reverse_iterator{cend()};
  92. }
  93. template <typename T>
  94. inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rend() noexcept {
  95. return reverse_iterator{begin()};
  96. }
  97. template <typename T>
  98. inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rend() const noexcept {
  99. return const_reverse_iterator{begin()};
  100. }
  101. template <typename T>
  102. inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::crend() const noexcept{
  103. return const_reverse_iterator{cbegin()};
  104. }
  105. template <typename T>
  106. inline bool intrusive_list<T>::empty() const noexcept {
  107. return size() == 0;
  108. }
  109. template <typename T>
  110. inline typename intrusive_list<T>::size_type intrusive_list<T>::size() const noexcept {
  111. return size_;
  112. }
  113. template <typename T>
  114. inline typename intrusive_list<T>::size_type intrusive_list<T>::max_size() const noexcept {
  115. return std::numeric_limits<size_type>::max();
  116. }
  117. template <typename T>
  118. inline void intrusive_list<T>::clear() noexcept {
  119. erase(begin(), end());
  120. }
  121. template <typename T>
  122. typename intrusive_list<T>::iterator
  123. intrusive_list<T>::insert(const_iterator pos, pointer value) {
  124. node_type* n = &(value->*node_);
  125. if ( n->list_ == nullptr ) {
  126. insert_impl( pos, n );
  127. } else {
  128. throw std::logic_error{ "cannot use intrusive_list<T>::insert to perform a splice" };
  129. }
  130. return iterator{n};
  131. }
  132. template <typename T>
  133. typename intrusive_list<T>::iterator
  134. intrusive_list<T>::transfer(const_iterator pos, pointer value) {
  135. node_type* n = &(value->*node_);
  136. n->unlink( );
  137. insert_impl( pos, n );
  138. return iterator{n};
  139. }
  140. template <typename T>
  141. void intrusive_list<T>::insert_impl( const_iterator pos, node_type * n ) {
  142. link(pos.get()->prev_, n);
  143. link(n, pos.get());
  144. n->list_ = this;
  145. ++size_;
  146. }
  147. template <typename T>
  148. typename intrusive_list<T>::iterator
  149. intrusive_list<T>::insert(const_iterator pos, std::initializer_list<pointer> ilist) {
  150. for (pointer p : ilist) {
  151. insert( pos, p );
  152. }
  153. return iterator{pos.get()};
  154. }
  155. template <typename T>
  156. typename intrusive_list<T>::iterator intrusive_list<T>::erase(iterator pos) {
  157. unlink(pos.get());
  158. pos.get()->list_ = nullptr;
  159. --size_;
  160. return iterator{pos.get()->next_};
  161. }
  162. template <typename T>
  163. typename intrusive_list<T>::iterator intrusive_list<T>::erase(iterator first, iterator last) {
  164. while (first != last) {
  165. first = erase(first);
  166. }
  167. return last;
  168. }
  169. template <typename T>
  170. inline void intrusive_list<T>::push_back(pointer value) {
  171. insert(cend(), value);
  172. }
  173. template <typename T>
  174. void intrusive_list<T>::pop_back() {
  175. intrusive_node<T> *old = end_.prev_;
  176. end_.prev_ = old->prev_;
  177. unlink(old);
  178. --size_;
  179. }
  180. template <typename T>
  181. inline void intrusive_list<T>::push_front(pointer value) {
  182. insert(begin(), value);
  183. }
  184. template <typename T>
  185. inline void intrusive_list<T>::pop_front() {
  186. erase(begin());
  187. }
  188. template <typename T>
  189. void intrusive_list<T>::remove( pointer value ) {
  190. node_type* n = &(value->*node_);
  191. if (n->list_ == this) {
  192. unlink(n);
  193. --size_;
  194. }
  195. }
  196. template <typename T>
  197. template< class UnaryPredicate >
  198. void intrusive_list<T>::remove_if( UnaryPredicate pred ) {
  199. auto it = begin();
  200. while (it != end()) {
  201. pointer p = it.get()->ptr_;
  202. ++it;
  203. if (pred(p)) {
  204. remove(p);
  205. }
  206. }
  207. }
  208. template <typename T>
  209. inline void intrusive_list<T>::link(node_type* lhs, node_type* rhs) {
  210. if ( lhs ) { lhs->next_ = rhs; }
  211. rhs->prev_ = lhs;
  212. }
  213. template <typename T>
  214. inline void intrusive_list<T>::unlink(node_type* node) {
  215. if (node->next_) {
  216. node->next_->prev_ = node->prev_;
  217. }
  218. if (node->prev_) {
  219. node->prev_->next_ = node->next_;
  220. }
  221. }