From 8c45c914f0bbd0793397f7186a4575424424b063 Mon Sep 17 00:00:00 2001 From: Matthew Date: Mon, 21 Apr 2025 09:06:03 +1000 Subject: [PATCH] start work on changing rb tree to use linked list buckets --- src/allocators.c | 22 +++- src/allocators.h | 6 +- src/ds.c | 277 ++++++++++++++++++++++++++++------------------- src/ds.h | 32 ++++-- src/util.h | 8 ++ 5 files changed, 219 insertions(+), 126 deletions(-) diff --git a/src/allocators.c b/src/allocators.c index 325469b..212e604 100644 --- a/src/allocators.c +++ b/src/allocators.c @@ -176,8 +176,15 @@ static rawptr AllocAlign(usize size, usize alignment) if (alignment < 8) alignment = 8; - RBNode *node = NULL; - RBTreeSearch(ALLOC.tree, size, &node); + RBNode *node = P_RB_NIL; + rawptr mem = NULL; + if (!RBTreeSearchNearest(ALLOC.tree, size, &node)) + { + AllocGrow(size); + RBTreeSearchNearest(ALLOC.tree, size, &node); + } + + } static void Free(rawptr ptr) @@ -191,6 +198,10 @@ static void AllocGrow(usize size) { usize grow_size = size < ALLOC.grow_size ? ALLOC.grow_size : ALLOC.grow_size + size; MemRealloc(ALLOC.buffer, ALLOC.size, ALLOC.size + grow_size); + + AllocInfo *info = CreateAllocInfo(ALLOC.buffer + ALLOC.size); // TODO: check this if things fuck up it could be wrong + RBTreeFindOrInsert(ALLOC.tree, grow_size, info); + ALLOC.size += grow_size; ALLOC.free_size += grow_size; } @@ -211,6 +222,13 @@ static rawptr FLMemAlloc(usize size) return FreeListAlloc(&FL_ALLOC, size); } +static rawptr FLMemAllocZeroed(usize size) +{ + rawptr ptr = FreeListAlloc(&FL_ALLOC, size); + MemZero(ptr, size); + return ptr; +} + static void FLMemFree(rawptr ptr) { FreeListFree(&FL_ALLOC, ptr); diff --git a/src/allocators.h b/src/allocators.h index d18d8f0..6c000ed 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -34,13 +34,14 @@ static Arena *ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no); typedef struct AllocInfo { - rawptr *ptrs; - u32 count; + rawptr ptr; + struct AllocInfo *next; } AllocInfo; typedef struct Allocator { RBTree *tree; + RBTree *used_tree; HashTable *hash_table; rawptr buffer; u64 size; @@ -93,6 +94,7 @@ typedef struct FLAlloc static void GlobalFreeListInit(usize size); static rawptr FLMemAlloc(usize size); +static rawptr FLMemAllocZeroed(usize size); static void FLMemFree(rawptr ptr); static void _FreeListInit(FreeList **alloc, usize size); static void FreeListInit(FLAlloc *alloc, usize size); diff --git a/src/ds.c b/src/ds.c index 06ab85b..56c3b08 100644 --- a/src/ds.c +++ b/src/ds.c @@ -3,6 +3,9 @@ RBNode RB_NIL = { .color = RB_BLACK }; RBNode *P_RB_NIL = &RB_NIL; +RBDataNode RB_DN_NIL = {0}; +RBDataNode *P_RB_DN_NIL = &RB_DN_NIL; + HashNode HT_NIL = {0}; HashNode *P_HT_NIL = &HT_NIL; @@ -16,24 +19,33 @@ static void RBTreeInit(RBTree *tree) { Assert(tree != NULL, "RBTree is null"); RB_NIL.right = RB_NIL.left = RB_NIL.parent = P_RB_NIL; + RB_DN_NIL.next = P_RB_DN_NIL; tree->root = P_RB_NIL; tree->nil = P_RB_NIL; } -static inline void RBTreeInitNode(RBNode *node, u32 key, rawptr value) +static inline void RBTreePushDataNode(RBDataNode *first, RBDataNode *last, rawptr value) { + RBDataNode *data_node = FLMemAllocZeroed(sizeof(RBDataNode)); + data_node->data = value; + RBQueuePush(first, last, data_node); +} + +static inline RBNode *RBTreeInitNode(u32 key, rawptr value) +{ + RBNode *node = FLMemAllocZeroed(sizeof(RBNode)); node->parent = node->left = node->right = P_RB_NIL; node->color = RB_BLACK; node->key = key; - node->data = value; + + RBTreePushDataNode(node->bucket.first, node->bucket.last, value); + + return node; } -static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value) +static void RBTreeInsert(RBTree *tree, u32 key, rawptr value) { - RBNode *node = FLMemAlloc(sizeof(RBNode)); - RBTreeInitNode(node, key, value); - RBNode *existing_node = P_RB_NIL; node->left = node->right = tree->nil; @@ -52,15 +64,16 @@ static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value) { Assert(curr_node != tree->nil, "Current Node is NIL"); - if (curr_node->key == node->key) + if (curr_node->key == key) { - existing_node = curr_node; + RBTreeInitDataNode(curr_node->bucket.first, curr_node->bucket.last, value); break; } - else if (curr_node->key < node->key) + else if (curr_node->key < key) { if (curr_node->right == tree->nil) { + RBNode *node = RBTreeInitNode(key, value); node->parent = curr_node; curr_node->right = node; break; @@ -74,6 +87,7 @@ static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value) { if (curr_node->left == tree->nil) { + RBNode *node = RBTreeInitNode(key, value); node->parent = curr_node; curr_node->left = node; break; @@ -88,8 +102,6 @@ static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value) if (node->parent->color != RB_BLACK && existing_node != P_RB_NIL) RBTreeCorrect(tree, node); - - return existing_node; } static void RBTreeCorrect(RBTree *tree, RBNode *node) @@ -135,119 +147,142 @@ static void RBTreeCorrect(RBTree *tree, RBNode *node) } while ((p = node->parent)); } -static void RBTreeDelete(RBTree *tree, u32 key) +static void RBTreeDelete(RBTree *tree, u32 key, rawptr value) { RBNode *node = NULL; Assert(RBTreeSearch(tree, key, &node), "Unable to find node in RBTreeDelete"); - if (node == tree->root && node->left == tree->nil && node->right == tree->nil) + if (node->bucket.first.data != value) { - tree->root = tree->nil; - } - else if (node->left != tree->nil && node->right != tree->nil) - { - RBNode *ln = node->right; + Assert(node->bucket.first->next != P_RB_DN_NIL, "RBTreeDelete Failure: unable to find value to delete"); + RBDataNode *data_node = node->bucket.first->next; + RBDataNode *prev_node = node->bucket.first; - while (ln->left != tree->nil) - ln = ln->left; - - node->key = ln->key; - node->data = ln->data; - - if (node->right == ln) - node->right = tree->nil; - else - ln->parent->left = tree->nil; - - ln->parent = tree->nil; - } - else if (node->color == RB_BLACK && node->left != tree->nil) - { - node->key = node->left->key; - node->data = node->left->data; - node->left = tree->nil; - } - else if (node->color == RB_BLACK && node->right != tree->nil) - { - node->key = node->right->key; - node->data = node->right->data; - node->right = tree->nil; - } - else if (node->color == RB_RED && node->right == tree->nil && node->left == tree->nil) - { - RBNodeDir dir = NodeDir(node); - node->parent->child[dir] = tree->nil; - } - else - { - RBNode *p = node->parent; - RBNodeColor col = node->color; - RBNode *s, *cn, *dn; - - RBNodeDir dir = NodeDir(node); - p->child[dir] = tree->nil; - - goto start_deletion; - - do + while (data_node != P_RB_DN_NIL) { - dir = NodeDir(node); - start_deletion: - s = p->child[1 - dir]; - dn = s->child[1 - dir]; - cn = s->child[dir]; - - if (s->color == RB_RED) + if (data_node->data == value) { - RBTreeRotate(tree, p, dir); - p->color = RB_RED; - s->color = RB_BLACK; - s = cn; + prev_node->next = data_node->next; + if (data_node == node->bucket.last) + node->bucket.last = prev_node; + FLMemFree(data_node); + } + } + } + else + { + FLMemFree(node->bucket.first); + + if (node == tree->root && node->left == tree->nil && node->right == tree->nil) + { + tree->root = tree->nil; + } + else if (node->left != tree->nil && node->right != tree->nil) + { + RBNode *ln = node->right; + + while (ln->left != tree->nil) + ln = ln->left; + + node->key = ln->key; + node->data = ln->data; + + if (node->right == ln) + node->right = tree->nil; + else + ln->parent->left = tree->nil; + + ln->parent = tree->nil; + } + else if (node->color == RB_BLACK && node->left != tree->nil) + { + node->key = node->left->key; + node->data = node->left->data; + node->left = tree->nil; + } + else if (node->color == RB_BLACK && node->right != tree->nil) + { + node->key = node->right->key; + node->data = node->right->data; + node->right = tree->nil; + } + else if (node->color == RB_RED && node->right == tree->nil && node->left == tree->nil) + { + RBNodeDir dir = NodeDir(node); + node->parent->child[dir] = tree->nil; + } + else + { + RBNode *p = node->parent; + RBNodeColor col = node->color; + RBNode *s, *cn, *dn; + + RBNodeDir dir = NodeDir(node); + p->child[dir] = tree->nil; + + goto start_deletion; + + do + { + dir = NodeDir(node); + start_deletion: + s = p->child[1 - dir]; dn = s->child[1 - dir]; - if (dn->color == RB_RED) - goto rotate_sibling; cn = s->child[dir]; - if (cn->color == RB_RED) + + if (s->color == RB_RED) + { + RBTreeRotate(tree, p, dir); + p->color = RB_RED; + s->color = RB_BLACK; + s = cn; + + dn = s->child[1 - dir]; + if (dn->color == RB_RED) + goto rotate_sibling; + cn = s->child[dir]; + if (cn->color == RB_RED) + goto rotate_parent; + + s->color = RB_RED; + p->color = RB_BLACK; + return; + } + + if (dn->color == RB_RED) goto rotate_parent; + if (cn->color == RB_RED) + goto rotate_sibling; + + if (p->color == RB_RED) + { + s->color = RB_RED; + p->color = RB_BLACK; + return; + } + + if (p == tree->nil) + return; + s->color = RB_RED; - p->color = RB_BLACK; - return; - } - - if (dn->color == RB_RED) - goto rotate_parent; - - if (cn->color == RB_RED) - goto rotate_sibling; - - if (p->color == RB_RED) - { - s->color = RB_RED; - p->color = RB_BLACK; - return; - } - - if (p == tree->nil) - return; + node = p; + } while ((p = node->parent)); + rotate_sibling: + RBTreeRotate(tree, s, 1 - dir); s->color = RB_RED; - node = p; - } while ((p = node->parent)); + cn->color = RB_BLACK; + dn = s; + s = cn; - rotate_sibling: - RBTreeRotate(tree, s, 1 - dir); - s->color = RB_RED; - cn->color = RB_BLACK; - dn = s; - s = cn; - - rotate_parent: - RBTreeRotate(tree, p, dir); - s->color = p->color; - p->color = RB_BLACK; - dn->color = RB_BLACK; + rotate_parent: + RBTreeRotate(tree, p, dir); + s->color = p->color; + p->color = RB_BLACK; + dn->color = RB_BLACK; + } } } @@ -257,20 +292,36 @@ static b32 RBTreeSearchNearest(RBTree *tree, u32 key, RBNode **out_node) RBNode *node = tree->root; RBNode *nearest = tree->root; + u32 nearest_diff = UINT32_MAX; while (true) { - - - if (node->key == key) + if (node == tree->nil) break; - if (node->left == tree->nil && node->right == tree->nil) - break; + u32 diff = Abs(node->key - key); - if (node->key < key && node->right != tree->nil) + if (diff == 0) + { + nearest = node; + break; + } + + if (diff < nearest_diff) + { + nearest_diff = diff; + nearest = node; + } + + if (node->key < key) node = node->right; + else + node = node->left; } + + *out_node = nearest != tree->nil ? nearest : tree->nil; + + return *out_node != tree->nil; } static b32 RBTreeSearch(RBTree *tree, u32 key, RBNode **out_node) diff --git a/src/ds.h b/src/ds.h index 843c0d7..5a934f7 100644 --- a/src/ds.h +++ b/src/ds.h @@ -1,10 +1,11 @@ #pragma once -// ::DataStructures::Macros::Header:: +// ::DataStructures::RedBlackTree::Header:: #define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT) - -// ::DataStructures::RedBlackTree::Header:: +#define RBQueuePop(f, l) SLLQueuePop(P_RB_DN_NIL, f, l) +#define RBQueuePush(f, l, n) SLLQueuePush(P_RB_DN_NIL, f, l, n) +#define RBQueuePushFront(f, l, n) SLLQueuePush(P_RB_DN_NIL, f, l, n) typedef enum RBNodeColor_e { @@ -18,6 +19,18 @@ typedef enum RBNodeDir_e RB_RIGHT, } RBNodeDir; +typedef struct RBDataNode +{ + rawptr data; + struct RBDataNode *next; +} RBDataNode; + +typedef struct RBBucket +{ + RBDataNode *first; + RBDataNode *last; +} RBBucket; + typedef struct RBNode { union @@ -31,7 +44,7 @@ typedef struct RBNode }; struct RBNode *parent; u32 key; - rawptr data; + RBBucket bucket; RBNodeColor color; } RBNode; @@ -42,11 +55,12 @@ typedef struct RBTree } RBTree; static void RBTreeInit (RBTree *tree); -static inline void RBTreeInitNode(RBNode *node, u32 key, rawptr value); +static inline RBNode *RBTreeInitNode(u32 key, rawptr value); +static inline void RBTreePushDataNode(RBDataNode *first, RBDataNode *last, rawptr value); static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value); static b32 RBTreeSearchNearest(RBTree *tree, u32 key, RBNode **node); static b32 RBTreeSearch (RBTree *tree, u32 key, RBNode **node); -static void RBTreeDelete (RBTree *tree, u32 key); +static void RBTreeDelete (RBTree *tree, u32 key, rawptr value); static void RBTreeLeftRotate (RBTree *tree, RBNode *node); static void RBTreeRightRotate(RBTree *tree, RBNode *node); static void RBTreeRotate (RBTree *tree, RBNode *node, RBNodeDir dir); @@ -55,9 +69,9 @@ static void RBTreeTransplant (RBTree *tree, RBNode *node, RBNode *placed_node); // ::DataStructures::HashTable::Functions::Header:: -#define HTQueuePop(f, l) SLLQueuePop(&HT_NIL, f, l) -#define HTQueuePush(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) -#define HTQueuePushFront(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) +#define HTQueuePop(f, l) SLLQueuePop(P_HT_NIL, f, l) +#define HTQueuePush(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n) +#define HTQueuePushFront(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n) typedef struct KeyValuePair { diff --git a/src/util.h b/src/util.h index 147e265..d1dbc59 100644 --- a/src/util.h +++ b/src/util.h @@ -150,6 +150,8 @@ void MemCpy(rawptr dst, rawptr src, usize len); #define Clamp(v, min, max) MathGeneric(Clamp, (v, min, max)) +#define Abs(v) MathGeneric(Abs, (v)) + #define DefMin(T) \ T T##Min(T l, T r) \ { \ @@ -168,6 +170,12 @@ T T##Clamp(T v, T min, T max) \ return Min(max, Max(v, min)); \ } +#define DefAbs(T) \ +T T##Abs(T v) \ +{ \ + return v < (T)0 ? -v : v; \ +} + // ::Util::Hashing::Functions::Header:: u64 static inline HashFromString(String8 string);