Skip to content

Commit 6fbdb4d

Browse files
Add o1heapGetMaxAllocationSize(), closes #18
1 parent d506b28 commit 6fbdb4d

File tree

4 files changed

+38
-0
lines changed

4 files changed

+38
-0
lines changed

o1heap/o1heap.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,14 @@ void o1heapFree(O1HeapInstance* const handle, void* const pointer)
476476
}
477477
}
478478

479+
size_t o1heapGetMaxAllocationSize(const O1HeapInstance* const handle)
480+
{
481+
O1HEAP_ASSERT(handle != NULL);
482+
// The largest allocation is smaller (up to almost two times) than the arena capacity,
483+
// due to the power-of-two padding and the fragment header overhead.
484+
return pow2(log2Floor(handle->diagnostics.capacity)) - O1HEAP_ALIGNMENT;
485+
}
486+
479487
bool o1heapDoInvariantsHold(const O1HeapInstance* const handle)
480488
{
481489
O1HEAP_ASSERT(handle != NULL);

o1heap/o1heap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ void* o1heapAllocate(O1HeapInstance* const handle, const size_t amount);
104104
/// The function is executed in constant time.
105105
void o1heapFree(O1HeapInstance* const handle, void* const pointer);
106106

107+
/// Obtains the maximum theoretically possible allocation size for this heap instance.
108+
/// This is useful when implementing std::allocator_traits<Alloc>::max_size.
109+
size_t o1heapGetMaxAllocationSize(const O1HeapInstance* const handle);
110+
107111
/// Performs a basic sanity check on the heap.
108112
/// This function can be used as a weak but fast method of heap corruption detection.
109113
/// If the handle pointer is NULL, the behavior is undefined.

tests/internal.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ struct O1HeapInstance final
167167
validate();
168168
}
169169

170+
[[nodiscard]] auto getMaxAllocationSize() const
171+
{
172+
return o1heapGetMaxAllocationSize(reinterpret_cast<const ::O1HeapInstance*>(this));
173+
}
174+
170175
[[nodiscard]] auto doInvariantsHold() const
171176
{
172177
return o1heapDoInvariantsHold(reinterpret_cast<const ::O1HeapInstance*>(this));

tests/test_general.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,27 @@ TEST_CASE("General: random A")
562562
}
563563
}
564564

565+
TEST_CASE("General: max allocation size")
566+
{
567+
alignas(128U) std::array<std::byte, 4096U + sizeof(internal::O1HeapInstance) + O1HEAP_ALIGNMENT - 1U> arena{};
568+
{
569+
auto heap = init(arena.data(), std::size(arena));
570+
REQUIRE(heap != nullptr);
571+
REQUIRE(heap->diagnostics.capacity == 4096);
572+
REQUIRE(4096 - O1HEAP_ALIGNMENT == heap->getMaxAllocationSize());
573+
REQUIRE(nullptr == heap->allocate(heap->getMaxAllocationSize() + 1));
574+
REQUIRE(nullptr != heap->allocate(heap->getMaxAllocationSize() + 0));
575+
}
576+
{
577+
auto heap = init(arena.data(), std::size(arena) - O1HEAP_ALIGNMENT);
578+
REQUIRE(heap != nullptr);
579+
REQUIRE(heap->diagnostics.capacity < 4095);
580+
REQUIRE(2048 - O1HEAP_ALIGNMENT == heap->getMaxAllocationSize());
581+
REQUIRE(nullptr == heap->allocate(heap->getMaxAllocationSize() + 1));
582+
REQUIRE(nullptr != heap->allocate(heap->getMaxAllocationSize() + 0));
583+
}
584+
}
585+
565586
TEST_CASE("General: invariant checker")
566587
{
567588
using internal::Fragment;

0 commit comments

Comments
 (0)