]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
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: | |
50 | node_handle()BOOST_NOEXCEPT:node(0){} | |
51 | ||
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 | ||
61 | ~node_handle() | |
62 | { | |
63 | if(!empty()){ | |
64 | delete_node(); | |
65 | destroy_allocator(); | |
66 | } | |
67 | } | |
68 | ||
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 | ||
95 | value_type& value()const{return node->value();} | |
96 | allocator_type get_allocator()const{return *allocator_ptr();} | |
97 | ||
98 | #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) | |
99 | explicit | |
100 | #endif | |
101 | 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 | |
108 | bool empty()const BOOST_NOEXCEPT{return (node==0);} | |
109 | ||
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 | ||
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 | ||
147 | node_handle(Node* node_,const allocator_type& al):node(node_) | |
148 | { | |
149 | ::new (static_cast<void*>(allocator_ptr())) allocator_type(al); | |
150 | } | |
151 | ||
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 | ||
162 | const allocator_type* allocator_ptr()const | |
163 | { | |
164 | return reinterpret_cast<const allocator_type*>(&space); | |
165 | } | |
166 | ||
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 | ||
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 | ||
180 | void move_assign_allocator(BOOST_RV_REF(node_handle) x) | |
181 | { | |
182 | *allocator_ptr()=boost::move(*x.allocator_ptr()); | |
183 | } | |
184 | ||
185 | void destroy_allocator(){allocator_ptr()->~allocator_type();} | |
186 | ||
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 | { | |
216 | insert_return_type( | |
217 | Iterator position_,bool inserted_,BOOST_RV_REF(NodeHandle) node_): | |
218 | position(position_),inserted(inserted_),node(boost::move(node_)){} | |
219 | insert_return_type(BOOST_RV_REF(insert_return_type) x): | |
220 | position(x.position),inserted(x.inserted),node(boost::move(x.node)){} | |
221 | ||
222 | 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 |