#include <boost/container/pmr/global_resource.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/intrusive/detail/math.hpp>
#include "derived_from_memory_resource.hpp"
#include "memory_resource_logger.hpp"
using namespace boost::container::pmr;
template<class PoolResource>
struct derived_from_pool_resource
: public PoolResource
{
derived_from_pool_resource(const pool_options& opts, memory_resource* upstream)
: PoolResource(opts, upstream)
{}
explicit derived_from_pool_resource(memory_resource *p)
: PoolResource(p)
{}
explicit derived_from_pool_resource(const pool_options &opts)
: PoolResource(opts)
{}
derived_from_pool_resource()
: PoolResource()
{}
using PoolResource::do_allocate;
using PoolResource::do_deallocate;
using PoolResource::do_is_equal;
};
template<class PoolResource>
void test_default_constructor()
{
{
derived_from_memory_resource dmr;
dmr.reset();
PoolResource m;
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(dmr.do_allocate_called == false);
}
}
template<class PoolResource>
void test_upstream_constructor()
{
{
derived_from_memory_resource dmr;
dmr.reset();
PoolResource m(&dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(dmr.do_allocate_called == false);
}
}
template<class PoolResource>
void test_options_constructor()
{
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
pool_options opts;
PoolResource m(opts);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(mrl.m_info.size() == 0u);
}
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
pool_options opts;
opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk+1;
opts.largest_required_pool_block = pool_options_default_largest_required_pool_block+1;
PoolResource m(opts);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(mrl.m_info.size() == 0u);
}
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
pool_options opts;
opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block-1u;
PoolResource m(opts);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block);
BOOST_TEST(mrl.m_info.size() == 0u);
}
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
pool_options opts;
opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk;
opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block;
PoolResource m(opts);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block);
BOOST_TEST(mrl.m_info.size() == 0u);
}
}
template<class PoolResource>
void test_options_upstream_constructor()
{
{
derived_from_memory_resource dmr;
dmr.reset();
pool_options opts;
PoolResource m(opts, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(dmr.do_allocate_called == false);
}
{
derived_from_memory_resource dmr;
dmr.reset();
pool_options opts;
opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk+1;
opts.largest_required_pool_block = pool_options_default_largest_required_pool_block+1;
PoolResource m(opts, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block);
BOOST_TEST(dmr.do_allocate_called == false);
}
{
derived_from_memory_resource dmr;
dmr.reset();
pool_options opts;
opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block-1u;
PoolResource m(opts, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block);
BOOST_TEST(dmr.do_allocate_called == false);
}
{
derived_from_memory_resource dmr;
dmr.reset();
pool_options opts;
opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk;
opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block;
PoolResource m(opts, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == bi::detail::ceil_pow2(opts.largest_required_pool_block));
BOOST_TEST(dmr.do_allocate_called == false);
}
}
template<class PoolResource>
void test_options()
{
{
derived_from_memory_resource dmr;
dmr.reset();
pool_options opts;
opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk/2u;
opts.largest_required_pool_block = (pool_options_default_largest_required_pool_block
- pool_options_minimum_largest_required_pool_block) | std::size_t(1); PoolResource m(opts, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.options().max_blocks_per_chunk == opts.max_blocks_per_chunk);
BOOST_TEST(m.options().largest_required_pool_block == bi::detail::ceil_pow2(opts.largest_required_pool_block));
BOOST_TEST(dmr.do_allocate_called == false);
}
}
template<class PoolResource>
void test_do_allocate_deallocate()
{
memory_resource_logger mrl;
{
derived_from_pool_resource<PoolResource> dmbr(&mrl);
{
dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 2u);
dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 3u);
dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 3u);
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
{
derived_from_pool_resource<PoolResource> dmbr(&mrl);
{
void *p = dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 2u);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u);
dmbr.do_deallocate(p, 1, 1);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 1u);
p = dmbr.do_allocate(1, 1);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u);
BOOST_TEST(mrl.m_info.size() == 2u);
void *p2 = dmbr.do_allocate(1, 1);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 1u);
void *p3 = dmbr.do_allocate(1, 1);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u);
BOOST_TEST(mrl.m_info.size() == 3u);
dmbr.do_deallocate(p2, 1, 1);
dmbr.do_deallocate(p3, 1, 1);
dmbr.do_deallocate(p, 1, 1);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == 3u);
BOOST_TEST(mrl.m_info.size() == 3u);
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
{
pool_options opts;
opts.max_blocks_per_chunk = 32u;
derived_from_pool_resource<PoolResource> dmbr(opts, &mrl);
{
std::size_t loops = opts.max_blocks_per_chunk*2-1u;
while(loops--){
dmbr.do_allocate(1, 1);
}
const std::size_t num_chunks = bi::detail::floor_log2(opts.max_blocks_per_chunk)+1u;
BOOST_TEST(mrl.m_info.size() == 1u + num_chunks);
dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 1u);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u));
loops = opts.max_blocks_per_chunk;
while(loops--){
dmbr.do_allocate(1, 1);
}
BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 2u);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u));
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
{
pool_options opts;
opts.max_blocks_per_chunk = 32u;
derived_from_pool_resource<PoolResource> dmbr(opts, &mrl);
{
std::size_t loops = opts.max_blocks_per_chunk*2-1u;
while(loops--){
dmbr.do_allocate(1, 1);
}
BOOST_TEST(dmbr.pool_next_blocks_per_chunk(0u) == opts.max_blocks_per_chunk);
const std::size_t num_chunks = bi::detail::floor_log2(opts.max_blocks_per_chunk)+1u;
BOOST_TEST(mrl.m_info.size() == 1u + num_chunks);
dmbr.do_allocate(1, 1);
BOOST_TEST(dmbr.pool_next_blocks_per_chunk(0u) == opts.max_blocks_per_chunk);
BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 1u);
BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u));
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
{
pool_options opts;
opts.max_blocks_per_chunk = 1u;
derived_from_pool_resource<PoolResource> dmbr(opts, &mrl);
const pool_options &final_opts = dmbr.options();
dmbr.do_deallocate(dmbr.do_allocate(1, 1), 1, 1);
BOOST_TEST(mrl.m_info.size() == 2u);
const std::size_t minimum_size = dmbr.pool_block(0u);
const std::size_t maximum_size = final_opts.largest_required_pool_block;
BOOST_TEST(dmbr.pool_count() == (1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size)));
for(std::size_t i = 0, s = minimum_size, max = dmbr.pool_count(); i != max; ++i, s*=2){
BOOST_TEST(dmbr.pool_cached_blocks(i) == std::size_t(i == 0));
dmbr.do_deallocate(dmbr.do_allocate(s/2+1, 1), s/2+1, 1);
dmbr.do_deallocate(dmbr.do_allocate(s-1, 1), s-1, 1);
dmbr.do_deallocate(dmbr.do_allocate(s, 1), s, 1);
BOOST_TEST(mrl.m_info.size() == (1u + i + 1u));
BOOST_TEST(dmbr.pool_cached_blocks(i) == 1u);
}
void *p = dmbr.do_allocate(maximum_size+1, 1);
BOOST_TEST(mrl.m_info.size() == (1u + dmbr.pool_count() + 1u));
dmbr.do_deallocate(p, maximum_size+1, 1);
BOOST_TEST(mrl.m_info.size() == (1u + dmbr.pool_count()));
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
template<class PoolResource>
void test_do_is_equal()
{
memory_resource_logger mrl;
derived_from_pool_resource<PoolResource> dmbr(&mrl);
derived_from_pool_resource<PoolResource> dmbr2(&mrl);
BOOST_TEST(true == dmbr.do_is_equal(dmbr));
BOOST_TEST(false == dmbr.do_is_equal(dmbr2));
derived_from_memory_resource dmr;
BOOST_TEST(false == dmbr.do_is_equal(dmr));
}
template<class PoolResource>
void test_release()
{
memory_resource_logger mrl;
{
pool_options opts;
opts.max_blocks_per_chunk = 4u;
derived_from_pool_resource<PoolResource> dmbr(opts, &mrl);
const pool_options &final_opts = dmbr.options();
const std::size_t minimum_size = dmbr.pool_block(0u);
const std::size_t maximum_size = final_opts.largest_required_pool_block;
const std::size_t pool_count = 1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size);
std::size_t expected_memory_allocs = 0;
for(std::size_t i = 0, imax = pool_count, s = minimum_size; i != imax; s*=2, ++i){
for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){
dmbr.do_allocate(s, 1);
}
expected_memory_allocs = 1 + (bid::floor_log2(opts.max_blocks_per_chunk) + 1u)*(i+1);
BOOST_TEST(mrl.m_info.size() == expected_memory_allocs);
}
for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){
dmbr.do_allocate(maximum_size+1, 1);
BOOST_TEST(mrl.m_info.size() == ++expected_memory_allocs);
}
dmbr.release();
BOOST_TEST(mrl.m_info.size() == 1u);
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
template<class PoolResource>
void test_destructor()
{
memory_resource_logger mrl;
{
pool_options opts;
opts.max_blocks_per_chunk = 4u;
derived_from_pool_resource<PoolResource> dmbr(opts, &mrl);
const pool_options &final_opts = dmbr.options();
const std::size_t minimum_size = dmbr.pool_block(0u);
const std::size_t maximum_size = final_opts.largest_required_pool_block;
const std::size_t pool_count = 1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size);
std::size_t expected_memory_allocs = 0;
for(std::size_t i = 0, imax = pool_count, s = minimum_size; i != imax; s*=2, ++i){
for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){
dmbr.do_allocate(s, 1);
}
expected_memory_allocs = 1 + (bid::floor_log2(opts.max_blocks_per_chunk) + 1u)*(i+1);
BOOST_TEST(mrl.m_info.size() == expected_memory_allocs);
}
for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){
dmbr.do_allocate(maximum_size+1, 1);
BOOST_TEST(mrl.m_info.size() == ++expected_memory_allocs);
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
template<class PoolResource>
void test_pool_resource()
{
test_options_upstream_constructor<PoolResource>();
test_default_constructor<PoolResource>();
test_upstream_constructor<PoolResource>();
test_options_constructor<PoolResource>();
test_options<PoolResource>();
test_do_allocate_deallocate<PoolResource>();
test_do_is_equal<PoolResource>();
test_release<PoolResource>();
test_destructor<PoolResource>();
}