#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/container/pmr/global_resource.hpp>
#include <boost/core/lightweight_test.hpp>
#include "derived_from_memory_resource.hpp"
#include "memory_resource_logger.hpp"
using namespace boost::container::pmr;
static const std::size_t AllocCount = 32u;
namespace test_block_chain{
void test_constructor()
{
memory_resource_logger mrl;
block_slist bc(mrl);
BOOST_TEST(&bc.upstream_resource() == &mrl);
BOOST_TEST(mrl.m_info.size() == 0u);
}
void test_allocate()
{
memory_resource_logger mrl;
block_slist bc(mrl);
for(unsigned i = 0; i != unsigned(AllocCount); ++i){
const std::size_t alloc = i+1;
char *const addr = (char*)bc.allocate(alloc);
BOOST_TEST(mrl.m_info.size() == (i+1));
BOOST_TEST(mrl.m_info[i].bytes > alloc);
BOOST_TEST(mrl.m_info[i].alignment == memory_resource::max_align);
BOOST_TEST(mrl.m_info[i].address < addr);
BOOST_TEST(addr < (mrl.m_info[i].address + mrl.m_info[i].bytes));
BOOST_TEST((addr + alloc) <= (mrl.m_info[i].address + mrl.m_info[i].bytes));
BOOST_TEST((std::size_t(addr) % memory_resource::max_align) == 0);
}
}
void test_release()
{
memory_resource_logger mrl;
block_slist bc(mrl);
char *bufs[AllocCount];
for(unsigned i = 0; i != unsigned(AllocCount); ++i){
bufs[i] = (char*)bc.allocate(i+1);
}
(void)bufs;
BOOST_TEST(mrl.m_info.size() == AllocCount);
bc.release();
BOOST_TEST(mrl.m_mismatches == 0);
BOOST_TEST(mrl.m_info.size() == 0u);
}
void test_memory_resource()
{
derived_from_memory_resource d;
block_slist bc(d);
BOOST_TEST(&bc.upstream_resource() == &d);
}
void test_destructor()
{
memory_resource_logger mrl;
{
block_slist bc(mrl);
char *bufs[AllocCount];
for(unsigned i = 0; i != unsigned(AllocCount); ++i){
bufs[i] = (char*)bc.allocate(i+1);
}
(void)bufs;
BOOST_TEST(mrl.m_info.size() == AllocCount);
}
BOOST_TEST(mrl.m_mismatches == 0);
BOOST_TEST(mrl.m_info.size() == 0u);
}
}
void test_resource_constructor()
{
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
monotonic_buffer_resource m;
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(0);
}
{
derived_from_memory_resource dmr;
dmr.reset();
monotonic_buffer_resource m(&dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size);
BOOST_TEST(m.current_buffer() == 0);
BOOST_TEST(dmr.do_allocate_called == false);
}
}
void test_initial_size_constructor()
{
const std::size_t initial_size = monotonic_buffer_resource::initial_next_buffer_size*2;
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
monotonic_buffer_resource m(initial_size);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.next_buffer_size() >= initial_size);
BOOST_TEST(m.current_buffer() == 0);
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(0);
}
{
derived_from_memory_resource dmr;
dmr.reset();
monotonic_buffer_resource m(initial_size, &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.next_buffer_size() >= initial_size);
BOOST_TEST(m.current_buffer() == 0);
BOOST_TEST(dmr.do_allocate_called == false);
}
}
void test_buffer_constructor()
{
const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size*2;
unsigned char buf[BufSz];
{
memory_resource_logger mrl;
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(&mrl);
monotonic_buffer_resource m(buf, BufSz);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.next_buffer_size() >= BufSz*2);
BOOST_TEST(m.current_buffer() == buf);
BOOST_TEST(mrl.m_info.size() == 0u);
set_default_resource(0);
}
{
derived_from_memory_resource dmr;
dmr.reset();
monotonic_buffer_resource m(buf, sizeof(buf), &dmr);
BOOST_TEST(m.upstream_resource() == &dmr);
BOOST_TEST(m.next_buffer_size() >= sizeof(buf)*2);
BOOST_TEST(m.current_buffer() == buf);
BOOST_TEST(dmr.do_allocate_called == false);
}
{
monotonic_buffer_resource m(buf, 0);
BOOST_TEST(m.upstream_resource() == get_default_resource());
BOOST_TEST(m.next_buffer_size() > 1);
BOOST_TEST(m.current_buffer() == buf);
}
}
struct derived_from_monotonic_buffer_resource
: public monotonic_buffer_resource
{
explicit derived_from_monotonic_buffer_resource(memory_resource *p)
: monotonic_buffer_resource(p)
{}
explicit derived_from_monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream)
: monotonic_buffer_resource(initial_size, upstream)
{}
explicit derived_from_monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream)
: monotonic_buffer_resource(buffer, buffer_size, upstream)
{}
using monotonic_buffer_resource::do_allocate;
using monotonic_buffer_resource::do_deallocate;
using monotonic_buffer_resource::do_is_equal;
};
void test_upstream_resource()
{
const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size;
boost::move_detail::aligned_storage<BufSz+block_slist::header_size>::type buf;
derived_from_memory_resource dmr;
dmr.reset();
derived_from_monotonic_buffer_resource dmbr(&dmr);
BOOST_TEST(dmbr.upstream_resource() == &dmr);
BOOST_TEST(dmbr.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size);
BOOST_TEST(dmbr.current_buffer() == 0);
BOOST_TEST(dmr.do_allocate_called == false);
dmr.do_allocate_return = &buf;
void *addr = dmbr.do_allocate(1u, 1u);
BOOST_TEST(addr > (char*)&buf);
BOOST_TEST(addr < (char*)(&buf+1));
BOOST_TEST(dmr.do_allocate_called == true);
BOOST_TEST(dmr.do_allocate_bytes > BufSz);
BOOST_TEST(dmr.do_allocate_alignment == memory_resource::max_align);
}
void test_do_allocate()
{
memory_resource_logger mrl;
{
std::size_t remaining_storage = 0u;
derived_from_monotonic_buffer_resource dmbr(&mrl);
{
dmbr.do_allocate(1, 1);
BOOST_TEST(mrl.m_info.size() == 1u);
BOOST_TEST(mrl.m_info[0].bytes == monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
std::size_t remaining = dmbr.remaining_storage(1u);
BOOST_TEST(remaining == monotonic_buffer_resource::initial_next_buffer_size-1u);
remaining_storage = remaining;
}
{
std::size_t wasted_due_to_alignment;
dmbr.remaining_storage(4u, wasted_due_to_alignment);
BOOST_TEST(wasted_due_to_alignment == 3u);
dmbr.do_allocate(4, 4);
BOOST_TEST(mrl.m_info.size() == 1u);
std::size_t remaining = dmbr.remaining_storage(1u);
BOOST_TEST(remaining == remaining_storage - 4 - wasted_due_to_alignment);
remaining_storage = remaining;
}
{
std::size_t wasted_due_to_alignment;
std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment);
BOOST_TEST(mrl.m_info.size() == 1u);
dmbr.do_allocate(4, 4);
BOOST_TEST(mrl.m_info.size() == 1u);
remaining = dmbr.remaining_storage(1u);
BOOST_TEST(remaining == remaining_storage - 4u);
remaining_storage = remaining;
}
{
dmbr.do_allocate(remaining_storage, 2);
std::size_t wasted_due_to_alignment;
std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment);
BOOST_TEST(wasted_due_to_alignment == 0u);
BOOST_TEST(remaining == 0u);
BOOST_TEST(mrl.m_info.size() == 1u);
remaining_storage = 0u;
}
{
dmbr.do_allocate(1u, 1u);
BOOST_TEST(mrl.m_info.size() == 2u);
BOOST_TEST(mrl.m_info[1].bytes == 2*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
std::size_t wasted_due_to_alignment;
std::size_t remaining = dmbr.remaining_storage(2u, wasted_due_to_alignment);
BOOST_TEST(wasted_due_to_alignment == 1u);
BOOST_TEST(remaining == (mrl.m_info[1].bytes - 1u - wasted_due_to_alignment - block_slist::header_size));
remaining_storage = dmbr.remaining_storage(1u);
}
{
std::size_t next_alloc = 5*monotonic_buffer_resource::initial_next_buffer_size;
dmbr.do_allocate(next_alloc, 1u);
BOOST_TEST(mrl.m_info.size() == 3u);
BOOST_TEST(mrl.m_info[2].bytes == 8*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
remaining_storage = dmbr.remaining_storage(1u);
}
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
{
boost::move_detail::aligned_storage
<monotonic_buffer_resource::initial_next_buffer_size>::type buf;
derived_from_monotonic_buffer_resource dmbr(&buf, sizeof(buf), &mrl);
BOOST_TEST(dmbr.remaining_storage(1u) == sizeof(buf));
dmbr.do_allocate(dmbr.remaining_storage(1u), 1u);
BOOST_TEST(mrl.m_info.size() == 0u);
BOOST_TEST(dmbr.remaining_storage(1u) == 0u);
}
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
void test_do_deallocate()
{
memory_resource_logger mrl;
const std::size_t initial_size = 1u;
{
derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
const unsigned iterations = 8;
char *bufs[iterations];
std::size_t sizes[iterations];
for(unsigned i = 0; i != iterations; ++i)
{
sizes[i] = dmbr.remaining_storage()+1;
bufs[i] = (char*)dmbr.do_allocate(sizes[i], 1);
BOOST_TEST(mrl.m_info.size() == (i+1));
}
std::size_t remaining = dmbr.remaining_storage();
for(unsigned i = 0; i != iterations; ++i)
{
dmbr.do_deallocate(bufs[i], sizes[i], 1u);
BOOST_TEST(mrl.m_info.size() == iterations);
BOOST_TEST(remaining == dmbr.remaining_storage());
BOOST_TEST(mrl.m_mismatches == 0u);
}
}
}
void test_do_is_equal()
{
memory_resource_logger mrl;
derived_from_monotonic_buffer_resource dmbr(&mrl);
derived_from_monotonic_buffer_resource 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));
}
void test_release()
{
{
memory_resource_logger mrl;
const std::size_t initial_size = 1u;
derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
const unsigned iterations = 8;
for(unsigned i = 0; i != iterations; ++i)
{
dmbr.do_allocate(dmbr.remaining_storage()+1, 1);
BOOST_TEST(mrl.m_info.size() == (i+1));
}
dmbr.release();
BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
{
boost::move_detail::aligned_storage
<monotonic_buffer_resource::initial_next_buffer_size>::type buf;
monotonic_buffer_resource monr(&buf, sizeof(buf));
memory_resource &mr = monr;
BOOST_TEST(monr.remaining_storage(1u) == sizeof(buf));
mr.allocate(monr.remaining_storage(1u), 1u);
BOOST_TEST(monr.current_buffer() == ((char*)&buf + sizeof(buf)));
BOOST_TEST(monr.remaining_storage(1u) == 0u);
monr.release();
BOOST_TEST(monr.remaining_storage(1u) == sizeof(buf));
BOOST_TEST(monr.current_buffer() == &buf);
}
}
void test_destructor()
{
memory_resource_logger mrl;
const std::size_t initial_size = 1u;
{
derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
const unsigned iterations = 8;
for(unsigned i = 0; i != iterations; ++i)
{
dmbr.do_allocate(dmbr.remaining_storage()+1, 1);
BOOST_TEST(mrl.m_info.size() == (i+1));
}
} BOOST_TEST(mrl.m_mismatches == 0u);
BOOST_TEST(mrl.m_info.size() == 0u);
}
int main()
{
test_block_chain::test_constructor();
test_block_chain::test_allocate();
test_block_chain::test_release();
test_block_chain::test_memory_resource();
test_block_chain::test_destructor();
test_resource_constructor();
test_initial_size_constructor();
test_buffer_constructor();
test_upstream_resource();
test_do_allocate();
test_do_deallocate();
test_do_is_equal();
test_release();
test_destructor();
return ::boost::report_errors();
}