pw_allocator: Add Realloc and Calloc
This implements and tests Realloc() and Calloc() function in
freelist_heap.cc. Users can resize an existing pointer or initialize
pointers with 0.
Change-Id: Ief9146601aa6b89e3ff7b87f19c711c22a9abcb6
diff --git a/pw_allocator/freelist_heap.cc b/pw_allocator/freelist_heap.cc
index 1d80466..9ff5044 100644
--- a/pw_allocator/freelist_heap.cc
+++ b/pw_allocator/freelist_heap.cc
@@ -14,6 +14,8 @@
#include "pw_allocator/freelist_heap.h"
+#include <cstring>
+
namespace pw::allocator {
FreeListHeap::FreeListHeap(span<std::byte> region, FreeList& freelist)
@@ -33,7 +35,6 @@
if (chunk.data() == nullptr) {
return nullptr;
}
-
freelist_.RemoveChunk(chunk);
Block* chunk_block = Block::FromUsableSpace(chunk.data());
@@ -58,12 +59,11 @@
}
Block* chunk_block = Block::FromUsableSpace(bytes);
-
// Ensure that the block is in-use
if (!chunk_block->Used()) {
return;
}
-
+ chunk_block->MarkFree();
// Can we combine with the left or right blocks?
Block* prev = chunk_block->PrevBlock();
Block* next = nullptr;
@@ -85,9 +85,60 @@
freelist_.RemoveChunk(BlockToSpan(next));
chunk_block->MergeNext();
}
-
// Add back to the freelist
freelist_.AddChunk(BlockToSpan(chunk_block));
}
+// Follows constract of the C standard realloc() function
+// If ptr is free'd, will return nullptr.
+void* FreeListHeap::Realloc(void* ptr, size_t size) {
+ if (size == 0) {
+ Free(ptr);
+ return nullptr;
+ }
+
+ // If the pointer is nullptr, allocate a new memory.
+ if (ptr == nullptr) {
+ return Allocate(size);
+ }
+
+ std::byte* bytes = reinterpret_cast<std::byte*>(ptr);
+
+ // TODO(chenghanzh): Enhance with debug information for out-of-range and more.
+ if (bytes < region_.data() || bytes >= region_.data() + region_.size()) {
+ return nullptr;
+ }
+
+ Block* chunk_block = Block::FromUsableSpace(bytes);
+ if (!chunk_block->Used()) {
+ return nullptr;
+ }
+ size_t old_size = chunk_block->InnerSize();
+
+ // Do nothing and return ptr if the required memory size is smaller than
+ // the current size.
+ // TODO: Currently do not support shrink of memory chunk.
+ if (old_size >= size) {
+ return ptr;
+ }
+
+ void* new_ptr = Allocate(size);
+ // Don't invalidate ptr if Allocate(size) fails to initilize the memory.
+ if (new_ptr == nullptr) {
+ return nullptr;
+ }
+ memcpy(new_ptr, ptr, old_size);
+
+ Free(ptr);
+ return new_ptr;
+}
+
+void* FreeListHeap::Calloc(size_t num, size_t size) {
+ void* ptr = Allocate(num * size);
+ if (ptr != nullptr) {
+ memset(ptr, 0, num * size);
+ }
+ return ptr;
+}
+
} // namespace pw::allocator