node_handle.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* Copyright 2003-2020 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/multi_index for library home page.
  7. */
  8. #ifndef BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
  14. #include <algorithm>
  15. #include <boost/core/addressof.hpp>
  16. #include <boost/detail/workaround.hpp>
  17. #include <boost/move/core.hpp>
  18. #include <boost/move/utility_core.hpp>
  19. #include <boost/multi_index_container_fwd.hpp>
  20. #include <boost/multi_index/detail/allocator_traits.hpp>
  21. #include <boost/type_traits/aligned_storage.hpp>
  22. #include <boost/type_traits/alignment_of.hpp>
  23. #include <new>
  24. namespace boost{
  25. namespace multi_index{
  26. namespace detail{
  27. /* Node handle template class following [container.node] specs.
  28. */
  29. #include <boost/multi_index/detail/define_if_constexpr_macro.hpp>
  30. template<typename Node,typename Allocator>
  31. class node_handle
  32. {
  33. public:
  34. typedef typename Node::value_type value_type;
  35. typedef Allocator allocator_type;
  36. private:
  37. typedef allocator_traits<allocator_type> alloc_traits;
  38. public:
  39. node_handle()BOOST_NOEXCEPT:node(0){}
  40. node_handle(BOOST_RV_REF(node_handle) x)BOOST_NOEXCEPT:node(x.node)
  41. {
  42. if(!x.empty()){
  43. move_construct_allocator(boost::move(x));
  44. x.destroy_allocator();
  45. x.node=0;
  46. }
  47. }
  48. ~node_handle()
  49. {
  50. if(!empty()){
  51. delete_node();
  52. destroy_allocator();
  53. }
  54. }
  55. node_handle& operator=(BOOST_RV_REF(node_handle) x)
  56. {
  57. if(this!=&x){
  58. if(!empty()){
  59. delete_node();
  60. if(!x.empty()){
  61. BOOST_MULTI_INDEX_IF_CONSTEXPR(
  62. alloc_traits::propagate_on_container_move_assignment::value){
  63. move_assign_allocator(boost::move(x));
  64. }
  65. x.destroy_allocator();
  66. }
  67. else{
  68. destroy_allocator();
  69. }
  70. }
  71. else if(!x.empty()){
  72. move_construct_allocator(boost::move(x));
  73. x.destroy_allocator();
  74. }
  75. node=x.node;
  76. x.node=0;
  77. }
  78. return *this;
  79. }
  80. value_type& value()const{return node->value();}
  81. allocator_type get_allocator()const{return *allocator_ptr();}
  82. #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
  83. explicit
  84. #endif
  85. operator bool()const BOOST_NOEXCEPT{return (node!=0);}
  86. #if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=70000)&&__cplusplus<201103L
  87. /* https://github.com/boostorg/config/issues/336 */
  88. #else
  89. BOOST_ATTRIBUTE_NODISCARD
  90. #endif
  91. bool empty()const BOOST_NOEXCEPT{return (node==0);}
  92. void swap(node_handle& x)
  93. BOOST_NOEXCEPT_IF(
  94. alloc_traits::propagate_on_container_swap::value||
  95. alloc_traits::is_always_equal::value)
  96. {
  97. if(!empty()){
  98. if(!x.empty()){
  99. BOOST_MULTI_INDEX_IF_CONSTEXPR(
  100. alloc_traits::propagate_on_container_swap::value){
  101. using std::swap;
  102. swap(*allocator_ptr(),*x.allocator_ptr());
  103. }
  104. }
  105. else{
  106. x.move_construct_allocator(boost::move(*this));
  107. destroy_allocator();
  108. }
  109. }
  110. else if(!x.empty()){
  111. move_construct_allocator(boost::move(x));
  112. x.destroy_allocator();
  113. }
  114. std::swap(node,x.node);
  115. }
  116. friend void swap(node_handle& x,node_handle& y)
  117. BOOST_NOEXCEPT_IF(noexcept(x.swap(y)))
  118. {
  119. x.swap(y);
  120. }
  121. private:
  122. BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle)
  123. template <typename,typename,typename>
  124. friend class boost::multi_index::multi_index_container;
  125. node_handle(Node* node_,const allocator_type& al):node(node_)
  126. {
  127. ::new (static_cast<void*>(allocator_ptr())) allocator_type(al);
  128. }
  129. void release_node()
  130. {
  131. if(!empty()){
  132. node=0;
  133. destroy_allocator();
  134. }
  135. }
  136. #include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
  137. const allocator_type* allocator_ptr()const
  138. {
  139. return reinterpret_cast<const allocator_type*>(&space);
  140. }
  141. allocator_type* allocator_ptr()
  142. {
  143. return reinterpret_cast<allocator_type*>(&space);
  144. }
  145. #include <boost/multi_index/detail/restore_wstrict_aliasing.hpp>
  146. void move_construct_allocator(BOOST_RV_REF(node_handle) x)
  147. {
  148. ::new (static_cast<void*>(allocator_ptr()))
  149. allocator_type(boost::move(*x.allocator_ptr()));
  150. }
  151. void move_assign_allocator(BOOST_RV_REF(node_handle) x)
  152. {
  153. *allocator_ptr()=boost::move(*x.allocator_ptr());
  154. }
  155. void destroy_allocator(){allocator_ptr()->~allocator_type();}
  156. void delete_node()
  157. {
  158. typedef typename rebind_alloc_for<
  159. allocator_type,Node
  160. >::type node_allocator;
  161. typedef detail::allocator_traits<node_allocator> node_alloc_traits;
  162. typedef typename node_alloc_traits::pointer node_pointer;
  163. alloc_traits::destroy(*allocator_ptr(),boost::addressof(node->value()));
  164. node_allocator nal(*allocator_ptr());
  165. node_alloc_traits::deallocate(nal,static_cast<node_pointer>(node),1);
  166. }
  167. Node* node;
  168. typename aligned_storage<
  169. sizeof(allocator_type),
  170. alignment_of<allocator_type>::value
  171. >::type space;
  172. };
  173. #include <boost/multi_index/detail/undef_if_constexpr_macro.hpp>
  174. /* node handle insert return type template class following
  175. * [container.insert.return] specs.
  176. */
  177. template<typename Iterator,typename NodeHandle>
  178. struct insert_return_type
  179. {
  180. insert_return_type(
  181. Iterator position_,bool inserted_,BOOST_RV_REF(NodeHandle) node_):
  182. position(position_),inserted(inserted_),node(boost::move(node_)){}
  183. insert_return_type(BOOST_RV_REF(insert_return_type) x):
  184. position(x.position),inserted(x.inserted),node(boost::move(x.node)){}
  185. insert_return_type& operator=(BOOST_RV_REF(insert_return_type) x)
  186. {
  187. position=x.position;
  188. inserted=x.inserted;
  189. node=boost::move(x.node);
  190. return *this;
  191. }
  192. Iterator position;
  193. bool inserted;
  194. NodeHandle node;
  195. private:
  196. BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type)
  197. };
  198. } /* namespace multi_index::detail */
  199. } /* namespace multi_index */
  200. } /* namespace boost */
  201. #endif