Skip to content

Instantly share code, notes, and snippets.

@gmbeard
Last active December 6, 2018 22:05
Show Gist options
  • Save gmbeard/a52621367fe800124683db6b604c8671 to your computer and use it in GitHub Desktop.
Save gmbeard/a52621367fe800124683db6b604c8671 to your computer and use it in GitHub Desktop.
Fixed-size pool allocator
#include <iostream>
#include <memory>
#include <atomic>
#include <cassert>
struct Node {
uint8_t* const data;
size_t const length;
Node* next;
};
constexpr auto kMaxBlockSize = size_t { 1024 };
constexpr auto kActualBufferSize = kMaxBlockSize - sizeof(Node);
auto get_memory_head() -> std::atomic<Node*>& {
static std::atomic<Node*> head { };
return head;
}
auto get_block_count() -> std::atomic<int64_t>& {
static std::atomic<int64_t> count { 0 };
return count;
}
auto heap_allocate_block() -> Node* {
auto* node = static_cast<Node*>(std::malloc(kMaxBlockSize));
std::cout << "Allocated block from heap\n";
return new (static_cast<void*>(node)) Node {
reinterpret_cast<uint8_t*>(node + 1),
kActualBufferSize,
nullptr
};
}
auto pop_block() -> Node* {
auto* next_node = get_memory_head().load();
if (!next_node) {
return next_node;
}
while (!get_memory_head().compare_exchange_strong(next_node,
next_node->next))
{
next_node = get_memory_head().load();
if (!next_node) {
return next_node;
}
}
get_block_count().fetch_sub(1);
return next_node;
}
auto allocate_block() -> uint8_t* {
auto* next_node = pop_block();
if (!next_node) {
next_node = heap_allocate_block();
}
else {
std::cerr << "Used block from pool\n";
}
return next_node->data;
}
auto push_block(Node* node) {
node->next = get_memory_head().load();
while (!get_memory_head().compare_exchange_strong(node->next,
node))
;
get_block_count().fetch_add(1);
std::cerr << "Pushed block back to the pool\n";
}
auto deallocate_block(uint8_t* data) {
auto* node = reinterpret_cast<Node*>(data - sizeof(Node));
if (get_block_count().load() > 1) {
std::free(node);
std::cerr << "Destroyed block\n";
return;
}
push_block(node);
}
using DataPtr = std::unique_ptr<uint8_t, decltype(deallocate_block)&>;
auto main() -> int {
auto p1 = DataPtr { allocate_block(), deallocate_block };
auto p2 = DataPtr { allocate_block(), deallocate_block };
DataPtr { allocate_block(), deallocate_block };
DataPtr { allocate_block(), deallocate_block };
(void)p1;
(void)p2;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment