intrusive_list.tpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 auto intrusive_list<T>::front() -> reference {
  43. return *begin();
  44. }
  45. template <typename T>
  46. inline auto intrusive_list<T>::front() const -> const_reference {
  47. return *begin();
  48. }
  49. template <typename T>
  50. inline auto intrusive_list<T>::back() -> reference {
  51. return *--end();
  52. }
  53. template <typename T>
  54. inline auto intrusive_list<T>::back() const -> const_reference {
  55. return *--end();
  56. }
  57. template <typename T>
  58. inline auto intrusive_list<T>::begin() noexcept -> iterator {
  59. return iterator{head_};
  60. }
  61. template <typename T>
  62. inline auto intrusive_list<T>::begin() const noexcept -> const_iterator {
  63. return const_iterator{head_};
  64. }
  65. template <typename T>
  66. inline auto intrusive_list<T>::cbegin() const noexcept -> const_iterator {
  67. return const_iterator{head_};
  68. }
  69. template <typename T>
  70. inline auto intrusive_list<T>::end() noexcept -> iterator {
  71. return iterator{tail_};
  72. }
  73. template <typename T>
  74. inline auto intrusive_list<T>::end() const noexcept -> const_iterator {
  75. return const_iterator{tail_};
  76. }
  77. template <typename T>
  78. inline auto intrusive_list<T>::cend() const noexcept -> const_iterator {
  79. return const_iterator{tail_};
  80. }
  81. template <typename T>
  82. inline auto intrusive_list<T>::rbegin() -> reverse_iterator {
  83. return reverse_iterator{end()};
  84. }
  85. template <typename T>
  86. inline auto intrusive_list<T>::rbegin() const noexcept -> const_reverse_iterator {
  87. return const_reverse_iterator{end()};
  88. }
  89. template <typename T>
  90. inline auto intrusive_list<T>::crbegin() const noexcept -> const_reverse_iterator {
  91. return const_reverse_iterator{cend()};
  92. }
  93. template <typename T>
  94. inline auto intrusive_list<T>::rend() noexcept -> reverse_iterator {
  95. return reverse_iterator{begin()};
  96. }
  97. template <typename T>
  98. inline auto intrusive_list<T>::rend() const noexcept -> const_reverse_iterator {
  99. return const_reverse_iterator{begin()};
  100. }
  101. template <typename T>
  102. inline auto intrusive_list<T>::crend() const noexcept -> const_reverse_iterator {
  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 auto intrusive_list<T>::size() const noexcept -> size_type {
  111. return size_;
  112. }
  113. template <typename T>
  114. inline auto intrusive_list<T>::max_size() const noexcept -> size_type {
  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. auto intrusive_list<T>::insert(const_iterator pos, pointer value) -> iterator {
  123. node_type* n = &(value->*node_);
  124. if ( n->list_ == nullptr ) {
  125. insert_impl( pos, n );
  126. } else {
  127. throw std::logic_error{ "cannot use intrusive_list<T>::insert to perform a splice" };
  128. }
  129. return iterator{n};
  130. }
  131. template <typename T>
  132. auto intrusive_list<T>::transfer(const_iterator pos, pointer value) -> iterator {
  133. node_type* n = &(value->*node_);
  134. n->unlink( );
  135. insert_impl( pos, n );
  136. return iterator{n};
  137. }
  138. template <typename T>
  139. void intrusive_list<T>::insert_impl( const_iterator pos, node_type * n ) {
  140. link(pos.get()->prev_, n);
  141. link(n, pos.get());
  142. n->list_ = this;
  143. ++size_;
  144. }
  145. template <typename T>
  146. auto intrusive_list<T>::insert(const_iterator pos, std::initializer_list<pointer> ilist) -> iterator {
  147. for (pointer p : ilist) {
  148. insert( pos, p );
  149. }
  150. return iterator{pos.get()};
  151. }
  152. template <typename T>
  153. auto intrusive_list<T>::erase(iterator pos) -> iterator {
  154. unlink(pos.get());
  155. pos.get()->list_ = nullptr;
  156. --size_;
  157. return iterator{pos.get()->next_};
  158. }
  159. template <typename T>
  160. auto intrusive_list<T>::erase(iterator first, iterator last) -> iterator {
  161. while (first != last) {
  162. first = erase(first);
  163. }
  164. return last;
  165. }
  166. template <typename T>
  167. inline void intrusive_list<T>::push_back(pointer value) {
  168. insert(cend(), value);
  169. }
  170. template <typename T>
  171. void intrusive_list<T>::pop_back() {
  172. intrusive_node<T> *old = end_.prev_;
  173. end_.prev_ = old->prev_;
  174. unlink(old);
  175. --size_;
  176. }
  177. template <typename T>
  178. inline void intrusive_list<T>::push_front(pointer value) {
  179. insert(begin(), value);
  180. }
  181. template <typename T>
  182. inline void intrusive_list<T>::pop_front() {
  183. erase(begin());
  184. }
  185. template <typename T>
  186. void intrusive_list<T>::remove( pointer value ) {
  187. node_type* n = &(value->*node_);
  188. if (n->list_ == this) {
  189. unlink(n);
  190. --size_;
  191. }
  192. }
  193. template <typename T>
  194. template< class UnaryPredicate >
  195. void intrusive_list<T>::remove_if( UnaryPredicate pred ) {
  196. auto it = begin();
  197. while (it != end()) {
  198. pointer p = it.get()->ptr_;
  199. ++it;
  200. if (pred(p)) {
  201. remove(p);
  202. }
  203. }
  204. }
  205. template <typename T>
  206. inline void intrusive_list<T>::link(node_type* lhs, node_type* rhs) {
  207. if ( lhs ) { lhs->next_ = rhs; }
  208. rhs->prev_ = lhs;
  209. }
  210. template <typename T>
  211. inline void intrusive_list<T>::unlink(node_type* node) {
  212. if (node->next_) {
  213. node->next_->prev_ = node->prev_;
  214. }
  215. if (node->prev_) {
  216. node->prev_->next_ = node->next_;
  217. }
  218. }