4coder/4coder_lib/4coder_heap.cpp

144 lines
4.6 KiB
C++

/*
4coder_heap.cpp - Preversioning
no warranty implied; use at your own risk
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit.
*/
// TOP
#define heap__sent_init(s) (s)->next=(s)->prev=(s)
#define heap__insert_next(p,n) ((n)->next=(p)->next,(n)->prev=(p),(n)->next->prev=(n),(p)->next=(n))
#define heap__insert_prev(p,n) ((n)->prev=(p)->prev,(n)->next=(p),(n)->prev->next=(n),(p)->prev=(n))
#define heap__remove(n) ((n)->next->prev=(n)->prev,(n)->prev->next=(n)->next)
#if defined(DO_HEAP_CHECKS)
static void
heap_assert_good(Heap *heap){
if (heap->in_order.next != 0){
Assert(heap->in_order.prev != 0);
Assert(heap->free_nodes.next != 0);
Assert(heap->free_nodes.prev != 0);
for (Heap_Basic_Node *node = &heap->in_order;;){
Assert(node->next->prev == node);
Assert(node->prev->next == node);
node = node->next;
if (node == &heap->in_order){
break;
}
}
for (Heap_Basic_Node *node = &heap->free_nodes;;){
Assert(node->next->prev == node);
Assert(node->prev->next == node);
node = node->next;
if (node == &heap->free_nodes){
break;
}
}
}
}
#else
#define heap_assert_good(heap) ((void)(heap))
#endif
static void
heap_init(Heap *heap){
heap__sent_init(&heap->in_order);
heap__sent_init(&heap->free_nodes);
heap->used_space = 0;
heap->total_space = 0;
}
static void
heap_extend(Heap *heap, void *memory, i32 size){
heap_assert_good(heap);
if (size >= sizeof(Heap_Node)){
Heap_Node *new_node = (Heap_Node*)memory;
heap__insert_prev(&heap->in_order, &new_node->order);
heap__insert_next(&heap->free_nodes, &new_node->alloc);
new_node->size = size - sizeof(*new_node);
heap->total_space += (umem)size;
}
heap_assert_good(heap);
}
static void*
heap__reserve_chunk(Heap *heap, Heap_Node *node, i32 size){
u8 *ptr = (u8*)(node + 1);
i32 left_over_size = node->size - size;
if (left_over_size > sizeof(*node)){
i32 new_node_size = left_over_size - sizeof(*node);
Heap_Node *new_node = (Heap_Node*)(ptr + size);
heap__insert_next(&node->order, &new_node->order);
heap__insert_next(&node->alloc, &new_node->alloc);
new_node->size = new_node_size;
}
heap__remove(&node->alloc);
node->alloc.next = 0;
node->alloc.prev = 0;
node->size = size;
heap->used_space += sizeof(*node) + size;
return(ptr);
}
static void*
heap_allocate(Heap *heap, i32 size){
if (heap->in_order.next != 0){
heap_assert_good(heap);
i32 aligned_size = (size + sizeof(Heap_Node) - 1);
aligned_size = aligned_size - (aligned_size%sizeof(Heap_Node));
for (Heap_Basic_Node *n = heap->free_nodes.next;
n != &heap->free_nodes;
n = n->next){
Heap_Node *node = CastFromMember(Heap_Node, alloc, n);
if (node->size >= aligned_size){
void *ptr = heap__reserve_chunk(heap, node, aligned_size);
heap_assert_good(heap);
return(ptr);
}
}
heap_assert_good(heap);
}
return(0);
}
static void
heap__merge(Heap *heap, Heap_Node *l, Heap_Node *r){
if (&l->order != &heap->in_order && &r->order != &heap->in_order &&
l->alloc.next != 0 && l->alloc.prev != 0 &&
r->alloc.next != 0 && r->alloc.prev != 0){
u8 *ptr = (u8*)(l + 1) + l->size;
if (PtrDif(ptr, r) == 0){
heap__remove(&r->order);
heap__remove(&r->alloc);
heap__remove(&l->alloc);
l->size += r->size + sizeof(*r);
heap__insert_next(&heap->free_nodes, &l->alloc);
}
}
}
static void
heap_free(Heap *heap, void *memory){
if (heap->in_order.next != 0 && memory != 0){
Heap_Node *node = ((Heap_Node*)memory) - 1;
Assert(node->alloc.next == 0);
Assert(node->alloc.prev == 0);
heap->used_space -= sizeof(*node) + node->size;
heap_assert_good(heap);
heap__insert_next(&heap->free_nodes, &node->alloc);
heap_assert_good(heap);
heap__merge(heap, node, CastFromMember(Heap_Node, order, node->order.next));
heap_assert_good(heap);
heap__merge(heap, CastFromMember(Heap_Node, order, node->order.prev), node);
heap_assert_good(heap);
}
}
#define heap_array(g, T, size) (T*)heap_allocate(g, sizeof(T)*(size))
// BOTTOM