annotate DEPENDENCIES/generic/include/boost/container/detail/node_pool_impl.hpp @ 125:34e428693f5d vext

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