1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // See http://www.boost.org/libs/container for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #define BOOST_CONTAINER_SOURCE
12 #include <boost/container/detail/config_begin.hpp>
13 #include <boost/container/detail/workaround.hpp>
15 #include <boost/container/pmr/global_resource.hpp>
17 #include <boost/container/detail/pool_resource.hpp>
18 #include <boost/container/detail/block_slist.hpp>
19 #include <boost/container/detail/min_max.hpp>
20 #include <boost/container/detail/placement_new.hpp>
21 #include <boost/intrusive/linear_slist_algorithms.hpp>
22 #include <boost/intrusive/detail/math.hpp>
33 : public block_slist_base
<>
35 typedef block_slist_base
<> block_slist_base_t
;
38 explicit pool_data_t(std::size_t initial_blocks_per_chunk
)
39 : block_slist_base_t(), next_blocks_per_chunk(initial_blocks_per_chunk
)
40 { slist_algo::init_header(&free_slist
); }
42 void *allocate_block() BOOST_NOEXCEPT
44 if(slist_algo::unique(&free_slist
)){
47 slist_node
*pv
= slist_algo::node_traits::get_next(&free_slist
);
48 slist_algo::unlink_after(&free_slist
);
53 void deallocate_block(void *p
) BOOST_NOEXCEPT
55 slist_node
*pv
= ::new(p
, boost_container_new_t()) slist_node();
56 slist_algo::link_after(&free_slist
, pv
);
59 void release(memory_resource
&upstream
)
61 slist_algo::init_header(&free_slist
);
62 this->block_slist_base_t::release(upstream
);
63 next_blocks_per_chunk
= pool_options_minimum_max_blocks_per_chunk
;
66 void replenish(memory_resource
&mr
, std::size_t pool_block
, std::size_t max_blocks_per_chunk
)
69 std::size_t blocks_per_chunk
= boost::container::dtl::min_value(max_blocks_per_chunk
, next_blocks_per_chunk
);
71 blocks_per_chunk
= boost::container::dtl::min_value(blocks_per_chunk
, std::size_t(-1)/pool_block
);
73 //Minimum block size is at least max_align, so all pools allocate sizes that are multiple of max_align,
74 //meaning that all blocks are max_align-aligned.
75 char *p
= static_cast<char *>(block_slist_base_t::allocate(blocks_per_chunk
*pool_block
, mr
));
77 //Create header types. This is no-throw
78 for(std::size_t i
= 0, max
= blocks_per_chunk
; i
!= max
; ++i
){
79 slist_node
*const pv
= ::new(p
, boost_container_new_t()) slist_node();
80 slist_algo::link_after(&free_slist
, pv
);
84 //Update next block per chunk
85 next_blocks_per_chunk
= max_blocks_per_chunk
/2u < blocks_per_chunk
? max_blocks_per_chunk
: blocks_per_chunk
*2u;
88 std::size_t cache_count() const
89 { return slist_algo::count(&free_slist
) - 1u; }
91 slist_node free_slist
;
92 std::size_t next_blocks_per_chunk
;
97 //Detect overflow in ceil_pow2
98 BOOST_STATIC_ASSERT(pool_options_default_max_blocks_per_chunk
<= (std::size_t(-1)/2u+1u));
100 BOOST_STATIC_ASSERT(bi::detail::static_is_pow2
<pool_options_default_max_blocks_per_chunk
>::value
);
101 BOOST_STATIC_ASSERT(bi::detail::static_is_pow2
<pool_options_minimum_largest_required_pool_block
>::value
);
103 //unsynchronized_pool_resource
105 void pool_resource::priv_limit_option(std::size_t &val
, std::size_t min
, std::size_t max
) //static
111 val
= val
< min
? min
: boost::container::dtl::min_value(val
, max
);
115 std::size_t pool_resource::priv_pool_index(std::size_t block_size
) //static
117 //For allocations equal or less than pool_options_minimum_largest_required_pool_block
118 //the smallest pool is used
119 block_size
= boost::container::dtl::max_value(block_size
, pool_options_minimum_largest_required_pool_block
);
120 return bi::detail::ceil_log2(block_size
)
121 - bi::detail::ceil_log2(pool_options_minimum_largest_required_pool_block
);
124 std::size_t pool_resource::priv_pool_block(std::size_t index
) //static
126 //For allocations equal or less than pool_options_minimum_largest_required_pool_block
127 //the smallest pool is used
128 return pool_options_minimum_largest_required_pool_block
<< index
;
131 void pool_resource::priv_fix_options()
133 priv_limit_option(m_options
.max_blocks_per_chunk
134 , pool_options_minimum_max_blocks_per_chunk
135 , pool_options_default_max_blocks_per_chunk
);
137 ( m_options
.largest_required_pool_block
138 , pool_options_minimum_largest_required_pool_block
139 , pool_options_default_largest_required_pool_block
);
140 m_options
.largest_required_pool_block
= bi::detail::ceil_pow2(m_options
.largest_required_pool_block
);
143 void pool_resource::priv_init_pools()
145 const std::size_t num_pools
= priv_pool_index(m_options
.largest_required_pool_block
)+1u;
146 //Otherwise, just use the default alloc (zero pools)
149 p
= m_upstream
.allocate(sizeof(pool_data_t
)*num_pools
);
151 m_pool_data
= static_cast<pool_data_t
*>(p
);
152 for(std::size_t i
= 0, max
= num_pools
; i
!= max
; ++i
){
153 ::new(&m_pool_data
[i
], boost_container_new_t()) pool_data_t(pool_options_minimum_max_blocks_per_chunk
);
155 m_pool_count
= num_pools
;
158 void pool_resource::priv_constructor_body()
160 this->priv_fix_options();
163 pool_resource::pool_resource(const pool_options
& opts
, memory_resource
* upstream
) BOOST_NOEXCEPT
164 : m_options(opts
), m_upstream(*upstream
), m_oversized_list(), m_pool_data(), m_pool_count()
165 { this->priv_constructor_body(); }
167 pool_resource::pool_resource() BOOST_NOEXCEPT
168 : m_options(), m_upstream(*get_default_resource()), m_oversized_list(), m_pool_data(), m_pool_count()
169 { this->priv_constructor_body(); }
171 pool_resource::pool_resource(memory_resource
* upstream
) BOOST_NOEXCEPT
172 : m_options(), m_upstream(*upstream
), m_oversized_list(), m_pool_data(), m_pool_count()
173 { this->priv_constructor_body(); }
175 pool_resource::pool_resource(const pool_options
& opts
) BOOST_NOEXCEPT
176 : m_options(opts
), m_upstream(*get_default_resource()), m_oversized_list(), m_pool_data(), m_pool_count()
177 { this->priv_constructor_body(); }
179 pool_resource::~pool_resource()
183 for(std::size_t i
= 0, max
= m_pool_count
; i
!= max
; ++i
){
184 m_pool_data
[i
].~pool_data_t();
187 m_upstream
.deallocate((void*)m_pool_data
, sizeof(pool_data_t
)*m_pool_count
);
191 void pool_resource::release()
193 m_oversized_list
.release(m_upstream
);
194 for(std::size_t i
= 0, max
= m_pool_count
; i
!= max
; ++i
)
196 m_pool_data
[i
].release(m_upstream
);
200 memory_resource
* pool_resource::upstream_resource() const
201 { return &m_upstream
; }
203 pool_options
pool_resource::options() const
204 { return m_options
; }
206 void* pool_resource::do_allocate(std::size_t bytes
, std::size_t alignment
)
209 this->priv_init_pools();
211 (void)alignment
; //alignment ignored here, max_align is used by pools
212 if(bytes
> m_options
.largest_required_pool_block
){
213 return m_oversized_list
.allocate(bytes
, m_upstream
);
216 const std::size_t pool_idx
= priv_pool_index(bytes
);
217 pool_data_t
& pool
= m_pool_data
[pool_idx
];
218 void *p
= pool
.allocate_block();
220 pool
.replenish(m_upstream
, priv_pool_block(pool_idx
), m_options
.max_blocks_per_chunk
);
221 p
= pool
.allocate_block();
227 void pool_resource::do_deallocate(void* p
, std::size_t bytes
, std::size_t alignment
)
229 (void)alignment
; //alignment ignored here, max_align is used by pools
230 if(bytes
> m_options
.largest_required_pool_block
){
232 return m_oversized_list
.deallocate(p
, m_upstream
);
235 const std::size_t pool_idx
= priv_pool_index(bytes
);
236 return m_pool_data
[pool_idx
].deallocate_block(p
);
240 std::size_t pool_resource::pool_count() const
242 if(BOOST_LIKELY((0 != m_pool_data
))){
246 return priv_pool_index(m_options
.largest_required_pool_block
)+1u;
250 std::size_t pool_resource::pool_index(std::size_t bytes
) const
252 if(bytes
> m_options
.largest_required_pool_block
){
256 return priv_pool_index(bytes
);
260 std::size_t pool_resource::pool_next_blocks_per_chunk(std::size_t pool_idx
) const
262 if(BOOST_LIKELY((m_pool_data
&& pool_idx
< m_pool_count
))){
263 return m_pool_data
[pool_idx
].next_blocks_per_chunk
;
270 std::size_t pool_resource::pool_block(std::size_t pool_idx
) const
271 { return priv_pool_block(pool_idx
); }
273 std::size_t pool_resource::pool_cached_blocks(std::size_t pool_idx
) const
275 if(BOOST_LIKELY((m_pool_data
&& pool_idx
< m_pool_count
))){
276 return m_pool_data
[pool_idx
].cache_count();
284 } //namespace container {
285 } //namespace boost {
287 #include <boost/container/detail/config_end.hpp>