]>
Commit | Line | Data |
---|---|---|
1e59de90 | 1 | /* Copyright 2003-2021 Joaquin M Lopez Munoz. |
20effc67 TL |
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 | ||
1e59de90 TL |
28 | #if !defined(BOOST_NO_SFINAE) |
29 | #include <boost/type_traits/is_const.hpp> | |
30 | #include <boost/type_traits/is_same.hpp> | |
31 | #include <boost/utility/enable_if.hpp> | |
32 | #endif | |
33 | ||
20effc67 TL |
34 | namespace boost{ |
35 | ||
36 | namespace multi_index{ | |
37 | ||
38 | namespace detail{ | |
39 | ||
40 | /* Node handle template class following [container.node] specs. | |
41 | */ | |
42 | ||
43 | #include <boost/multi_index/detail/define_if_constexpr_macro.hpp> | |
44 | ||
45 | template<typename Node,typename Allocator> | |
46 | class node_handle | |
47 | { | |
48 | public: | |
49 | typedef typename Node::value_type value_type; | |
50 | typedef Allocator allocator_type; | |
51 | ||
52 | private: | |
53 | typedef allocator_traits<allocator_type> alloc_traits; | |
54 | ||
55 | public: | |
56 | node_handle()BOOST_NOEXCEPT:node(0){} | |
57 | ||
58 | node_handle(BOOST_RV_REF(node_handle) x)BOOST_NOEXCEPT:node(x.node) | |
59 | { | |
60 | if(!x.empty()){ | |
61 | move_construct_allocator(boost::move(x)); | |
62 | x.destroy_allocator(); | |
63 | x.node=0; | |
64 | } | |
65 | } | |
66 | ||
67 | ~node_handle() | |
68 | { | |
69 | if(!empty()){ | |
70 | delete_node(); | |
71 | destroy_allocator(); | |
72 | } | |
73 | } | |
74 | ||
75 | node_handle& operator=(BOOST_RV_REF(node_handle) x) | |
76 | { | |
77 | if(this!=&x){ | |
78 | if(!empty()){ | |
79 | delete_node(); | |
80 | if(!x.empty()){ | |
81 | BOOST_MULTI_INDEX_IF_CONSTEXPR( | |
82 | alloc_traits::propagate_on_container_move_assignment::value){ | |
83 | move_assign_allocator(boost::move(x)); | |
84 | } | |
85 | x.destroy_allocator(); | |
86 | } | |
87 | else{ | |
88 | destroy_allocator(); | |
89 | } | |
90 | } | |
91 | else if(!x.empty()){ | |
92 | move_construct_allocator(boost::move(x)); | |
93 | x.destroy_allocator(); | |
94 | } | |
95 | node=x.node; | |
96 | x.node=0; | |
97 | } | |
98 | return *this; | |
99 | } | |
100 | ||
101 | value_type& value()const{return node->value();} | |
102 | allocator_type get_allocator()const{return *allocator_ptr();} | |
103 | ||
104 | #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) | |
105 | explicit | |
106 | #endif | |
107 | operator bool()const BOOST_NOEXCEPT{return (node!=0);} | |
108 | ||
109 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=70000)&&__cplusplus<201103L | |
110 | /* https://github.com/boostorg/config/issues/336 */ | |
111 | #else | |
112 | BOOST_ATTRIBUTE_NODISCARD | |
113 | #endif | |
114 | bool empty()const BOOST_NOEXCEPT{return (node==0);} | |
115 | ||
116 | void swap(node_handle& x) | |
117 | BOOST_NOEXCEPT_IF( | |
118 | alloc_traits::propagate_on_container_swap::value|| | |
119 | alloc_traits::is_always_equal::value) | |
120 | { | |
121 | if(!empty()){ | |
122 | if(!x.empty()){ | |
123 | BOOST_MULTI_INDEX_IF_CONSTEXPR( | |
124 | alloc_traits::propagate_on_container_swap::value){ | |
125 | using std::swap; | |
126 | swap(*allocator_ptr(),*x.allocator_ptr()); | |
127 | } | |
128 | } | |
129 | else{ | |
130 | x.move_construct_allocator(boost::move(*this)); | |
131 | destroy_allocator(); | |
132 | } | |
133 | } | |
134 | else if(!x.empty()){ | |
135 | move_construct_allocator(boost::move(x)); | |
136 | x.destroy_allocator(); | |
137 | } | |
138 | std::swap(node,x.node); | |
139 | } | |
140 | ||
141 | friend void swap(node_handle& x,node_handle& y) | |
142 | BOOST_NOEXCEPT_IF(noexcept(x.swap(y))) | |
143 | { | |
144 | x.swap(y); | |
145 | } | |
146 | ||
147 | private: | |
148 | BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle) | |
149 | ||
150 | template <typename,typename,typename> | |
151 | friend class boost::multi_index::multi_index_container; | |
152 | ||
153 | node_handle(Node* node_,const allocator_type& al):node(node_) | |
154 | { | |
155 | ::new (static_cast<void*>(allocator_ptr())) allocator_type(al); | |
156 | } | |
157 | ||
158 | void release_node() | |
159 | { | |
160 | if(!empty()){ | |
161 | node=0; | |
162 | destroy_allocator(); | |
163 | } | |
164 | } | |
165 | ||
166 | #include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp> | |
167 | ||
168 | const allocator_type* allocator_ptr()const | |
169 | { | |
170 | return reinterpret_cast<const allocator_type*>(&space); | |
171 | } | |
172 | ||
173 | allocator_type* allocator_ptr() | |
174 | { | |
175 | return reinterpret_cast<allocator_type*>(&space); | |
176 | } | |
177 | ||
178 | #include <boost/multi_index/detail/restore_wstrict_aliasing.hpp> | |
179 | ||
180 | void move_construct_allocator(BOOST_RV_REF(node_handle) x) | |
181 | { | |
182 | ::new (static_cast<void*>(allocator_ptr())) | |
183 | allocator_type(boost::move(*x.allocator_ptr())); | |
184 | } | |
185 | ||
186 | void move_assign_allocator(BOOST_RV_REF(node_handle) x) | |
187 | { | |
188 | *allocator_ptr()=boost::move(*x.allocator_ptr()); | |
189 | } | |
190 | ||
191 | void destroy_allocator(){allocator_ptr()->~allocator_type();} | |
192 | ||
193 | void delete_node() | |
194 | { | |
195 | typedef typename rebind_alloc_for< | |
196 | allocator_type,Node | |
197 | >::type node_allocator; | |
198 | typedef detail::allocator_traits<node_allocator> node_alloc_traits; | |
199 | typedef typename node_alloc_traits::pointer node_pointer; | |
200 | ||
201 | alloc_traits::destroy(*allocator_ptr(),boost::addressof(node->value())); | |
202 | node_allocator nal(*allocator_ptr()); | |
203 | node_alloc_traits::deallocate(nal,static_cast<node_pointer>(node),1); | |
204 | } | |
205 | ||
206 | Node* node; | |
207 | typename aligned_storage< | |
208 | sizeof(allocator_type), | |
209 | alignment_of<allocator_type>::value | |
210 | >::type space; | |
211 | }; | |
212 | ||
213 | #include <boost/multi_index/detail/undef_if_constexpr_macro.hpp> | |
214 | ||
215 | /* node handle insert return type template class following | |
216 | * [container.insert.return] specs. | |
217 | */ | |
218 | ||
219 | template<typename Iterator,typename NodeHandle> | |
220 | struct insert_return_type | |
221 | { | |
222 | insert_return_type( | |
223 | Iterator position_,bool inserted_,BOOST_RV_REF(NodeHandle) node_): | |
224 | position(position_),inserted(inserted_),node(boost::move(node_)){} | |
225 | insert_return_type(BOOST_RV_REF(insert_return_type) x): | |
226 | position(x.position),inserted(x.inserted),node(boost::move(x.node)){} | |
227 | ||
228 | insert_return_type& operator=(BOOST_RV_REF(insert_return_type) x) | |
229 | { | |
230 | position=x.position; | |
231 | inserted=x.inserted; | |
232 | node=boost::move(x.node); | |
233 | return *this; | |
234 | } | |
235 | ||
236 | Iterator position; | |
237 | bool inserted; | |
238 | NodeHandle node; | |
239 | ||
240 | private: | |
241 | BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type) | |
242 | }; | |
243 | ||
1e59de90 TL |
244 | /* utility for SFINAEing merge and related operations */ |
245 | ||
246 | #if !defined(BOOST_NO_SFINAE) | |
247 | ||
248 | #define BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(Dst,Src,T) \ | |
249 | typename enable_if_c< \ | |
250 | !is_const< Dst >::value&&!is_const< Src >::value&& \ | |
251 | is_same<typename Dst::node_type,typename Src::node_type>::value, \ | |
252 | T \ | |
253 | >::type | |
254 | ||
255 | #else | |
256 | ||
257 | #define BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(Dst,Src,T) T | |
258 | ||
259 | #endif | |
260 | ||
20effc67 TL |
261 | } /* namespace multi_index::detail */ |
262 | ||
263 | } /* namespace multi_index */ | |
264 | ||
265 | } /* namespace boost */ | |
266 | ||
267 | #endif |