2024-05-29 16:29:08 +10:00
|
|
|
#include <cruft/util/tap.hpp>
|
|
|
|
#include <cruft/util/alloc/stack.hpp>
|
2015-11-13 17:17:37 +11:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
2018-12-19 17:55:24 +11:00
|
|
|
n_allocations (cruft::alloc::stack &store,
|
2015-11-13 17:17:37 +11:00
|
|
|
unsigned count,
|
|
|
|
size_t bytes,
|
|
|
|
size_t alignment = alignof (std::max_align_t))
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2018-05-10 13:53:06 +10:00
|
|
|
auto ptr = store.allocate<uint8_t> (bytes, alignment);
|
|
|
|
store.deallocate (ptr);
|
2015-11-13 17:17:37 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::TAP::logger tap;
|
2015-11-13 17:17:37 +11:00
|
|
|
|
|
|
|
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.
|
2018-02-28 17:55:56 +11:00
|
|
|
alignas (std::max_align_t) std::byte memory[BUFFER_SIZE];
|
|
|
|
std::fill (std::begin (memory), std::end (memory), std::byte{0});
|
2015-11-13 17:17:37 +11:00
|
|
|
|
2018-12-19 17:55:24 +11:00
|
|
|
cruft::alloc::stack store (cruft::make_view(memory, memory + BUFFER_AVAILABLE));
|
2015-11-13 17:17:37 +11:00
|
|
|
|
2017-08-31 13:48:33 +10:00
|
|
|
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
|
2016-06-22 19:51:18 +10:00
|
|
|
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
|
2015-11-30 16:08:07 +11:00
|
|
|
tap.expect_eq (store.capacity (), BUFFER_AVAILABLE, "bytes capacity matches");
|
|
|
|
|
2015-11-13 17:17:37 +11:00
|
|
|
// larger than total allocations should throw
|
|
|
|
tap.expect_throw<std::bad_alloc> (
|
2018-05-10 13:53:06 +10:00
|
|
|
[&store] (void) { store.allocate<uint8_t> (BUFFER_AVAILABLE + 1, 1); },
|
2015-11-13 17:17:37 +11:00
|
|
|
"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
|
2018-05-10 13:53:06 +10:00
|
|
|
auto ptr = store.allocate<uint8_t> (BUFFER_REQUEST);
|
2015-11-13 17:17:37 +11:00
|
|
|
(void)ptr;
|
|
|
|
|
|
|
|
tap.expect_throw<std::bad_alloc> (
|
2018-05-10 13:53:06 +10:00
|
|
|
[&store] (void) { store.allocate<uint8_t> (BUFFER_REQUEST); },
|
2015-11-13 17:17:37 +11:00
|
|
|
"bad_alloc thrown on exhaustion"
|
|
|
|
);
|
2015-11-30 16:08:07 +11:00
|
|
|
|
|
|
|
// 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");
|
2015-11-13 17:17:37 +11:00
|
|
|
|
|
|
|
// 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 ();
|
|
|
|
}
|