1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // See http://www.boost.org/libs/container for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
12 #define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/interprocess/containers/container/detail/config_begin.hpp>
19 #include <boost/interprocess/containers/container/detail/workaround.hpp>
24 #include <boost/interprocess/detail/move.hpp>
25 #include <boost/intrusive/options.hpp>
27 #include <boost/interprocess/containers/container/detail/version_type.hpp>
28 #include <boost/interprocess/containers/container/detail/type_traits.hpp>
29 #include <boost/interprocess/containers/container/detail/utilities.hpp>
30 #include <boost/interprocess/containers/container/detail/mpl.hpp>
31 #include <boost/interprocess/containers/container/detail/destroyers.hpp>
33 #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
34 #include <boost/interprocess/containers/container/detail/preprocessor.hpp>
37 #include <boost/interprocess/containers/container/detail/algorithms.hpp>
41 namespace interprocess_container
{
42 namespace containers_detail
{
44 //!A deleter for scoped_ptr that deallocates the memory
45 //!allocated for an object using a STL allocator.
46 template <class Allocator
>
47 struct scoped_deallocator
49 typedef typename
Allocator::pointer pointer
;
50 typedef containers_detail::integral_constant
<unsigned,
51 boost::interprocess_container::containers_detail::
52 version
<Allocator
>::value
> alloc_version
;
53 typedef containers_detail::integral_constant
<unsigned, 1> allocator_v1
;
54 typedef containers_detail::integral_constant
<unsigned, 2> allocator_v2
;
57 void priv_deallocate(allocator_v1
)
58 { m_alloc
.deallocate(m_ptr
, 1); }
60 void priv_deallocate(allocator_v2
)
61 { m_alloc
.deallocate_one(m_ptr
); }
63 scoped_deallocator(scoped_deallocator
&);
64 scoped_deallocator
& operator=(scoped_deallocator
&);
68 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator
)
73 scoped_deallocator(pointer p
, Allocator
& a
)
74 : m_ptr(p
), m_alloc(a
)
78 { if (m_ptr
)priv_deallocate(alloc_version()); }
80 scoped_deallocator(BOOST_INTERPROCESS_RV_REF(scoped_deallocator
) o
)
81 : m_ptr(o
.m_ptr
), m_alloc(o
.m_alloc
)
92 class allocator_destroyer_and_chain_builder
94 typedef typename
A::value_type value_type
;
95 typedef typename
A::multiallocation_chain multiallocation_chain
;
98 multiallocation_chain
&c_
;
101 allocator_destroyer_and_chain_builder(A
&a
, multiallocation_chain
&c
)
105 void operator()(const typename
A::pointer
&p
)
107 value_type
*vp
= containers_detail::get_pointer(p
);
114 class allocator_multialloc_chain_node_deallocator
116 typedef typename
A::value_type value_type
;
117 typedef typename
A::multiallocation_chain multiallocation_chain
;
118 typedef allocator_destroyer_and_chain_builder
<A
> chain_builder
;
121 multiallocation_chain c_
;
124 allocator_multialloc_chain_node_deallocator(A
&a
)
128 chain_builder
get_chain_builder()
129 { return chain_builder(a_
, c_
); }
131 ~allocator_multialloc_chain_node_deallocator()
134 a_
.deallocate_individual(boost::interprocess::move(c_
));
139 template<class ValueCompare
, class Node
>
141 : private ValueCompare
143 typedef typename
ValueCompare::key_type key_type
;
144 typedef typename
ValueCompare::value_type value_type
;
145 typedef typename
ValueCompare::key_of_value key_of_value
;
147 node_compare(const ValueCompare
&pred
)
151 ValueCompare
&value_comp()
152 { return static_cast<ValueCompare
&>(*this); }
154 ValueCompare
&value_comp() const
155 { return static_cast<const ValueCompare
&>(*this); }
157 bool operator()(const Node
&a
, const Node
&b
) const
158 { return ValueCompare::operator()(a
.get_data(), b
.get_data()); }
161 template<class A
, class ICont
>
162 struct node_alloc_holder
164 typedef node_alloc_holder
<A
, ICont
> self_t
;
165 typedef typename
A::value_type value_type
;
166 typedef typename
ICont::value_type Node
;
167 typedef typename
A::template rebind
<Node
>::other NodeAlloc
;
169 typedef typename
NodeAlloc::pointer NodePtr
;
170 typedef containers_detail::scoped_deallocator
<NodeAlloc
> Deallocator
;
171 typedef typename
NodeAlloc::size_type size_type
;
172 typedef typename
NodeAlloc::difference_type difference_type
;
173 typedef containers_detail::integral_constant
<unsigned, 1> allocator_v1
;
174 typedef containers_detail::integral_constant
<unsigned, 2> allocator_v2
;
175 typedef containers_detail::integral_constant
<unsigned,
176 boost::interprocess_container::containers_detail::
177 version
<NodeAlloc
>::value
> alloc_version
;
178 typedef typename
ICont::iterator icont_iterator
;
179 typedef typename
ICont::const_iterator icont_citerator
;
180 typedef allocator_destroyer
<NodeAlloc
> Destroyer
;
183 node_alloc_holder(node_alloc_holder
&);
184 node_alloc_holder
& operator=(node_alloc_holder
&);
187 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder
)
189 node_alloc_holder(const ValAlloc
&a
)
193 node_alloc_holder(const node_alloc_holder
&other
)
194 : members_(other
.node_alloc())
197 node_alloc_holder(BOOST_INTERPROCESS_RV_REF(node_alloc_holder
) other
)
198 : members_(boost::interprocess::move(other
.node_alloc()))
199 { this->swap(other
); }
202 node_alloc_holder(const ValAlloc
&a
, const Pred
&c
)
203 : members_(a
, typename
ICont::value_compare(c
))
207 node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc
) a
, const Pred
&c
)
208 : members_(a
, typename
ICont::value_compare(c
))
212 node_alloc_holder(const node_alloc_holder
&other
, const Pred
&c
)
213 : members_(other
.node_alloc(), typename
ICont::value_compare(c
))
217 { this->clear(alloc_version()); }
219 size_type
max_size() const
220 { return this->node_alloc().max_size(); }
222 NodePtr
allocate_one()
223 { return this->allocate_one(alloc_version()); }
225 NodePtr
allocate_one(allocator_v1
)
226 { return this->node_alloc().allocate(1); }
228 NodePtr
allocate_one(allocator_v2
)
229 { return this->node_alloc().allocate_one(); }
231 void deallocate_one(NodePtr p
)
232 { return this->deallocate_one(p
, alloc_version()); }
234 void deallocate_one(NodePtr p
, allocator_v1
)
235 { this->node_alloc().deallocate(p
, 1); }
237 void deallocate_one(NodePtr p
, allocator_v2
)
238 { this->node_alloc().deallocate_one(p
); }
240 template<class Convertible1
, class Convertible2
>
241 static void construct(const NodePtr
&ptr
,
242 #ifdef BOOST_HAS_RVALUE_REFS
243 std::pair
<Convertible1
, Convertible2
> &&
245 boost::interprocess::rv
<std::pair
<Convertible1
, Convertible2
> > &
249 typedef typename
Node::hook_type hook_type
;
250 typedef typename
Node::value_type::first_type first_type
;
251 typedef typename
Node::value_type::second_type second_type
;
252 Node
*nodeptr
= containers_detail::get_pointer(ptr
);
254 //Hook constructor does not throw
255 new(static_cast<hook_type
*>(nodeptr
))hook_type();
256 //Now construct pair members_holder
257 value_type
*valueptr
= &nodeptr
->get_data();
258 new((void*)&valueptr
->first
) first_type(boost::interprocess::move(value
.first
));
260 new((void*)&valueptr
->second
) second_type(boost::interprocess::move(value
.second
));
263 valueptr
->first
.~first_type();
264 static_cast<hook_type
*>(nodeptr
)->~hook_type();
270 static void destroy(const NodePtr
&ptr
)
271 { containers_detail::get_pointer(ptr
)->~Node(); }
273 Deallocator
create_node_and_deallocator()
275 return Deallocator(this->allocate_one(), this->node_alloc());
278 #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
280 template<class ...Args
>
281 static void construct(const NodePtr
&ptr
, Args
&&...args
)
282 { new((void*)containers_detail::get_pointer(ptr
)) Node(boost::interprocess::forward
<Args
>(args
)...); }
284 template<class ...Args
>
285 NodePtr
create_node(Args
&&...args
)
287 NodePtr p
= this->allocate_one();
288 Deallocator
node_deallocator(p
, this->node_alloc());
289 self_t::construct(p
, boost::interprocess::forward
<Args
>(args
)...);
290 node_deallocator
.release();
294 #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
296 static void construct(const NodePtr
&ptr
)
297 { new((void*)containers_detail::get_pointer(ptr
)) Node(); }
299 NodePtr
create_node()
301 NodePtr p
= this->allocate_one();
302 Deallocator
node_deallocator(p
, this->node_alloc());
303 self_t::construct(p
);
304 node_deallocator
.release();
308 #define BOOST_PP_LOCAL_MACRO(n) \
309 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
310 void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
312 new((void*)containers_detail::get_pointer(ptr)) \
313 Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
316 #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
317 #include BOOST_PP_LOCAL_ITERATE()
319 #define BOOST_PP_LOCAL_MACRO(n) \
320 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
321 NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
323 NodePtr p = this->allocate_one(); \
324 Deallocator node_deallocator(p, this->node_alloc()); \
325 self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
326 node_deallocator.release(); \
330 #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
331 #include BOOST_PP_LOCAL_ITERATE()
333 #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
336 NodePtr
create_node_from_it(It it
)
338 NodePtr p
= this->allocate_one();
339 Deallocator
node_deallocator(p
, this->node_alloc());
340 ::boost::interprocess_container::construct_in_place(containers_detail::get_pointer(p
), it
);
341 node_deallocator
.release();
345 void destroy_node(NodePtr node
)
347 self_t::destroy(node
);
348 this->deallocate_one(node
);
351 void swap(node_alloc_holder
&x
)
353 NodeAlloc
& this_alloc
= this->node_alloc();
354 NodeAlloc
& other_alloc
= x
.node_alloc();
356 if (this_alloc
!= other_alloc
){
357 containers_detail::do_swap(this_alloc
, other_alloc
);
360 this->icont().swap(x
.icont());
363 template<class FwdIterator
, class Inserter
>
364 FwdIterator allocate_many_and_construct
365 (FwdIterator beg
, difference_type n
, Inserter inserter
)
368 typedef typename
NodeAlloc::multiallocation_chain multiallocation_chain
;
370 //Try to allocate memory in a single block
371 multiallocation_chain
mem(this->node_alloc().allocate_individual(n
));
375 for(difference_type i
= 0; i
< n
; ++i
, ++beg
, --constructed
){
376 p
= containers_detail::get_pointer(mem
.front());
380 boost::interprocess_container::construct_in_place(p
, beg
);
382 //This can throw in some containers (predicate might throw)
390 this->node_alloc().deallocate_individual(boost::interprocess::move(mem
));
399 void clear(allocator_v1
)
400 { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); }
402 void clear(allocator_v2
)
404 typename
NodeAlloc::multiallocation_chain chain
;
405 allocator_destroyer_and_chain_builder
<NodeAlloc
> builder(this->node_alloc(), chain
);
406 this->icont().clear_and_dispose(builder
);
407 BOOST_STATIC_ASSERT((boost::interprocess::is_movable
<typename
NodeAlloc::multiallocation_chain
>::value
== true));
409 this->node_alloc().deallocate_individual(boost::interprocess::move(chain
));
412 icont_iterator
erase_range(icont_iterator first
, icont_iterator last
, allocator_v1
)
413 { return this->icont().erase_and_dispose(first
, last
, Destroyer(this->node_alloc())); }
415 icont_iterator
erase_range(icont_iterator first
, icont_iterator last
, allocator_v2
)
417 allocator_multialloc_chain_node_deallocator
<NodeAlloc
> chain_holder(this->node_alloc());
418 return this->icont().erase_and_dispose(first
, last
, chain_holder
.get_chain_builder());
421 template<class Key
, class Comparator
>
422 size_type
erase_key(const Key
& k
, const Comparator
&comp
, allocator_v1
)
423 { return this->icont().erase_and_dispose(k
, comp
, Destroyer(this->node_alloc())); }
425 template<class Key
, class Comparator
>
426 size_type
erase_key(const Key
& k
, const Comparator
&comp
, allocator_v2
)
428 allocator_multialloc_chain_node_deallocator
<NodeAlloc
> chain_holder(this->node_alloc());
429 return this->icont().erase_and_dispose(k
, comp
, chain_holder
.get_chain_builder());
435 cloner(node_alloc_holder
&holder
)
439 NodePtr
operator()(const Node
&other
) const
440 { return m_holder
.create_node(other
.get_data()); }
442 node_alloc_holder
&m_holder
;
447 destroyer(node_alloc_holder
&holder
)
451 void operator()(NodePtr n
) const
452 { m_holder
.destroy_node(n
); }
454 node_alloc_holder
&m_holder
;
457 struct members_holder
461 members_holder(const members_holder
&);
464 template<class ConvertibleToAlloc
>
465 members_holder(const ConvertibleToAlloc
&c2alloc
)
469 template<class ConvertibleToAlloc
, class Pred
>
470 members_holder(const ConvertibleToAlloc
&c2alloc
, const Pred
&c
)
471 : NodeAlloc(c2alloc
), m_icont(c
)
473 //The intrusive container
477 ICont
&non_const_icont() const
478 { return const_cast<ICont
&>(this->members_
.m_icont
); }
481 { return this->members_
.m_icont
; }
483 const ICont
&icont() const
484 { return this->members_
.m_icont
; }
486 NodeAlloc
&node_alloc()
487 { return static_cast<NodeAlloc
&>(this->members_
); }
489 const NodeAlloc
&node_alloc() const
490 { return static_cast<const NodeAlloc
&>(this->members_
); }
493 } //namespace containers_detail {
494 } //namespace interprocess_container {
495 } //namespace boost {
497 #include <boost/interprocess/containers/container/detail/config_end.hpp>
499 #endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_