fix doc example typo
[boost.git] / boost / interprocess / containers / container / detail / node_alloc_holder.hpp
blob6a5160d5b14fb28c53b3b4685fa8a1030e089105
1 //////////////////////////////////////////////////////////////////////////////
2 //
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)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
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)
15 # pragma once
16 #endif
18 #include <boost/interprocess/containers/container/detail/config_begin.hpp>
19 #include <boost/interprocess/containers/container/detail/workaround.hpp>
21 #include <utility>
22 #include <functional>
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>
35 #endif
37 #include <boost/interprocess/containers/container/detail/algorithms.hpp>
40 namespace boost {
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;
56 private:
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 &);
66 public:
68 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator)
70 pointer m_ptr;
71 Allocator& m_alloc;
73 scoped_deallocator(pointer p, Allocator& a)
74 : m_ptr(p), m_alloc(a)
77 ~scoped_deallocator()
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)
82 { o.release(); }
84 pointer get() const
85 { return m_ptr; }
87 void release()
88 { m_ptr = 0; }
91 template <class A>
92 class allocator_destroyer_and_chain_builder
94 typedef typename A::value_type value_type;
95 typedef typename A::multiallocation_chain multiallocation_chain;
97 A & a_;
98 multiallocation_chain &c_;
100 public:
101 allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c)
102 : a_(a), c_(c)
105 void operator()(const typename A::pointer &p)
107 value_type *vp = containers_detail::get_pointer(p);
108 vp->~value_type();
109 c_.push_front(vp);
113 template <class A>
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;
120 A & a_;
121 multiallocation_chain c_;
123 public:
124 allocator_multialloc_chain_node_deallocator(A &a)
125 : a_(a), c_()
128 chain_builder get_chain_builder()
129 { return chain_builder(a_, c_); }
131 ~allocator_multialloc_chain_node_deallocator()
133 if(!c_.empty())
134 a_.deallocate_individual(boost::interprocess::move(c_));
139 template<class ValueCompare, class Node>
140 struct node_compare
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)
148 : 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;
168 typedef A ValAlloc;
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;
182 private:
183 node_alloc_holder(node_alloc_holder&);
184 node_alloc_holder & operator=(node_alloc_holder&);
186 public:
187 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder)
189 node_alloc_holder(const ValAlloc &a)
190 : members_(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); }
201 template<class Pred>
202 node_alloc_holder(const ValAlloc &a, const Pred &c)
203 : members_(a, typename ICont::value_compare(c))
206 template<class Pred>
207 node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc) a, const Pred &c)
208 : members_(a, typename ICont::value_compare(c))
211 template<class Pred>
212 node_alloc_holder(const node_alloc_holder &other, const Pred &c)
213 : members_(other.node_alloc(), typename ICont::value_compare(c))
216 ~node_alloc_holder()
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> &&
244 #else
245 boost::interprocess::rv<std::pair<Convertible1, Convertible2> > &
246 #endif
247 value)
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));
259 BOOST_TRY{
260 new((void*)&valueptr->second) second_type(boost::interprocess::move(value.second));
262 BOOST_CATCH(...){
263 valueptr->first.~first_type();
264 static_cast<hook_type*>(nodeptr)->~hook_type();
265 BOOST_RETHROW
267 BOOST_CATCH_END
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();
291 return (p);
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();
305 return (p);
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(); \
327 return (p); \
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
335 template<class It>
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();
342 return (p);
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)
367 if(n){
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));
372 int constructed = 0;
373 Node *p = 0;
374 BOOST_TRY{
375 for(difference_type i = 0; i < n; ++i, ++beg, --constructed){
376 p = containers_detail::get_pointer(mem.front());
377 mem.pop_front();
378 //This can throw
379 constructed = 0;
380 boost::interprocess_container::construct_in_place(p, beg);
381 ++constructed;
382 //This can throw in some containers (predicate might throw)
383 inserter(*p);
386 BOOST_CATCH(...){
387 if(constructed){
388 this->destroy(p);
390 this->node_alloc().deallocate_individual(boost::interprocess::move(mem));
391 BOOST_RETHROW
393 BOOST_CATCH_END
395 return beg;
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));
408 if(!chain.empty())
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());
432 protected:
433 struct cloner
435 cloner(node_alloc_holder &holder)
436 : m_holder(holder)
439 NodePtr operator()(const Node &other) const
440 { return m_holder.create_node(other.get_data()); }
442 node_alloc_holder &m_holder;
445 struct destroyer
447 destroyer(node_alloc_holder &holder)
448 : m_holder(holder)
451 void operator()(NodePtr n) const
452 { m_holder.destroy_node(n); }
454 node_alloc_holder &m_holder;
457 struct members_holder
458 : public NodeAlloc
460 private:
461 members_holder(const members_holder&);
463 public:
464 template<class ConvertibleToAlloc>
465 members_holder(const ConvertibleToAlloc &c2alloc)
466 : NodeAlloc(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
474 ICont m_icont;
475 } members_;
477 ICont &non_const_icont() const
478 { return const_cast<ICont&>(this->members_.m_icont); }
480 ICont &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_