common_slist_algorithms.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2014
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. #ifndef BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP
  13. #define BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP
  14. #ifndef BOOST_CONFIG_HPP
  15. # include <boost/config.hpp>
  16. #endif
  17. #if defined(BOOST_HAS_PRAGMA_ONCE)
  18. # pragma once
  19. #endif
  20. #include <boost/intrusive/intrusive_fwd.hpp>
  21. #include <boost/intrusive/detail/workaround.hpp>
  22. #include <boost/intrusive/detail/assert.hpp>
  23. #include <boost/intrusive/detail/algo_type.hpp>
  24. #include <cstddef>
  25. namespace boost {
  26. namespace intrusive {
  27. namespace detail {
  28. template<class NodeTraits>
  29. class common_slist_algorithms
  30. {
  31. public:
  32. typedef typename NodeTraits::node node;
  33. typedef typename NodeTraits::node_ptr node_ptr;
  34. typedef typename NodeTraits::const_node_ptr const_node_ptr;
  35. typedef NodeTraits node_traits;
  36. static node_ptr get_previous_node(node_ptr p, node_ptr this_node)
  37. {
  38. for( node_ptr p_next
  39. ; this_node != (p_next = NodeTraits::get_next(p))
  40. ; p = p_next){
  41. //Logic error: possible use of linear lists with
  42. //operations only permitted with circular lists
  43. BOOST_INTRUSIVE_INVARIANT_ASSERT(p);
  44. }
  45. return p;
  46. }
  47. inline static void init(node_ptr this_node) BOOST_NOEXCEPT
  48. { NodeTraits::set_next(this_node, node_ptr()); }
  49. static bool unique(const_node_ptr this_node) BOOST_NOEXCEPT
  50. {
  51. node_ptr next = NodeTraits::get_next(this_node);
  52. return !next || next == this_node;
  53. }
  54. inline static bool inited(const_node_ptr this_node) BOOST_NOEXCEPT
  55. { return !NodeTraits::get_next(this_node); }
  56. inline static void unlink_after(node_ptr prev_node) BOOST_NOEXCEPT
  57. {
  58. const_node_ptr this_node(NodeTraits::get_next(prev_node));
  59. NodeTraits::set_next(prev_node, NodeTraits::get_next(this_node));
  60. }
  61. inline static void unlink_after(node_ptr prev_node, node_ptr last_node) BOOST_NOEXCEPT
  62. { NodeTraits::set_next(prev_node, last_node); }
  63. static void link_after(node_ptr prev_node, node_ptr this_node) BOOST_NOEXCEPT
  64. {
  65. NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node));
  66. NodeTraits::set_next(prev_node, this_node);
  67. }
  68. static void incorporate_after(node_ptr bp, node_ptr b, node_ptr be) BOOST_NOEXCEPT
  69. {
  70. node_ptr p(NodeTraits::get_next(bp));
  71. NodeTraits::set_next(bp, b);
  72. NodeTraits::set_next(be, p);
  73. }
  74. static void transfer_after(node_ptr bp, node_ptr bb, node_ptr be) BOOST_NOEXCEPT
  75. {
  76. if (bp != bb && bp != be && bb != be) {
  77. node_ptr next_b = NodeTraits::get_next(bb);
  78. node_ptr next_e = NodeTraits::get_next(be);
  79. node_ptr next_p = NodeTraits::get_next(bp);
  80. NodeTraits::set_next(bb, next_e);
  81. NodeTraits::set_next(be, next_p);
  82. NodeTraits::set_next(bp, next_b);
  83. }
  84. }
  85. struct stable_partition_info
  86. {
  87. std::size_t num_1st_partition;
  88. std::size_t num_2nd_partition;
  89. node_ptr beg_2st_partition;
  90. node_ptr new_last_node;
  91. };
  92. template<class Pred>
  93. static void stable_partition(node_ptr before_beg, node_ptr end, Pred pred, stable_partition_info &info)
  94. {
  95. node_ptr bcur = before_beg;
  96. node_ptr cur = node_traits::get_next(bcur);
  97. node_ptr new_f = end;
  98. std::size_t num1 = 0, num2 = 0;
  99. while(cur != end){
  100. if(pred(cur)){
  101. ++num1;
  102. bcur = cur;
  103. cur = node_traits::get_next(cur);
  104. }
  105. else{
  106. ++num2;
  107. node_ptr last_to_remove = bcur;
  108. new_f = cur;
  109. bcur = cur;
  110. cur = node_traits::get_next(cur);
  111. BOOST_INTRUSIVE_TRY{
  112. //Main loop
  113. while(cur != end){
  114. if(pred(cur)){ //Might throw
  115. ++num1;
  116. //Process current node
  117. node_traits::set_next(last_to_remove, cur);
  118. last_to_remove = cur;
  119. node_ptr nxt = node_traits::get_next(cur);
  120. node_traits::set_next(bcur, nxt);
  121. cur = nxt;
  122. }
  123. else{
  124. ++num2;
  125. bcur = cur;
  126. cur = node_traits::get_next(cur);
  127. }
  128. }
  129. }
  130. BOOST_INTRUSIVE_CATCH(...){
  131. node_traits::set_next(last_to_remove, new_f);
  132. BOOST_INTRUSIVE_RETHROW;
  133. }
  134. BOOST_INTRUSIVE_CATCH_END
  135. node_traits::set_next(last_to_remove, new_f);
  136. break;
  137. }
  138. }
  139. info.num_1st_partition = num1;
  140. info.num_2nd_partition = num2;
  141. info.beg_2st_partition = new_f;
  142. info.new_last_node = bcur;
  143. }
  144. //! <b>Requires</b>: f and l must be in a circular list.
  145. //!
  146. //! <b>Effects</b>: Returns the number of nodes in the range [f, l).
  147. //!
  148. //! <b>Complexity</b>: Linear
  149. //!
  150. //! <b>Throws</b>: Nothing.
  151. static std::size_t distance(const_node_ptr f, const_node_ptr l) BOOST_NOEXCEPT
  152. {
  153. const_node_ptr i(f);
  154. std::size_t result = 0;
  155. while(i != l){
  156. i = NodeTraits::get_next(i);
  157. ++result;
  158. }
  159. return result;
  160. }
  161. //! <b>Requires</b>: "disposer" must be an object function
  162. //! taking a node_ptr parameter and shouldn't throw.
  163. //!
  164. //! <b>Effects</b>: Calls
  165. //! <tt>void disposer::operator()(node_ptr)</tt> for every node of the list
  166. //! [p, e).
  167. //!
  168. //! <b>Returns</b>: The number of unlinked/disposed nodes
  169. //!
  170. //! <b>Complexity</b>: Linear to the number of element of the list.
  171. //!
  172. //! <b>Throws</b>: Nothing.
  173. template<class Disposer>
  174. static std::size_t unlink_after_and_dispose(node_ptr bb, node_ptr e, Disposer disposer) BOOST_NOEXCEPT
  175. {
  176. std::size_t n = 0u;
  177. node_ptr i = node_traits::get_next(bb);
  178. while (i != e) {
  179. node_ptr to_erase(i);
  180. i = node_traits::get_next(i);
  181. disposer(to_erase);
  182. ++n;
  183. }
  184. node_traits::set_next(bb, e);
  185. return n;
  186. }
  187. //! <b>Requires</b>: "disposer" must be an object function
  188. //! taking a node_ptr parameter and shouldn't throw.
  189. //!
  190. //! <b>Effects</b>: Calls
  191. //! <tt>void disposer::operator()(node_ptr)</tt> for every node of the list
  192. //! after p (but not for p). Works for circular or linear lists
  193. //!
  194. //! <b>Complexity</b>: Linear to the number of element of the list.
  195. //!
  196. //! <b>Throws</b>: Nothing.
  197. template<class Disposer>
  198. inline static void unlink_after_and_dispose(node_ptr bb, Disposer disposer) BOOST_NOEXCEPT
  199. {
  200. node_ptr i = node_traits::get_next(bb);
  201. node_traits::set_next(bb, node_traits::get_next(i));
  202. disposer(i);
  203. }
  204. //! <b>Requires</b>: "disposer" must be an object function
  205. //! taking a node_ptr parameter and shouldn't throw.
  206. //!
  207. //! <b>Effects</b>: Unlinks all nodes reachable from p (but not p) and calls
  208. //! <tt>void disposer::operator()(node_ptr)</tt> for every node of the list
  209. //! where p is linked.
  210. //!
  211. //! <b>Complexity</b>: Linear to the number of element of the list.
  212. //!
  213. //! <b>Throws</b>: Nothing.
  214. template<class Disposer>
  215. static std::size_t detach_and_dispose(node_ptr p, Disposer disposer) BOOST_NOEXCEPT
  216. {
  217. std::size_t n = 0;
  218. node_ptr i = node_traits::get_next(p);
  219. while ( i != p || i != node_ptr() ) {
  220. node_ptr to_erase(i);
  221. i = node_traits::get_next(i);
  222. disposer(to_erase);
  223. }
  224. node_traits::set_next(p, i);
  225. return n;
  226. }
  227. };
  228. /// @endcond
  229. } //namespace detail
  230. /// @cond
  231. template<class NodeTraits>
  232. struct get_algo<CommonSListAlgorithms, NodeTraits>
  233. {
  234. typedef detail::common_slist_algorithms<NodeTraits> type;
  235. };
  236. } //namespace intrusive
  237. } //namespace boost
  238. #endif //BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP