PageRenderTime 35ms CodeModel.GetById 11ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

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

http://hadesmem.googlecode.com/
C++ Header | 366 lines | 255 code | 51 blank | 60 comment | 20 complexity | d6e4eaf55eef94e6d6bd1bffef6ce0cf 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_CONTAINER_DETAIL_NODE_POOL_IMPL_HPP
 12#define BOOST_CONTAINER_DETAIL_NODE_POOL_IMPL_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_CONTAINER_FWD_HPP
 20#include INCLUDE_BOOST_CONTAINER_DETAIL_WORKAROUND_HPP
 21#include INCLUDE_BOOST_CONTAINER_DETAIL_UTILITIES_HPP
 22#include <boost/pointer_to_other.hpp>
 23#include <boost/intrusive/set.hpp>
 24#include <boost/intrusive/slist.hpp>
 25#include INCLUDE_BOOST_CONTAINER_DETAIL_TYPE_TRAITS_HPP
 26#include INCLUDE_BOOST_CONTAINER_DETAIL_MATH_FUNCTIONS_HPP
 27#include INCLUDE_BOOST_CONTAINER_DETAIL_MPL_HPP
 28#include INCLUDE_BOOST_CONTAINER_DETAIL_POOL_COMMON_HPP
 29#include <boost/assert.hpp>
 30#include <cstddef>
 31#include <functional>   //std::unary_function
 32
 33namespace boost {
 34namespace container {
 35namespace containers_detail {
 36
 37template<class SegmentManagerBase>
 38class private_node_pool_impl
 39{
 40   //Non-copyable
 41   private_node_pool_impl();
 42   private_node_pool_impl(const private_node_pool_impl &);
 43   private_node_pool_impl &operator=(const private_node_pool_impl &);
 44
 45   //A node object will hold node_t when it's not allocated
 46   public:
 47   typedef typename SegmentManagerBase::void_pointer              void_pointer;
 48   typedef typename node_slist<void_pointer>::slist_hook_t        slist_hook_t;
 49   typedef typename node_slist<void_pointer>::node_t              node_t;
 50   typedef typename node_slist<void_pointer>::node_slist_t        free_nodes_t;
 51   typedef typename SegmentManagerBase::multiallocation_chain     multiallocation_chain;
 52
 53   private:
 54   typedef typename bi::make_slist
 55      < node_t, bi::base_hook<slist_hook_t>
 56      , bi::linear<true>
 57      , bi::constant_time_size<false> >::type      blockslist_t;
 58   public:
 59
 60   //!Segment manager typedef
 61   typedef SegmentManagerBase segment_manager_base_type;
 62
 63   //!Constructor from a segment manager. Never throws
 64   private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_block)
 65   :  m_nodes_per_block(nodes_per_block)
 66   ,  m_real_node_size(lcm(node_size, std::size_t(alignment_of<node_t>::value)))
 67      //General purpose allocator
 68   ,  mp_segment_mngr_base(segment_mngr_base)
 69   ,  m_blocklist()
 70   ,  m_freelist()
 71      //Debug node count
 72   ,  m_allocated(0)
 73   {}
 74
 75   //!Destructor. Deallocates all allocated blocks. Never throws
 76   ~private_node_pool_impl()
 77   {  this->purge_blocks();  }
 78
 79   std::size_t get_real_num_node() const
 80   {  return m_nodes_per_block; }
 81
 82   //!Returns the segment manager. Never throws
 83   segment_manager_base_type* get_segment_manager_base()const
 84   {  return containers_detail::get_pointer(mp_segment_mngr_base);  }
 85
 86   void *allocate_node()
 87   {  return priv_alloc_node();  }
 88   
 89   //!Deallocates an array pointed by ptr. Never throws
 90   void deallocate_node(void *ptr)
 91   {  priv_dealloc_node(ptr); }
 92
 93   //!Allocates a singly linked list of n nodes ending in null pointer. 
 94   multiallocation_chain allocate_nodes(const std::size_t n)
 95   {
 96      //Preallocate all needed blocks to fulfill the request
 97      std::size_t cur_nodes = m_freelist.size();
 98      if(cur_nodes < n){
 99         priv_alloc_block(((n - cur_nodes) - 1)/m_nodes_per_block + 1);
100      }
101
102      //We just iterate the needed nodes to get the last we'll erase
103      typedef typename free_nodes_t::iterator free_iterator;
104      free_iterator before_last_new_it = m_freelist.before_begin();
105      for(std::size_t j = 0; j != n; ++j){
106         ++before_last_new_it;
107      }
108
109      //Cache the first node of the allocated range before erasing
110      free_iterator first_node(m_freelist.begin());
111      free_iterator last_node (before_last_new_it);
112
113      //Erase the range. Since we already have the distance, this is O(1)
114      m_freelist.erase_after( m_freelist.before_begin()
115                            , ++free_iterator(before_last_new_it)
116                            , n);
117
118      //Now take the last erased node and just splice it in the end
119      //of the intrusive list that will be traversed by the multialloc iterator.
120      multiallocation_chain chain;
121      chain.incorporate_after(chain.before_begin(), &*first_node, &*last_node, n);
122      m_allocated += n;
123      return BOOST_CONTAINER_MOVE_NAMESPACE::move(chain);
124   }
125
126   void deallocate_nodes(multiallocation_chain chain)
127   {
128      typedef typename multiallocation_chain::iterator iterator;
129      iterator it(chain.begin()), itend(chain.end());
130      while(it != itend){
131         void *pElem = &*it;
132         ++it;
133         priv_dealloc_node(pElem);
134      }
135   }
136
137   //!Deallocates all the free blocks of memory. Never throws
138   void deallocate_free_blocks()
139   {
140      typedef typename free_nodes_t::iterator nodelist_iterator;
141      typename blockslist_t::iterator bit(m_blocklist.before_begin()),
142                                      it(m_blocklist.begin()),
143                                      itend(m_blocklist.end());
144      free_nodes_t backup_list;
145      nodelist_iterator backup_list_last = backup_list.before_begin();
146
147      //Execute the algorithm and get an iterator to the last value
148      std::size_t blocksize = get_rounded_size
149         (m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
150
151      while(it != itend){
152         //Collect all the nodes from the block pointed by it
153         //and push them in the list
154         free_nodes_t free_nodes;
155         nodelist_iterator last_it = free_nodes.before_begin();
156         const void *addr = get_block_from_hook(&*it, blocksize);
157
158         m_freelist.remove_and_dispose_if
159            (is_between(addr, blocksize), push_in_list(free_nodes, last_it));
160
161         //If the number of nodes is equal to m_nodes_per_block
162         //this means that the block can be deallocated
163         if(free_nodes.size() == m_nodes_per_block){
164            //Unlink the nodes
165            free_nodes.clear();
166            it = m_blocklist.erase_after(bit);
167            mp_segment_mngr_base->deallocate((void*)addr);
168         }
169         //Otherwise, insert them in the backup list, since the
170         //next "remove_if" does not need to check them again.
171         else{
172            //Assign the iterator to the last value if necessary
173            if(backup_list.empty() && !m_freelist.empty()){
174               backup_list_last = last_it;
175            }
176            //Transfer nodes. This is constant time.
177            backup_list.splice_after
178               ( backup_list.before_begin()
179               , free_nodes
180               , free_nodes.before_begin()
181               , last_it
182               , free_nodes.size());
183            bit = it;
184            ++it;
185         }
186      }
187      //We should have removed all the nodes from the free list
188      BOOST_ASSERT(m_freelist.empty());
189
190      //Now pass all the node to the free list again
191      m_freelist.splice_after
192         ( m_freelist.before_begin()
193         , backup_list
194         , backup_list.before_begin()
195         , backup_list_last
196         , backup_list.size());
197   }
198
199   std::size_t num_free_nodes()
200   {  return m_freelist.size();  }
201
202   //!Deallocates all used memory. Precondition: all nodes allocated from this pool should
203   //!already be deallocated. Otherwise, undefined behaviour. Never throws
204   void purge_blocks()
205   {
206      //check for memory leaks
207      BOOST_ASSERT(m_allocated==0);
208      std::size_t blocksize = get_rounded_size
209         (m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
210      typename blockslist_t::iterator
211         it(m_blocklist.begin()), itend(m_blocklist.end()), aux;
212
213      //We iterate though the NodeBlock list to free the memory
214      while(!m_blocklist.empty()){
215         void *addr = get_block_from_hook(&m_blocklist.front(), blocksize);
216         m_blocklist.pop_front();
217         mp_segment_mngr_base->deallocate((void*)addr);
218      }
219      //Just clear free node list
220      m_freelist.clear();
221   }
222
223   void swap(private_node_pool_impl &other)
224   {
225      BOOST_ASSERT(m_nodes_per_block == other.m_nodes_per_block);
226      BOOST_ASSERT(m_real_node_size == other.m_real_node_size);
227      std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
228      m_blocklist.swap(other.m_blocklist);
229      m_freelist.swap(other.m_freelist);
230      std::swap(m_allocated, other.m_allocated);
231   }
232
233   private:
234
235   struct push_in_list
236   {
237      push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
238         :  slist_(l), last_it_(it)
239      {}
240      
241      void operator()(typename free_nodes_t::pointer p) const
242      {
243         slist_.push_front(*p);
244         if(slist_.size() == 1){ //Cache last element
245            ++last_it_ = slist_.begin();
246         }
247      }
248
249      private:
250      free_nodes_t &slist_;
251      typename free_nodes_t::iterator &last_it_;
252   };
253
254   struct is_between
255      :  std::unary_function<typename free_nodes_t::value_type, bool>
256   {
257      is_between(const void *addr, std::size_t size)
258         :  beg_(static_cast<const char *>(addr)), end_(beg_+size)
259      {}
260      
261      bool operator()(typename free_nodes_t::const_reference v) const
262      {
263         return (beg_ <= reinterpret_cast<const char *>(&v) && 
264                 end_ >  reinterpret_cast<const char *>(&v));
265      }
266      private:
267      const char *      beg_;
268      const char *      end_;
269   };
270
271   //!Allocates one node, using single segregated storage algorithm.
272   //!Never throws
273   node_t *priv_alloc_node()
274   {
275      //If there are no free nodes we allocate a new block
276      if (m_freelist.empty())
277         priv_alloc_block();
278      //We take the first free node
279      node_t *n = (node_t*)&m_freelist.front();
280      m_freelist.pop_front();
281      ++m_allocated;
282      return n;
283   }
284
285   //!Deallocates one node, using single segregated storage algorithm.
286   //!Never throws
287   void priv_dealloc_node(void *pElem)
288   {
289      //We put the node at the beginning of the free node list
290      node_t * to_deallocate = static_cast<node_t*>(pElem);
291      m_freelist.push_front(*to_deallocate);
292      BOOST_ASSERT(m_allocated>0);
293      --m_allocated;
294   }
295
296   //!Allocates several blocks of nodes. Can throw
297   void priv_alloc_block(std::size_t num_blocks = 1)
298   {
299      if(!num_blocks)
300         return;
301      std::size_t blocksize = 
302         get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
303
304      try{
305         for(std::size_t i = 0; i != num_blocks; ++i){
306            //We allocate a new NodeBlock and put it as first
307            //element in the free Node list
308            char *pNode = reinterpret_cast<char*>
309               (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t)));
310            char *pBlock = pNode;
311            m_blocklist.push_front(get_block_hook(pBlock, blocksize));
312
313            //We initialize all Nodes in Node Block to insert 
314            //them in the free Node list
315            for(std::size_t i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){
316               m_freelist.push_front(*new (pNode) node_t);
317            }
318         }
319      }
320      catch(...){
321         //to-do: if possible, an efficient way to deallocate allocated blocks
322         throw;
323      }
324   }
325
326   //!Deprecated, use deallocate_free_blocks
327   void deallocate_free_chunks()
328   {  this->deallocate_free_blocks(); }
329
330   //!Deprecated, use purge_blocks
331   void purge_chunks()
332   {  this->purge_blocks(); }
333
334   private:
335   //!Returns a reference to the block hook placed in the end of the block
336   static node_t & get_block_hook (void *block, std::size_t blocksize)
337   {  
338      return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize);  
339   }
340
341   //!Returns the starting address of the block reference to the block hook placed in the end of the block
342   void *get_block_from_hook (node_t *hook, std::size_t blocksize)
343   {  
344      return (reinterpret_cast<char*>(hook) - blocksize);
345   }
346
347   private:
348   typedef typename boost::pointer_to_other
349      <void_pointer, segment_manager_base_type>::type   segment_mngr_base_ptr_t;
350
351   const std::size_t m_nodes_per_block;
352   const std::size_t m_real_node_size;
353   segment_mngr_base_ptr_t mp_segment_mngr_base;   //Segment manager
354   blockslist_t      m_blocklist;      //Intrusive container of blocks
355   free_nodes_t      m_freelist;       //Intrusive container of free nods
356   std::size_t       m_allocated;      //Used nodes for debugging
357};
358
359
360}  //namespace containers_detail {
361}  //namespace container {
362}  //namespace boost {
363
364#include INCLUDE_BOOST_CONTAINER_DETAIL_CONFIG_END_HPP
365
366#endif   //#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP