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 9 #ifndef BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP 10 #define BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ 17 #include <algorithm> 18 #include <boost/core/addressof.hpp> 19 #include <boost/detail/workaround.hpp> 20 #include <boost/move/core.hpp> 21 #include <boost/move/utility_core.hpp> 22 #include <boost/multi_index_container_fwd.hpp> 23 #include <boost/multi_index/detail/allocator_traits.hpp> 24 #include <boost/type_traits/aligned_storage.hpp> 25 #include <boost/type_traits/alignment_of.hpp> 26 #include <new> 27 28 namespace boost{ 29 30 namespace multi_index{ 31 32 namespace detail{ 33 34 /* Node handle template class following [container.node] specs. 35 */ 36 37 #include <boost/multi_index/detail/define_if_constexpr_macro.hpp> 38 39 template<typename Node,typename Allocator> 40 class node_handle 41 { 42 public: 43 typedef typename Node::value_type value_type; 44 typedef Allocator allocator_type; 45 46 private: 47 typedef allocator_traits<allocator_type> alloc_traits; 48 49 public: node_handle()50 node_handle()BOOST_NOEXCEPT:node(0){} 51 node_handle(BOOST_RV_REF (node_handle)x)52 node_handle(BOOST_RV_REF(node_handle) x)BOOST_NOEXCEPT:node(x.node) 53 { 54 if(!x.empty()){ 55 move_construct_allocator(boost::move(x)); 56 x.destroy_allocator(); 57 x.node=0; 58 } 59 } 60 ~node_handle()61 ~node_handle() 62 { 63 if(!empty()){ 64 delete_node(); 65 destroy_allocator(); 66 } 67 } 68 operator =(BOOST_RV_REF (node_handle)x)69 node_handle& operator=(BOOST_RV_REF(node_handle) x) 70 { 71 if(this!=&x){ 72 if(!empty()){ 73 delete_node(); 74 if(!x.empty()){ 75 BOOST_MULTI_INDEX_IF_CONSTEXPR( 76 alloc_traits::propagate_on_container_move_assignment::value){ 77 move_assign_allocator(boost::move(x)); 78 } 79 x.destroy_allocator(); 80 } 81 else{ 82 destroy_allocator(); 83 } 84 } 85 else if(!x.empty()){ 86 move_construct_allocator(boost::move(x)); 87 x.destroy_allocator(); 88 } 89 node=x.node; 90 x.node=0; 91 } 92 return *this; 93 } 94 value() const95 value_type& value()const{return node->value();} get_allocator() const96 allocator_type get_allocator()const{return *allocator_ptr();} 97 98 #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) 99 explicit 100 #endif operator bool() const101 operator bool()const BOOST_NOEXCEPT{return (node!=0);} 102 103 #if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=70000)&&__cplusplus<201103L 104 /* https://github.com/boostorg/config/issues/336 */ 105 #else 106 BOOST_ATTRIBUTE_NODISCARD 107 #endif empty() const108 bool empty()const BOOST_NOEXCEPT{return (node==0);} 109 swap(node_handle & x)110 void swap(node_handle& x) 111 BOOST_NOEXCEPT_IF( 112 alloc_traits::propagate_on_container_swap::value|| 113 alloc_traits::is_always_equal::value) 114 { 115 if(!empty()){ 116 if(!x.empty()){ 117 BOOST_MULTI_INDEX_IF_CONSTEXPR( 118 alloc_traits::propagate_on_container_swap::value){ 119 using std::swap; 120 swap(*allocator_ptr(),*x.allocator_ptr()); 121 } 122 } 123 else{ 124 x.move_construct_allocator(boost::move(*this)); 125 destroy_allocator(); 126 } 127 } 128 else if(!x.empty()){ 129 move_construct_allocator(boost::move(x)); 130 x.destroy_allocator(); 131 } 132 std::swap(node,x.node); 133 } 134 swap(node_handle & x,node_handle & y)135 friend void swap(node_handle& x,node_handle& y) 136 BOOST_NOEXCEPT_IF(noexcept(x.swap(y))) 137 { 138 x.swap(y); 139 } 140 141 private: 142 BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle) 143 144 template <typename,typename,typename> 145 friend class boost::multi_index::multi_index_container; 146 node_handle(Node * node_,const allocator_type & al)147 node_handle(Node* node_,const allocator_type& al):node(node_) 148 { 149 ::new (static_cast<void*>(allocator_ptr())) allocator_type(al); 150 } 151 release_node()152 void release_node() 153 { 154 if(!empty()){ 155 node=0; 156 destroy_allocator(); 157 } 158 } 159 160 #include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp> 161 allocator_ptr() const162 const allocator_type* allocator_ptr()const 163 { 164 return reinterpret_cast<const allocator_type*>(&space); 165 } 166 allocator_ptr()167 allocator_type* allocator_ptr() 168 { 169 return reinterpret_cast<allocator_type*>(&space); 170 } 171 172 #include <boost/multi_index/detail/restore_wstrict_aliasing.hpp> 173 move_construct_allocator(BOOST_RV_REF (node_handle)x)174 void move_construct_allocator(BOOST_RV_REF(node_handle) x) 175 { 176 ::new (static_cast<void*>(allocator_ptr())) 177 allocator_type(boost::move(*x.allocator_ptr())); 178 } 179 move_assign_allocator(BOOST_RV_REF (node_handle)x)180 void move_assign_allocator(BOOST_RV_REF(node_handle) x) 181 { 182 *allocator_ptr()=boost::move(*x.allocator_ptr()); 183 } 184 destroy_allocator()185 void destroy_allocator(){allocator_ptr()->~allocator_type();} 186 delete_node()187 void delete_node() 188 { 189 typedef typename rebind_alloc_for< 190 allocator_type,Node 191 >::type node_allocator; 192 typedef detail::allocator_traits<node_allocator> node_alloc_traits; 193 typedef typename node_alloc_traits::pointer node_pointer; 194 195 alloc_traits::destroy(*allocator_ptr(),boost::addressof(node->value())); 196 node_allocator nal(*allocator_ptr()); 197 node_alloc_traits::deallocate(nal,static_cast<node_pointer>(node),1); 198 } 199 200 Node* node; 201 typename aligned_storage< 202 sizeof(allocator_type), 203 alignment_of<allocator_type>::value 204 >::type space; 205 }; 206 207 #include <boost/multi_index/detail/undef_if_constexpr_macro.hpp> 208 209 /* node handle insert return type template class following 210 * [container.insert.return] specs. 211 */ 212 213 template<typename Iterator,typename NodeHandle> 214 struct insert_return_type 215 { insert_return_typeboost::multi_index::detail::insert_return_type216 insert_return_type( 217 Iterator position_,bool inserted_,BOOST_RV_REF(NodeHandle) node_): 218 position(position_),inserted(inserted_),node(boost::move(node_)){} insert_return_typeboost::multi_index::detail::insert_return_type219 insert_return_type(BOOST_RV_REF(insert_return_type) x): 220 position(x.position),inserted(x.inserted),node(boost::move(x.node)){} 221 operator =boost::multi_index::detail::insert_return_type222 insert_return_type& operator=(BOOST_RV_REF(insert_return_type) x) 223 { 224 position=x.position; 225 inserted=x.inserted; 226 node=boost::move(x.node); 227 return *this; 228 } 229 230 Iterator position; 231 bool inserted; 232 NodeHandle node; 233 234 private: 235 BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type) 236 }; 237 238 } /* namespace multi_index::detail */ 239 240 } /* namespace multi_index */ 241 242 } /* namespace boost */ 243 244 #endif 245