libcruft-util/test/alloc/stack.cpp

78 lines
2.8 KiB
C++

#include <cruft/util/tap.hpp>
#include <cruft/util/alloc/stack.hpp>
///////////////////////////////////////////////////////////////////////////////
void
n_allocations (cruft::alloc::stack &store,
unsigned count,
size_t bytes,
size_t alignment = alignof (std::max_align_t))
{
for (unsigned i = 0; i < count; ++i) {
auto ptr = store.allocate<uint8_t> (bytes, alignment);
store.deallocate (ptr);
}
}
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
cruft::TAP::logger tap;
constexpr size_t BUFFER_AVAILABLE = 32;
constexpr size_t BUFFER_REQUEST = BUFFER_AVAILABLE - alignof (std::max_align_t);
constexpr size_t BUFFER_PAD = 32;
constexpr size_t BUFFER_SIZE = BUFFER_AVAILABLE + BUFFER_PAD;
// alignment is kinda important, so make it a little easier and ensure
// something suitable right off the bat.
alignas (std::max_align_t) std::byte memory[BUFFER_SIZE];
std::fill (std::begin (memory), std::end (memory), std::byte{0});
cruft::alloc::stack store (cruft::make_view(memory, memory + BUFFER_AVAILABLE));
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
tap.expect_eq (store.capacity (), BUFFER_AVAILABLE, "bytes capacity matches");
// larger than total allocations should throw
tap.expect_throw<std::bad_alloc> (
[&store] (void) { store.allocate<uint8_t> (BUFFER_AVAILABLE + 1, 1); },
"excessive allocation throws bad_alloc"
);
// try a large number of allocations so we exercise the frame handling and
// alignment routines.
tap.expect_nothrow (
[&store] (void) { n_allocations (store, BUFFER_AVAILABLE, BUFFER_REQUEST); },
"repeated allocation/deallocation"
);
// perform two near maximum allocations and check for exhaustion through
// bad_alloc
auto ptr = store.allocate<uint8_t> (BUFFER_REQUEST);
(void)ptr;
tap.expect_throw<std::bad_alloc> (
[&store] (void) { store.allocate<uint8_t> (BUFFER_REQUEST); },
"bad_alloc thrown on exhaustion"
);
// check byte counts are plausible. stacks use some extra memory for book
// keeping, so we need to use relational comparison rather than equality.
tap.expect_ge (store.used (), BUFFER_REQUEST, "bytes used matches");
tap.expect_le (store.remain (), BUFFER_AVAILABLE - BUFFER_REQUEST, "bytes remain matches");
// try many allocations again after resetting the allocator to zero usage
store.reset ();
tap.expect_nothrow (
[&store] (void) { n_allocations (store, BUFFER_AVAILABLE, BUFFER_REQUEST); },
"no bad_alloc after reset"
);
return tap.status ();
}