PageRenderTime 51ms CodeModel.GetById 12ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/interprocess/containers/container/detail/node_alloc_holder.hpp

http://hadesmem.googlecode.com/
C++ Header | 501 lines | 382 code | 100 blank | 19 comment | 10 complexity | 7100dabc29478b7ce1612767676588e7 MD5 | raw file
  1//////////////////////////////////////////////////////////////////////////////
  2//
  3// (C) Copyright Ion Gaztanaga 2005-2009. 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//////////////////////////////////////////////////////////////////////////////
 10
 11#ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
 12#define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
 13
 14#if (defined _MSC_VER) && (_MSC_VER >= 1200)
 15#  pragma once
 16#endif
 17
 18#include "config_begin.hpp"
 19#include INCLUDE_BOOST_CONTAINER_DETAIL_WORKAROUND_HPP
 20
 21#include <utility>
 22#include <functional>
 23
 24#include INCLUDE_BOOST_CONTAINER_MOVE_HPP
 25#include <boost/intrusive/options.hpp>
 26
 27#include INCLUDE_BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP
 28#include INCLUDE_BOOST_CONTAINER_DETAIL_TYPE_TRAITS_HPP
 29#include INCLUDE_BOOST_CONTAINER_DETAIL_UTILITIES_HPP
 30#include INCLUDE_BOOST_CONTAINER_DETAIL_MPL_HPP
 31#include INCLUDE_BOOST_CONTAINER_DETAIL_DESTROYERS_HPP
 32
 33#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
 34#include INCLUDE_BOOST_CONTAINER_DETAIL_PREPROCESSOR_HPP
 35#endif
 36
 37#include INCLUDE_BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP
 38
 39
 40namespace boost {
 41namespace container {
 42namespace containers_detail {
 43
 44//!A deleter for scoped_ptr that deallocates the memory
 45//!allocated for an object using a STL allocator.
 46template <class Allocator>
 47struct scoped_deallocator
 48{
 49   typedef typename Allocator::pointer pointer;
 50   typedef containers_detail::integral_constant<unsigned,
 51      boost::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;
 55
 56   private:
 57   void priv_deallocate(allocator_v1)
 58   {  m_alloc.deallocate(m_ptr, 1); }
 59
 60   void priv_deallocate(allocator_v2)
 61   {  m_alloc.deallocate_one(m_ptr); }
 62
 63   BOOST_MOVE_MACRO_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator)
 64
 65   public:
 66
 67   pointer     m_ptr;
 68   Allocator&  m_alloc;
 69
 70   scoped_deallocator(pointer p, Allocator& a)
 71      : m_ptr(p), m_alloc(a)
 72   {}
 73
 74   ~scoped_deallocator()
 75   {  if (m_ptr)priv_deallocate(alloc_version());  }
 76
 77   scoped_deallocator(BOOST_MOVE_MACRO_RV_REF(scoped_deallocator) o)
 78      :  m_ptr(o.m_ptr), m_alloc(o.m_alloc)
 79   {  o.release();  }
 80
 81   pointer get() const
 82   {  return m_ptr;  }
 83
 84   void release()
 85   {  m_ptr = 0; }
 86};
 87
 88template <class A>
 89class allocator_destroyer_and_chain_builder
 90{
 91   typedef typename A::value_type value_type;
 92   typedef typename A::multiallocation_chain    multiallocation_chain;
 93
 94   A & a_;
 95   multiallocation_chain &c_;
 96
 97   public:
 98   allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c)
 99      :  a_(a), c_(c)
100   {}
101
102   void operator()(const typename A::pointer &p)
103   {  
104      value_type *vp = containers_detail::get_pointer(p);
105      vp->~value_type();
106      c_.push_front(vp);
107   }
108};
109
110template <class A>
111class allocator_multialloc_chain_node_deallocator
112{
113   typedef typename A::value_type value_type;
114   typedef typename A::multiallocation_chain    multiallocation_chain;
115   typedef allocator_destroyer_and_chain_builder<A> chain_builder;
116
117   A & a_;
118   multiallocation_chain c_;
119
120   public:
121   allocator_multialloc_chain_node_deallocator(A &a)
122      :  a_(a), c_()
123   {}
124
125   chain_builder get_chain_builder()
126   {  return chain_builder(a_, c_);  }
127
128   ~allocator_multialloc_chain_node_deallocator()
129   {
130      if(!c_.empty())
131         a_.deallocate_individual(BOOST_CONTAINER_MOVE_NAMESPACE::move(c_));
132   }
133};
134
135
136template<class ValueCompare, class Node>
137struct node_compare
138   :  private ValueCompare
139{
140   typedef typename ValueCompare::key_type     key_type;
141   typedef typename ValueCompare::value_type   value_type;
142   typedef typename ValueCompare::key_of_value key_of_value;
143
144   node_compare(const ValueCompare &pred)
145      :  ValueCompare(pred)
146   {}
147
148   ValueCompare &value_comp()
149   {  return static_cast<ValueCompare &>(*this);  }
150
151   ValueCompare &value_comp() const
152   {  return static_cast<const ValueCompare &>(*this);  }
153
154   bool operator()(const Node &a, const Node &b) const
155   {  return ValueCompare::operator()(a.get_data(), b.get_data());  }
156};
157
158template<class A, class ICont>
159struct node_alloc_holder
160{
161   typedef node_alloc_holder<A, ICont>                self_t;
162   typedef typename A::value_type                     value_type;
163   typedef typename ICont::value_type                 Node;
164   typedef typename A::template rebind<Node>::other   NodeAlloc;
165   typedef A                                          ValAlloc;
166   typedef typename NodeAlloc::pointer                NodePtr;
167   typedef containers_detail::scoped_deallocator<NodeAlloc>      Deallocator;
168   typedef typename NodeAlloc::size_type              size_type;
169   typedef typename NodeAlloc::difference_type        difference_type;
170   typedef containers_detail::integral_constant<unsigned, 1>     allocator_v1;
171   typedef containers_detail::integral_constant<unsigned, 2>     allocator_v2;
172   typedef containers_detail::integral_constant<unsigned,
173      boost::container::containers_detail::
174         version<NodeAlloc>::value>                   alloc_version;
175   typedef typename ICont::iterator                   icont_iterator;
176   typedef typename ICont::const_iterator             icont_citerator;
177   typedef allocator_destroyer<NodeAlloc>             Destroyer;
178
179   private:
180   BOOST_MOVE_MACRO_COPYABLE_AND_MOVABLE(node_alloc_holder)
181
182   public:
183
184   node_alloc_holder(const ValAlloc &a) 
185      : members_(a)
186   {}
187
188   node_alloc_holder(const node_alloc_holder &other)
189      : members_(other.node_alloc())
190   {}
191
192   node_alloc_holder(BOOST_MOVE_MACRO_RV_REF(node_alloc_holder) other)
193      : members_(BOOST_CONTAINER_MOVE_NAMESPACE::move(other.node_alloc()))
194   {  this->swap(other);  }
195
196   node_alloc_holder & operator=(BOOST_MOVE_MACRO_COPY_ASSIGN_REF(node_alloc_holder) other)
197   {  members_.assign(other.node_alloc());   }
198
199   node_alloc_holder & operator=(BOOST_MOVE_MACRO_RV_REF(node_alloc_holder) other)
200   {  members_.assign(other.node_alloc());   }
201
202   template<class Pred>
203   node_alloc_holder(const ValAlloc &a, const Pred &c) 
204      : members_(a, typename ICont::value_compare(c))
205   {}
206
207   template<class Pred>
208   node_alloc_holder(BOOST_MOVE_MACRO_RV_REF(ValAlloc) a, const Pred &c) 
209      : members_(a, typename ICont::value_compare(c))
210   {}
211
212   template<class Pred>
213   node_alloc_holder(const node_alloc_holder &other, const Pred &c)
214      : members_(other.node_alloc(), typename ICont::value_compare(c))
215   {}
216
217   ~node_alloc_holder()
218   {  this->clear(alloc_version()); }
219
220   size_type max_size() const
221   {  return this->node_alloc().max_size();  }
222
223   NodePtr allocate_one()
224   {  return this->allocate_one(alloc_version());   }
225
226   NodePtr allocate_one(allocator_v1)
227   {  return this->node_alloc().allocate(1);   }
228
229   NodePtr allocate_one(allocator_v2)
230   {  return this->node_alloc().allocate_one();   }
231
232   void deallocate_one(NodePtr p)
233   {  return this->deallocate_one(p, alloc_version());   }
234
235   void deallocate_one(NodePtr p, allocator_v1)
236   {  this->node_alloc().deallocate(p, 1);   }
237
238   void deallocate_one(NodePtr p, allocator_v2)
239   {  this->node_alloc().deallocate_one(p);   }
240
241   template<class Convertible1, class Convertible2>
242   static void construct(const NodePtr &ptr,
243      BOOST_MOVE_MACRO_RV_REF_2_TEMPL_ARGS(std::pair, Convertible1, Convertible2) value)
244   {  
245      typedef typename Node::hook_type                hook_type;
246      typedef typename Node::value_type::first_type   first_type;
247      typedef typename Node::value_type::second_type  second_type;
248      Node *nodeptr = containers_detail::get_pointer(ptr);
249
250      //Hook constructor does not throw
251      new(static_cast<hook_type*>(nodeptr))hook_type();
252      //Now construct pair members_holder
253      value_type *valueptr = &nodeptr->get_data();
254      new((void*)&valueptr->first) first_type(BOOST_CONTAINER_MOVE_NAMESPACE::move(value.first));
255      BOOST_TRY{
256         new((void*)&valueptr->second) second_type(BOOST_CONTAINER_MOVE_NAMESPACE::move(value.second));
257      }
258      BOOST_CATCH(...){
259         valueptr->first.~first_type();
260         static_cast<hook_type*>(nodeptr)->~hook_type();
261         BOOST_RETHROW
262      }
263      BOOST_CATCH_END
264   }
265
266   static void destroy(const NodePtr &ptr)
267   {  containers_detail::get_pointer(ptr)->~Node();  }
268
269   Deallocator create_node_and_deallocator()
270   {
271      return Deallocator(this->allocate_one(), this->node_alloc());
272   }
273
274   #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
275
276   template<class ...Args>
277   static void construct(const NodePtr &ptr, Args &&...args)
278   {  new((void*)containers_detail::get_pointer(ptr)) Node(BOOST_CONTAINER_MOVE_NAMESPACE::forward<Args>(args)...);  }
279
280   template<class ...Args>
281   NodePtr create_node(Args &&...args)
282   {
283      NodePtr p = this->allocate_one();
284      Deallocator node_deallocator(p, this->node_alloc());
285      self_t::construct(p, BOOST_CONTAINER_MOVE_NAMESPACE::forward<Args>(args)...);
286      node_deallocator.release();
287      return (p);
288   }
289
290   #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
291
292   static void construct(const NodePtr &ptr)
293   {  new((void*)containers_detail::get_pointer(ptr)) Node();  }
294
295   NodePtr create_node()
296   {
297      NodePtr p = this->allocate_one();
298      Deallocator node_deallocator(p, this->node_alloc());
299      self_t::construct(p);
300      node_deallocator.release();
301      return (p);
302   }
303
304   #define BOOST_PP_LOCAL_MACRO(n)                                                           \
305   template<BOOST_PP_ENUM_PARAMS(n, class P)>                                                \
306   void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
307   {                                                                                         \
308      new((void*)containers_detail::get_pointer(ptr))                                                   \
309      Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));                        \
310   }                                                                                         \
311   //!
312   #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
313   #include BOOST_PP_LOCAL_ITERATE()
314
315   #define BOOST_PP_LOCAL_MACRO(n)                                                        \
316   template<BOOST_PP_ENUM_PARAMS(n, class P)>                                             \
317   NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _))             \
318   {                                                                                      \
319      NodePtr p = this->allocate_one();                                                   \
320      Deallocator node_deallocator(p, this->node_alloc());                                \
321      self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));     \
322      node_deallocator.release();                                                         \
323      return (p);                                                                         \
324   }                                                                                      \
325   //!
326   #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
327   #include BOOST_PP_LOCAL_ITERATE()
328
329   #endif   //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
330
331   template<class It>
332   NodePtr create_node_from_it(It it)
333   {
334      NodePtr p = this->allocate_one();
335      Deallocator node_deallocator(p, this->node_alloc());
336      ::boost::container::construct_in_place(containers_detail::get_pointer(p), it);
337      node_deallocator.release();
338      return (p);
339   }
340
341   void destroy_node(NodePtr node)
342   {
343      self_t::destroy(node);
344      this->deallocate_one(node);
345   }
346
347   void swap(node_alloc_holder &x)
348   {
349      NodeAlloc& this_alloc   = this->node_alloc();
350      NodeAlloc& other_alloc  = x.node_alloc();
351
352      if (this_alloc != other_alloc){
353         containers_detail::do_swap(this_alloc, other_alloc);
354      }
355
356      this->icont().swap(x.icont());
357   }
358
359   template<class FwdIterator, class Inserter>
360   FwdIterator allocate_many_and_construct
361      (FwdIterator beg, difference_type n, Inserter inserter)
362   {
363      if(n){
364         typedef typename NodeAlloc::multiallocation_chain multiallocation_chain;
365
366         //Try to allocate memory in a single block
367         multiallocation_chain mem(this->node_alloc().allocate_individual(n));
368         int constructed = 0;
369         Node *p = 0;
370         BOOST_TRY{
371               for(difference_type i = 0; i < n; ++i, ++beg, --constructed){
372               p = containers_detail::get_pointer(mem.front());
373               mem.pop_front();
374               //This can throw
375               constructed = 0;
376               boost::container::construct_in_place(p, beg);
377               ++constructed;
378               //This can throw in some containers (predicate might throw)
379               inserter(*p);
380            }
381         }
382         BOOST_CATCH(...){
383            if(constructed){
384               this->destroy(p);
385            }
386            this->node_alloc().deallocate_individual(BOOST_CONTAINER_MOVE_NAMESPACE::move(mem));
387            BOOST_RETHROW
388         }
389         BOOST_CATCH_END
390      }
391      return beg;
392   }
393
394   void clear(allocator_v1)
395   {  this->icont().clear_and_dispose(Destroyer(this->node_alloc()));   }
396
397   void clear(allocator_v2)
398   {
399      typename NodeAlloc::multiallocation_chain chain;
400      allocator_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
401      this->icont().clear_and_dispose(builder);
402      BOOST_STATIC_ASSERT((::BOOST_CONTAINER_MOVE_NAMESPACE::is_movable<typename NodeAlloc::multiallocation_chain>::value == true));
403      if(!chain.empty())
404         this->node_alloc().deallocate_individual(BOOST_CONTAINER_MOVE_NAMESPACE::move(chain));
405   }
406
407   icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v1)
408   {  return this->icont().erase_and_dispose(first, last, Destroyer(this->node_alloc())); }
409
410   icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v2)
411   {
412      allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
413      return this->icont().erase_and_dispose(first, last, chain_holder.get_chain_builder());
414   }
415
416   template<class Key, class Comparator>
417   size_type erase_key(const Key& k, const Comparator &comp, allocator_v1)
418   {  return this->icont().erase_and_dispose(k, comp, Destroyer(this->node_alloc())); }
419
420   template<class Key, class Comparator>
421   size_type erase_key(const Key& k, const Comparator &comp, allocator_v2)
422   {
423      allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
424      return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder());
425   }
426
427   protected:
428   struct cloner
429   {
430      cloner(node_alloc_holder &holder)
431         :  m_holder(holder)
432      {}
433
434      NodePtr operator()(const Node &other) const
435      {  return m_holder.create_node(other.get_data());  }
436
437      node_alloc_holder &m_holder;
438   };
439
440   struct destroyer
441   {
442      destroyer(node_alloc_holder &holder)
443         :  m_holder(holder)
444      {}
445
446      void operator()(NodePtr n) const
447      {  m_holder.destroy_node(n);  }
448
449      node_alloc_holder &m_holder;
450   };
451
452   struct members_holder
453      :  public NodeAlloc
454   {
455      private:
456      members_holder(const members_holder&);
457
458      public:
459      template<class ConvertibleToAlloc>
460      members_holder(const ConvertibleToAlloc &c2alloc)
461         :  NodeAlloc(c2alloc)
462      {}
463
464      template<class ConvertibleToAlloc, class Pred>
465      members_holder(const ConvertibleToAlloc &c2alloc, const Pred &c)
466         :  NodeAlloc(c2alloc), m_icont(c)
467      {}
468
469      template<class ConvertibleToAlloc>
470      void assign (const ConvertibleToAlloc &c2alloc)
471      {
472         NodeAlloc::operator=(c2alloc);
473      }
474
475      //The intrusive container
476      ICont m_icont;
477   } members_;
478
479   ICont &non_const_icont() const
480   {  return const_cast<ICont&>(this->members_.m_icont);   }
481
482   ICont &icont()
483   {  return this->members_.m_icont;   }
484
485   const ICont &icont() const
486   {  return this->members_.m_icont;   }
487
488   NodeAlloc &node_alloc()
489   {  return static_cast<NodeAlloc &>(this->members_);   }
490
491   const NodeAlloc &node_alloc() const
492   {  return static_cast<const NodeAlloc &>(this->members_);   }
493};
494
495}  //namespace containers_detail {
496}  //namespace container {
497}  //namespace boost {
498
499#include INCLUDE_BOOST_CONTAINER_DETAIL_CONFIG_END_HPP
500
501#endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_