File indexing completed on 2025-01-30 09:34:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_CONTAINER_ADAPTIVE_POOL_HPP
0012 #define BOOST_CONTAINER_ADAPTIVE_POOL_HPP
0013
0014 #ifndef BOOST_CONFIG_HPP
0015 # include <boost/config.hpp>
0016 #endif
0017
0018 #if defined(BOOST_HAS_PRAGMA_ONCE)
0019 # pragma once
0020 #endif
0021
0022 #include <boost/container/detail/config_begin.hpp>
0023 #include <boost/container/detail/workaround.hpp>
0024 #include <boost/container/container_fwd.hpp>
0025 #include <boost/container/detail/version_type.hpp>
0026 #include <boost/container/throw_exception.hpp>
0027 #include <boost/container/detail/adaptive_node_pool.hpp>
0028 #include <boost/container/detail/multiallocation_chain.hpp>
0029 #include <boost/container/detail/mpl.hpp>
0030 #include <boost/container/detail/dlmalloc.hpp>
0031 #include <boost/container/detail/singleton.hpp>
0032 #include <boost/container/detail/placement_new.hpp>
0033
0034 #include <boost/move/detail/force_ptr.hpp>
0035
0036 #include <boost/assert.hpp>
0037 #include <boost/static_assert.hpp>
0038 #include <boost/move/utility_core.hpp>
0039 #include <cstddef>
0040
0041
0042 namespace boost {
0043 namespace container {
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 template < class T
0059 , std::size_t NodesPerBlock BOOST_CONTAINER_DOCONLY(= ADP_nodes_per_block)
0060 , std::size_t MaxFreeBlocks BOOST_CONTAINER_DOCONLY(= ADP_max_free_blocks)
0061 , std::size_t OverheadPercent BOOST_CONTAINER_DOCONLY(= ADP_overhead_percent)
0062 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I unsigned Version)
0063 >
0064 class adaptive_pool
0065 {
0066
0067
0068 public:
0069 typedef unsigned int allocation_type;
0070 typedef adaptive_pool
0071 <T, NodesPerBlock, MaxFreeBlocks, OverheadPercent
0072 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)
0073 > self_t;
0074
0075 static const std::size_t nodes_per_block = NodesPerBlock;
0076 static const std::size_t max_free_blocks = MaxFreeBlocks;
0077 static const std::size_t overhead_percent = OverheadPercent;
0078 static const std::size_t real_nodes_per_block = NodesPerBlock;
0079
0080 BOOST_CONTAINER_DOCIGN(BOOST_STATIC_ASSERT((Version <=2)));
0081
0082 public:
0083
0084 typedef T value_type;
0085 typedef T * pointer;
0086 typedef const T * const_pointer;
0087 typedef typename ::boost::container::
0088 dtl::unvoid_ref<T>::type reference;
0089 typedef typename ::boost::container::
0090 dtl::unvoid_ref<const T>::type const_reference;
0091 typedef std::size_t size_type;
0092 typedef std::ptrdiff_t difference_type;
0093
0094 typedef boost::container::dtl::
0095 version_type<self_t, Version> version;
0096
0097 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
0098 typedef boost::container::dtl::
0099 basic_multiallocation_chain<void*> multiallocation_chain_void;
0100 typedef boost::container::dtl::
0101 transform_multiallocation_chain
0102 <multiallocation_chain_void, T> multiallocation_chain;
0103 #endif
0104
0105
0106
0107 template<class T2>
0108 struct rebind
0109 {
0110 typedef adaptive_pool
0111 < T2
0112 , NodesPerBlock
0113 , MaxFreeBlocks
0114 , OverheadPercent
0115 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)
0116 > other;
0117 };
0118
0119 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
0120 private:
0121
0122 template<class T2, std::size_t N2, std::size_t F2, std::size_t O2, unsigned Version2>
0123 adaptive_pool& operator=
0124 (const adaptive_pool<T2, N2, F2, O2, Version2>&);
0125
0126 #endif
0127
0128 public:
0129
0130 adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW
0131 {}
0132
0133
0134 adaptive_pool(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0135 {}
0136
0137
0138 adaptive_pool & operator=(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0139 { return *this; }
0140
0141
0142 template<class T2>
0143 adaptive_pool
0144 (const adaptive_pool<T2, NodesPerBlock, MaxFreeBlocks, OverheadPercent
0145 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)> &) BOOST_NOEXCEPT_OR_NOTHROW
0146 {}
0147
0148
0149 ~adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW
0150 {}
0151
0152
0153
0154 size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW
0155 { return size_type(-1)/(2u*sizeof(T)); }
0156
0157
0158
0159 pointer allocate(size_type count, const void * = 0)
0160 {
0161 if(BOOST_UNLIKELY(count > size_type(-1)/(2u*sizeof(T))))
0162 boost::container::throw_bad_alloc();
0163
0164 if(Version == 1 && count == 1){
0165 typedef typename dtl::shared_adaptive_node_pool
0166 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0167 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0168 return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
0169 }
0170 else{
0171 return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T)));
0172 }
0173 }
0174
0175
0176
0177 void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW
0178 {
0179 (void)count;
0180 if(Version == 1 && count == 1){
0181 typedef dtl::shared_adaptive_node_pool
0182 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0183 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0184 singleton_t::instance().deallocate_node(ptr);
0185 }
0186 else{
0187 dlmalloc_free(ptr);
0188 }
0189 }
0190
0191 pointer allocation_command(allocation_type command,
0192 size_type limit_size,
0193 size_type &prefer_in_recvd_out_size,
0194 pointer &reuse)
0195 {
0196 pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);
0197 if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)))
0198 boost::container::throw_bad_alloc();
0199 return ret;
0200 }
0201
0202
0203
0204 size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW
0205 { return dlmalloc_size(p); }
0206
0207
0208
0209
0210 pointer allocate_one()
0211 {
0212 typedef dtl::shared_adaptive_node_pool
0213 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0214 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0215 return (pointer)singleton_t::instance().allocate_node();
0216 }
0217
0218
0219
0220 void allocate_individual(std::size_t num_elements, multiallocation_chain &chain)
0221 {
0222 typedef dtl::shared_adaptive_node_pool
0223 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0224 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0225 singleton_t::instance().allocate_nodes(num_elements, static_cast<typename shared_pool_t::multiallocation_chain&>(chain));
0226
0227
0228
0229
0230 }
0231
0232
0233
0234
0235 void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW
0236 {
0237 typedef dtl::shared_adaptive_node_pool
0238 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0239 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0240 singleton_t::instance().deallocate_node(p);
0241 }
0242
0243 void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
0244 {
0245 typedef dtl::shared_adaptive_node_pool
0246 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0247 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0248
0249
0250 singleton_t::instance().deallocate_nodes(chain);
0251 }
0252
0253
0254
0255 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain)
0256 {
0257 BOOST_STATIC_ASSERT(( Version > 1 ));
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes
0268 ( n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
0269 , move_detail::force_ptr<dlmalloc_memchain *>(&chain)))){
0270 boost::container::throw_bad_alloc();
0271 }
0272 }
0273
0274
0275
0276 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
0277 {
0278 BOOST_STATIC_ASSERT(( Version > 1 ));
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays
0289 ( n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
0290 , move_detail::force_ptr<dlmalloc_memchain *>(&chain)))){
0291 boost::container::throw_bad_alloc();
0292 }
0293 }
0294
0295 void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
0296 {
0297
0298
0299
0300
0301
0302 dlmalloc_multidealloc(move_detail::force_ptr<dlmalloc_memchain *>(&chain));
0303 }
0304
0305
0306 static void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW
0307 {
0308 typedef dtl::shared_adaptive_node_pool
0309 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> shared_pool_t;
0310 typedef dtl::singleton_default<shared_pool_t> singleton_t;
0311 singleton_t::instance().deallocate_free_blocks();
0312 }
0313
0314
0315
0316 friend void swap(adaptive_pool &, adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0317 {}
0318
0319
0320
0321 friend bool operator==(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0322 { return true; }
0323
0324
0325
0326 friend bool operator!=(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0327 { return false; }
0328
0329 private:
0330 pointer priv_allocation_command
0331 (allocation_type command, std::size_t limit_size
0332 ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr)
0333 {
0334 std::size_t const preferred_size = prefer_in_recvd_out_size;
0335 dlmalloc_command_ret_t ret = {0 , 0};
0336 if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){
0337 return pointer();
0338 }
0339 std::size_t l_size = limit_size*sizeof(T);
0340 std::size_t p_size = preferred_size*sizeof(T);
0341 std::size_t r_size;
0342 {
0343 void* reuse_ptr_void = reuse_ptr;
0344 ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
0345 reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
0346 }
0347 prefer_in_recvd_out_size = r_size/sizeof(T);
0348 return (pointer)ret.first;
0349 }
0350 };
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371 template < class T
0372 , std::size_t NodesPerBlock = ADP_nodes_per_block
0373 , std::size_t MaxFreeBlocks = ADP_max_free_blocks
0374 , std::size_t OverheadPercent = ADP_overhead_percent
0375 , unsigned Version = 2
0376 >
0377 class private_adaptive_pool
0378 {
0379
0380
0381 public:
0382 typedef unsigned int allocation_type;
0383 typedef private_adaptive_pool
0384 <T, NodesPerBlock, MaxFreeBlocks, OverheadPercent
0385 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)
0386 > self_t;
0387
0388 static const std::size_t nodes_per_block = NodesPerBlock;
0389 static const std::size_t max_free_blocks = MaxFreeBlocks;
0390 static const std::size_t overhead_percent = OverheadPercent;
0391 static const std::size_t real_nodes_per_block = NodesPerBlock;
0392
0393 BOOST_CONTAINER_DOCIGN(BOOST_STATIC_ASSERT((Version <=2)));
0394
0395 typedef dtl::private_adaptive_node_pool
0396 <sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> pool_t;
0397 pool_t m_pool;
0398
0399 public:
0400
0401 typedef T value_type;
0402 typedef T * pointer;
0403 typedef const T * const_pointer;
0404 typedef typename ::boost::container::
0405 dtl::unvoid_ref<T>::type reference;
0406 typedef typename ::boost::container::
0407 dtl::unvoid_ref<const T>::type const_reference;
0408 typedef std::size_t size_type;
0409 typedef std::ptrdiff_t difference_type;
0410
0411 typedef boost::container::dtl::
0412 version_type<self_t, Version> version;
0413
0414 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
0415 typedef boost::container::dtl::
0416 basic_multiallocation_chain<void*> multiallocation_chain_void;
0417 typedef boost::container::dtl::
0418 transform_multiallocation_chain
0419 <multiallocation_chain_void, T> multiallocation_chain;
0420 #endif
0421
0422
0423
0424 template<class T2>
0425 struct rebind
0426 {
0427 typedef private_adaptive_pool
0428 < T2
0429 , NodesPerBlock
0430 , MaxFreeBlocks
0431 , OverheadPercent
0432 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)
0433 > other;
0434 };
0435
0436 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
0437 private:
0438
0439 template<class T2, std::size_t N2, std::size_t F2, std::size_t O2, unsigned Version2>
0440 private_adaptive_pool& operator=
0441 (const private_adaptive_pool<T2, N2, F2, O2, Version2>&);
0442 #endif
0443
0444 public:
0445
0446 private_adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW
0447 {}
0448
0449
0450 private_adaptive_pool(const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0451 {}
0452
0453
0454 private_adaptive_pool & operator=(const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0455 { return *this; }
0456
0457
0458 template<class T2>
0459 private_adaptive_pool
0460 (const private_adaptive_pool<T2, NodesPerBlock, MaxFreeBlocks, OverheadPercent
0461 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version)> &) BOOST_NOEXCEPT_OR_NOTHROW
0462 {}
0463
0464
0465 ~private_adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW
0466 {}
0467
0468
0469
0470 size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW
0471 { return size_type(-1)/(2u*sizeof(T)); }
0472
0473
0474
0475 pointer allocate(size_type count, const void * = 0)
0476 {
0477 if(BOOST_UNLIKELY(count > size_type(-1)/(2u*sizeof(T))))
0478 boost::container::throw_bad_alloc();
0479
0480 if(Version == 1 && count == 1){
0481 return pointer(static_cast<T*>(m_pool.allocate_node()));
0482 }
0483 else{
0484 return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T)));
0485 }
0486 }
0487
0488
0489
0490 void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW
0491 {
0492 (void)count;
0493 if(Version == 1 && count == 1){
0494 m_pool.deallocate_node(ptr);
0495 }
0496 else{
0497 dlmalloc_free(ptr);
0498 }
0499 }
0500
0501 pointer allocation_command(allocation_type command,
0502 size_type limit_size,
0503 size_type &prefer_in_recvd_out_size,
0504 pointer &reuse)
0505 {
0506 pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);
0507 if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)))
0508 boost::container::throw_bad_alloc();
0509 return ret;
0510 }
0511
0512
0513
0514 size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW
0515 { return dlmalloc_size(p); }
0516
0517
0518
0519
0520 pointer allocate_one()
0521 {
0522 return (pointer)m_pool.allocate_node();
0523 }
0524
0525
0526
0527 void allocate_individual(std::size_t num_elements, multiallocation_chain &chain)
0528 {
0529 m_pool.allocate_nodes(num_elements, static_cast<typename pool_t::multiallocation_chain&>(chain));
0530 }
0531
0532
0533
0534
0535 void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW
0536 {
0537 m_pool.deallocate_node(p);
0538 }
0539
0540 void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
0541 {
0542 m_pool.deallocate_nodes(chain);
0543 }
0544
0545
0546
0547 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain)
0548 {
0549 BOOST_STATIC_ASSERT(( Version > 1 ));
0550 if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes
0551 ( n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
0552 , move_detail::force_ptr<dlmalloc_memchain *>(&chain)))){
0553 boost::container::throw_bad_alloc();
0554 }
0555 }
0556
0557
0558
0559 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
0560 {
0561 BOOST_STATIC_ASSERT(( Version > 1 ));
0562 if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays
0563 (n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
0564 , move_detail::force_ptr<dlmalloc_memchain *>(&chain)))){
0565 boost::container::throw_bad_alloc();
0566 }
0567 }
0568
0569 void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
0570 {
0571 dlmalloc_multidealloc(move_detail::force_ptr<dlmalloc_memchain *>(&chain));
0572 }
0573
0574
0575 void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW
0576 {
0577 m_pool.deallocate_free_blocks();
0578 }
0579
0580
0581
0582 friend void swap(private_adaptive_pool &, private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0583 {}
0584
0585
0586
0587 friend bool operator==(const private_adaptive_pool &, const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0588 { return true; }
0589
0590
0591
0592 friend bool operator!=(const private_adaptive_pool &, const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW
0593 { return false; }
0594
0595 private:
0596 pointer priv_allocation_command
0597 (allocation_type command, std::size_t limit_size
0598 ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr)
0599 {
0600 std::size_t const preferred_size = prefer_in_recvd_out_size;
0601 dlmalloc_command_ret_t ret = {0 , 0};
0602 if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){
0603 return pointer();
0604 }
0605 std::size_t l_size = limit_size*sizeof(T);
0606 std::size_t p_size = preferred_size*sizeof(T);
0607 std::size_t r_size;
0608 {
0609 void* reuse_ptr_void = reuse_ptr;
0610 ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
0611 reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
0612 }
0613 prefer_in_recvd_out_size = r_size/sizeof(T);
0614 return (pointer)ret.first;
0615 }
0616 };
0617
0618 }
0619 }
0620
0621 #include <boost/container/detail/config_end.hpp>
0622
0623 #endif