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