File indexing completed on 2025-01-18 09:30:12
0001
0002
0003
0004
0005
0006
0007
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
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
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
0072 typedef SegmentManagerBase segment_manager_base_type;
0073
0074
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
0079 , mp_segment_mngr_base(segment_mngr_base)
0080 , m_blocklist()
0081 , m_freelist()
0082
0083 , m_allocated(0)
0084 {}
0085
0086
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
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
0101 BOOST_CONTAINER_FORCEINLINE void deallocate_node(void *ptr)
0102 { this->priv_dealloc_node(ptr); }
0103
0104
0105 void allocate_nodes(const size_type n, multiallocation_chain &chain)
0106 {
0107
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
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
0121 free_iterator first_node(m_freelist.begin());
0122 free_iterator last_node (before_last_new_it);
0123
0124
0125 m_freelist.erase_after( m_freelist.before_begin()
0126 , ++free_iterator(before_last_new_it)
0127 , n);
0128
0129
0130
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
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
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
0162
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
0171
0172 if(free_nodes.size() == m_nodes_per_block){
0173
0174 free_nodes.clear();
0175 it = m_blocklist.erase_after(bit);
0176 mp_segment_mngr_base->deallocate((void*)addr);
0177 }
0178
0179
0180 else{
0181
0182 if(backup_list.empty() && !m_freelist.empty()){
0183 backup_list_last = last_it;
0184 }
0185
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
0197 BOOST_ASSERT(m_freelist.empty());
0198
0199
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
0212
0213 void purge_blocks()
0214 {
0215
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
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
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){
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
0281
0282 node_t *priv_alloc_node()
0283 {
0284
0285 if (m_freelist.empty())
0286 this->priv_alloc_block(1);
0287
0288 node_t *n = (node_t*)&m_freelist.front();
0289 m_freelist.pop_front();
0290 ++m_allocated;
0291 return n;
0292 }
0293
0294
0295
0296 void priv_dealloc_node(void *pElem)
0297 {
0298
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
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
0315
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
0322
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
0330 BOOST_CONTAINER_RETHROW
0331 }
0332 BOOST_CONTAINER_CATCH_END
0333 }
0334
0335
0336 void deallocate_free_chunks()
0337 { this->deallocate_free_blocks(); }
0338
0339
0340 void purge_chunks()
0341 { this->purge_blocks(); }
0342
0343 private:
0344
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
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;
0363 blockslist_t m_blocklist;
0364 free_nodes_t m_freelist;
0365 size_type m_allocated;
0366 };
0367
0368
0369 }
0370 }
0371 }
0372
0373 #include <boost/container/detail/config_end.hpp>
0374
0375 #endif