Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:12

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/container for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 #ifndef BOOST_CONTAINER_DETAIL_NODE_POOL_IMPL_HPP
0011 #define BOOST_CONTAINER_DETAIL_NODE_POOL_IMPL_HPP
0012 
0013 #ifndef BOOST_CONFIG_HPP
0014 #  include <boost/config.hpp>
0015 #endif
0016 
0017 #if defined(BOOST_HAS_PRAGMA_ONCE)
0018 #  pragma once
0019 #endif
0020 
0021 #include <boost/container/detail/config_begin.hpp>
0022 #include <boost/container/detail/workaround.hpp>
0023 #include <boost/container/container_fwd.hpp>
0024 
0025 #include <boost/container/detail/math_functions.hpp>
0026 #include <boost/container/detail/mpl.hpp>
0027 #include <boost/container/detail/pool_common.hpp>
0028 #include <boost/move/detail/to_raw_pointer.hpp>
0029 #include <boost/move/detail/force_ptr.hpp>
0030 #include <boost/container/detail/type_traits.hpp>
0031 
0032 #include <boost/intrusive/pointer_traits.hpp>
0033 #include <boost/intrusive/set.hpp>
0034 #include <boost/intrusive/slist.hpp>
0035 
0036 #include <boost/assert.hpp>
0037 #include <cstddef>
0038 
0039 namespace boost {
0040 namespace container {
0041 namespace dtl {
0042 
0043 template<class SegmentManagerBase>
0044 class private_node_pool_impl
0045 {
0046    //Non-copyable
0047    private_node_pool_impl();
0048    private_node_pool_impl(const private_node_pool_impl &);
0049    private_node_pool_impl &operator=(const private_node_pool_impl &);
0050 
0051    //A node object will hold node_t when it's not allocated
0052    public:
0053    typedef typename SegmentManagerBase::void_pointer              void_pointer;
0054    typedef typename node_slist<void_pointer>::slist_hook_t        slist_hook_t;
0055    typedef typename node_slist<void_pointer>::node_t              node_t;
0056    typedef typename node_slist<void_pointer>::node_slist_t        free_nodes_t;
0057    typedef typename SegmentManagerBase::multiallocation_chain     multiallocation_chain;
0058    typedef typename SegmentManagerBase::size_type                 size_type;
0059 
0060    private:
0061    typedef typename bi::make_slist
0062       < node_t, bi::base_hook<slist_hook_t>
0063       , bi::linear<true>
0064       , bi::constant_time_size<false> >::type      blockslist_t;
0065 
0066    static size_type get_rounded_size(size_type orig_size, size_type round_to)
0067    {  return ((orig_size-1)/round_to+1)*round_to;  }
0068 
0069    public:
0070 
0071    //!Segment manager typedef
0072    typedef SegmentManagerBase segment_manager_base_type;
0073 
0074    //!Constructor from a segment manager. Never throws
0075    private_node_pool_impl(segment_manager_base_type *segment_mngr_base, size_type node_size, size_type nodes_per_block)
0076    :  m_nodes_per_block(nodes_per_block)
0077    ,  m_real_node_size(lcm(node_size, size_type(alignment_of<node_t>::value)))
0078       //General purpose allocator
0079    ,  mp_segment_mngr_base(segment_mngr_base)
0080    ,  m_blocklist()
0081    ,  m_freelist()
0082       //Debug node count
0083    ,  m_allocated(0)
0084    {}
0085 
0086    //!Destructor. Deallocates all allocated blocks. Never throws
0087    BOOST_CONTAINER_FORCEINLINE ~private_node_pool_impl()
0088    {  this->purge_blocks();  }
0089 
0090    BOOST_CONTAINER_FORCEINLINE size_type get_real_num_node() const
0091    {  return m_nodes_per_block; }
0092 
0093    //!Returns the segment manager. Never throws
0094    BOOST_CONTAINER_FORCEINLINE segment_manager_base_type* get_segment_manager_base()const
0095    {  return boost::movelib::to_raw_pointer(mp_segment_mngr_base);  }
0096 
0097    BOOST_CONTAINER_FORCEINLINE void *allocate_node()
0098    {  return this->priv_alloc_node();  }
0099 
0100    //!Deallocates an array pointed by ptr. Never throws
0101    BOOST_CONTAINER_FORCEINLINE void deallocate_node(void *ptr)
0102    {  this->priv_dealloc_node(ptr); }
0103 
0104    //!Allocates a singly linked list of n nodes ending in null pointer.
0105    void allocate_nodes(const size_type n, multiallocation_chain &chain)
0106    {
0107       //Preallocate all needed blocks to fulfill the request
0108       size_type cur_nodes = m_freelist.size();
0109       if(cur_nodes < n){
0110          this->priv_alloc_block(((n - cur_nodes) - 1)/m_nodes_per_block + 1);
0111       }
0112 
0113       //We just iterate the needed nodes to get the last we'll erase
0114       typedef typename free_nodes_t::iterator free_iterator;
0115       free_iterator before_last_new_it = m_freelist.before_begin();
0116       for(size_type j = 0; j != n; ++j){
0117          ++before_last_new_it;
0118       }
0119 
0120       //Cache the first node of the allocated range before erasing
0121       free_iterator first_node(m_freelist.begin());
0122       free_iterator last_node (before_last_new_it);
0123 
0124       //Erase the range. Since we already have the distance, this is O(1)
0125       m_freelist.erase_after( m_freelist.before_begin()
0126                             , ++free_iterator(before_last_new_it)
0127                             , n);
0128 
0129       //Now take the last erased node and just splice it in the end
0130       //of the intrusive list that will be traversed by the multialloc iterator.
0131       chain.incorporate_after(chain.before_begin(), &*first_node, &*last_node, n);
0132       m_allocated += n;
0133    }
0134 
0135    void deallocate_nodes(multiallocation_chain &chain)
0136    {
0137       typedef typename multiallocation_chain::iterator iterator;
0138       iterator it(chain.begin()), itend(chain.end());
0139       while(it != itend){
0140          void *pElem = &*it;
0141          ++it;
0142          this->priv_dealloc_node(pElem);
0143       }
0144    }
0145 
0146    //!Deallocates all the free blocks of memory. Never throws
0147    void deallocate_free_blocks()
0148    {
0149       typedef typename free_nodes_t::iterator nodelist_iterator;
0150       typename blockslist_t::iterator bit(m_blocklist.before_begin()),
0151                                       it(m_blocklist.begin()),
0152                                       itend(m_blocklist.end());
0153       free_nodes_t backup_list;
0154       nodelist_iterator backup_list_last = backup_list.before_begin();
0155 
0156       //Execute the algorithm and get an iterator to the last value
0157       size_type blocksize = (get_rounded_size)
0158          (m_real_node_size*m_nodes_per_block, (size_type) alignment_of<node_t>::value);
0159 
0160       while(it != itend){
0161          //Collect all the nodes from the block pointed by it
0162          //and push them in the list
0163          free_nodes_t free_nodes;
0164          nodelist_iterator last_it = free_nodes.before_begin();
0165          const void *addr = get_block_from_hook(&*it, blocksize);
0166 
0167          m_freelist.remove_and_dispose_if
0168             (is_between(addr, blocksize), push_in_list(free_nodes, last_it));
0169 
0170          //If the number of nodes is equal to m_nodes_per_block
0171          //this means that the block can be deallocated
0172          if(free_nodes.size() == m_nodes_per_block){
0173             //Unlink the nodes
0174             free_nodes.clear();
0175             it = m_blocklist.erase_after(bit);
0176             mp_segment_mngr_base->deallocate((void*)addr);
0177          }
0178          //Otherwise, insert them in the backup list, since the
0179          //next "remove_if" does not need to check them again.
0180          else{
0181             //Assign the iterator to the last value if necessary
0182             if(backup_list.empty() && !m_freelist.empty()){
0183                backup_list_last = last_it;
0184             }
0185             //Transfer nodes. This is constant time.
0186             backup_list.splice_after
0187                ( backup_list.before_begin()
0188                , free_nodes
0189                , free_nodes.before_begin()
0190                , last_it
0191                , free_nodes.size());
0192             bit = it;
0193             ++it;
0194          }
0195       }
0196       //We should have removed all the nodes from the free list
0197       BOOST_ASSERT(m_freelist.empty());
0198 
0199       //Now pass all the node to the free list again
0200       m_freelist.splice_after
0201          ( m_freelist.before_begin()
0202          , backup_list
0203          , backup_list.before_begin()
0204          , backup_list_last
0205          , backup_list.size());
0206    }
0207 
0208    BOOST_CONTAINER_FORCEINLINE size_type num_free_nodes()
0209    {  return m_freelist.size();  }
0210 
0211    //!Deallocates all used memory. Precondition: all nodes allocated from this pool should
0212    //!already be deallocated. Otherwise, undefined behaviour. Never throws
0213    void purge_blocks()
0214    {
0215       //check for memory leaks
0216       BOOST_ASSERT(m_allocated==0);
0217       size_type blocksize = (get_rounded_size)
0218          (m_real_node_size*m_nodes_per_block, (size_type)alignment_of<node_t>::value);
0219 
0220       //We iterate though the NodeBlock list to free the memory
0221       while(!m_blocklist.empty()){
0222          void *addr = get_block_from_hook(&m_blocklist.front(), blocksize);
0223          m_blocklist.pop_front();
0224          mp_segment_mngr_base->deallocate((void*)addr);
0225       }
0226       //Just clear free node list
0227       m_freelist.clear();
0228    }
0229 
0230    void swap(private_node_pool_impl &other)
0231    {
0232       BOOST_ASSERT(m_nodes_per_block == other.m_nodes_per_block);
0233       BOOST_ASSERT(m_real_node_size == other.m_real_node_size);
0234       std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
0235       m_blocklist.swap(other.m_blocklist);
0236       m_freelist.swap(other.m_freelist);
0237       std::swap(m_allocated, other.m_allocated);
0238    }
0239 
0240    private:
0241 
0242    struct push_in_list
0243    {
0244       push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
0245          :  slist_(l), last_it_(it)
0246       {}
0247 
0248       void operator()(typename free_nodes_t::pointer p) const
0249       {
0250          slist_.push_front(*p);
0251          if(slist_.size() == 1){ //Cache last element
0252             ++last_it_ = slist_.begin();
0253          }
0254       }
0255 
0256       private:
0257       free_nodes_t &slist_;
0258       typename free_nodes_t::iterator &last_it_;
0259    };
0260 
0261    struct is_between
0262    {
0263       typedef typename free_nodes_t::value_type argument_type;
0264       typedef bool                              result_type;
0265 
0266       is_between(const void *addr, std::size_t size)
0267          :  beg_(static_cast<const char *>(addr)), end_(beg_+size)
0268       {}
0269 
0270       bool operator()(typename free_nodes_t::const_reference v) const
0271       {
0272          return (beg_ <= reinterpret_cast<const char *>(&v) &&
0273                  end_ >  reinterpret_cast<const char *>(&v));
0274       }
0275       private:
0276       const char *      beg_;
0277       const char *      end_;
0278    };
0279 
0280    //!Allocates one node, using single segregated storage algorithm.
0281    //!Never throws
0282    node_t *priv_alloc_node()
0283    {
0284       //If there are no free nodes we allocate a new block
0285       if (m_freelist.empty())
0286          this->priv_alloc_block(1);
0287       //We take the first free node
0288       node_t *n = (node_t*)&m_freelist.front();
0289       m_freelist.pop_front();
0290       ++m_allocated;
0291       return n;
0292    }
0293 
0294    //!Deallocates one node, using single segregated storage algorithm.
0295    //!Never throws
0296    void priv_dealloc_node(void *pElem)
0297    {
0298       //We put the node at the beginning of the free node list
0299       node_t * to_deallocate = static_cast<node_t*>(pElem);
0300       m_freelist.push_front(*to_deallocate);
0301       BOOST_ASSERT(m_allocated>0);
0302       --m_allocated;
0303    }
0304 
0305    //!Allocates several blocks of nodes. Can throw
0306    void priv_alloc_block(size_type num_blocks)
0307    {
0308       BOOST_ASSERT(num_blocks > 0);
0309       size_type blocksize =
0310          (get_rounded_size)(m_real_node_size*m_nodes_per_block, (size_type)alignment_of<node_t>::value);
0311 
0312       BOOST_CONTAINER_TRY{
0313          for(size_type i = 0; i != num_blocks; ++i){
0314             //We allocate a new NodeBlock and put it as first
0315             //element in the free Node list
0316             char *pNode = reinterpret_cast<char*>
0317                (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t)));
0318             char *pBlock = pNode;
0319             m_blocklist.push_front(get_block_hook(pBlock, blocksize));
0320 
0321             //We initialize all Nodes in Node Block to insert
0322             //them in the free Node list
0323             for(size_type j = 0; j < m_nodes_per_block; ++j, pNode += m_real_node_size){
0324                m_freelist.push_front(*new (pNode) node_t);
0325             }
0326          }
0327       }
0328       BOOST_CONTAINER_CATCH(...){
0329          //to-do: if possible, an efficient way to deallocate allocated blocks
0330          BOOST_CONTAINER_RETHROW
0331       }
0332       BOOST_CONTAINER_CATCH_END
0333    }
0334 
0335    //!Deprecated, use deallocate_free_blocks
0336    void deallocate_free_chunks()
0337    {  this->deallocate_free_blocks(); }
0338 
0339    //!Deprecated, use purge_blocks
0340    void purge_chunks()
0341    {  this->purge_blocks(); }
0342 
0343    private:
0344    //!Returns a reference to the block hook placed in the end of the block
0345    static node_t & get_block_hook (void *block, size_type blocksize)
0346    {
0347       return *move_detail::force_ptr<node_t*>(reinterpret_cast<char*>(block) + blocksize);
0348    }
0349 
0350    //!Returns the starting address of the block reference to the block hook placed in the end of the block
0351    void *get_block_from_hook (node_t *hook, size_type blocksize)
0352    {
0353       return (reinterpret_cast<char*>(hook) - blocksize);
0354    }
0355 
0356    private:
0357    typedef typename boost::intrusive::pointer_traits
0358       <void_pointer>::template rebind_pointer<segment_manager_base_type>::type   segment_mngr_base_ptr_t;
0359 
0360    const size_type m_nodes_per_block;
0361    const size_type m_real_node_size;
0362    segment_mngr_base_ptr_t mp_segment_mngr_base;   //Segment manager
0363    blockslist_t      m_blocklist;      //Intrusive container of blocks
0364    free_nodes_t      m_freelist;       //Intrusive container of free nods
0365    size_type       m_allocated;      //Used nodes for debugging
0366 };
0367 
0368 
0369 }  //namespace dtl {
0370 }  //namespace container {
0371 }  //namespace boost {
0372 
0373 #include <boost/container/detail/config_end.hpp>
0374 
0375 #endif   //#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP