start work on changing rb tree to use linked list buckets

This commit is contained in:
Matthew 2025-04-21 09:06:03 +10:00
parent 30153e1af3
commit 8c45c914f0
5 changed files with 219 additions and 126 deletions

View File

@ -176,8 +176,15 @@ static rawptr AllocAlign(usize size, usize alignment)
if (alignment < 8) if (alignment < 8)
alignment = 8; alignment = 8;
RBNode *node = NULL; RBNode *node = P_RB_NIL;
RBTreeSearch(ALLOC.tree, size, &node); rawptr mem = NULL;
if (!RBTreeSearchNearest(ALLOC.tree, size, &node))
{
AllocGrow(size);
RBTreeSearchNearest(ALLOC.tree, size, &node);
}
} }
static void Free(rawptr ptr) 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; usize grow_size = size < ALLOC.grow_size ? ALLOC.grow_size : ALLOC.grow_size + size;
MemRealloc(ALLOC.buffer, ALLOC.size, ALLOC.size + grow_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.size += grow_size;
ALLOC.free_size += grow_size; ALLOC.free_size += grow_size;
} }
@ -211,6 +222,13 @@ static rawptr FLMemAlloc(usize size)
return FreeListAlloc(&FL_ALLOC, 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) static void FLMemFree(rawptr ptr)
{ {
FreeListFree(&FL_ALLOC, ptr); FreeListFree(&FL_ALLOC, ptr);

View File

@ -34,13 +34,14 @@ static Arena *ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no);
typedef struct AllocInfo typedef struct AllocInfo
{ {
rawptr *ptrs; rawptr ptr;
u32 count; struct AllocInfo *next;
} AllocInfo; } AllocInfo;
typedef struct Allocator typedef struct Allocator
{ {
RBTree *tree; RBTree *tree;
RBTree *used_tree;
HashTable *hash_table; HashTable *hash_table;
rawptr buffer; rawptr buffer;
u64 size; u64 size;
@ -93,6 +94,7 @@ typedef struct FLAlloc
static void GlobalFreeListInit(usize size); static void GlobalFreeListInit(usize size);
static rawptr FLMemAlloc(usize size); static rawptr FLMemAlloc(usize size);
static rawptr FLMemAllocZeroed(usize size);
static void FLMemFree(rawptr ptr); static void FLMemFree(rawptr ptr);
static void _FreeListInit(FreeList **alloc, usize size); static void _FreeListInit(FreeList **alloc, usize size);
static void FreeListInit(FLAlloc *alloc, usize size); static void FreeListInit(FLAlloc *alloc, usize size);

277
src/ds.c
View File

@ -3,6 +3,9 @@
RBNode RB_NIL = { .color = RB_BLACK }; RBNode RB_NIL = { .color = RB_BLACK };
RBNode *P_RB_NIL = &RB_NIL; RBNode *P_RB_NIL = &RB_NIL;
RBDataNode RB_DN_NIL = {0};
RBDataNode *P_RB_DN_NIL = &RB_DN_NIL;
HashNode HT_NIL = {0}; HashNode HT_NIL = {0};
HashNode *P_HT_NIL = &HT_NIL; HashNode *P_HT_NIL = &HT_NIL;
@ -16,24 +19,33 @@ static void RBTreeInit(RBTree *tree)
{ {
Assert(tree != NULL, "RBTree is null"); Assert(tree != NULL, "RBTree is null");
RB_NIL.right = RB_NIL.left = RB_NIL.parent = P_RB_NIL; 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->root = P_RB_NIL;
tree->nil = 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->parent = node->left = node->right = P_RB_NIL;
node->color = RB_BLACK; node->color = RB_BLACK;
node->key = key; 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; RBNode *existing_node = P_RB_NIL;
node->left = node->right = tree->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"); 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; break;
} }
else if (curr_node->key < node->key) else if (curr_node->key < key)
{ {
if (curr_node->right == tree->nil) if (curr_node->right == tree->nil)
{ {
RBNode *node = RBTreeInitNode(key, value);
node->parent = curr_node; node->parent = curr_node;
curr_node->right = node; curr_node->right = node;
break; break;
@ -74,6 +87,7 @@ static RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value)
{ {
if (curr_node->left == tree->nil) if (curr_node->left == tree->nil)
{ {
RBNode *node = RBTreeInitNode(key, value);
node->parent = curr_node; node->parent = curr_node;
curr_node->left = node; curr_node->left = node;
break; 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) if (node->parent->color != RB_BLACK && existing_node != P_RB_NIL)
RBTreeCorrect(tree, node); RBTreeCorrect(tree, node);
return existing_node;
} }
static void RBTreeCorrect(RBTree *tree, RBNode *node) static void RBTreeCorrect(RBTree *tree, RBNode *node)
@ -135,119 +147,142 @@ static void RBTreeCorrect(RBTree *tree, RBNode *node)
} while ((p = node->parent)); } while ((p = node->parent));
} }
static void RBTreeDelete(RBTree *tree, u32 key) static void RBTreeDelete(RBTree *tree, u32 key, rawptr value)
{ {
RBNode *node = NULL; RBNode *node = NULL;
Assert(RBTreeSearch(tree, key, &node), "Unable to find node in RBTreeDelete"); 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; Assert(node->bucket.first->next != P_RB_DN_NIL, "RBTreeDelete Failure: unable to find value to delete");
} RBDataNode *data_node = node->bucket.first->next;
else if (node->left != tree->nil && node->right != tree->nil) RBDataNode *prev_node = node->bucket.first;
{
RBNode *ln = node->right;
while (ln->left != tree->nil) while (data_node != P_RB_DN_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); if (data_node->data == value)
start_deletion:
s = p->child[1 - dir];
dn = s->child[1 - dir];
cn = s->child[dir];
if (s->color == RB_RED)
{ {
RBTreeRotate(tree, p, dir); prev_node->next = data_node->next;
p->color = RB_RED; if (data_node == node->bucket.last)
s->color = RB_BLACK; node->bucket.last = prev_node;
s = cn;
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]; dn = s->child[1 - dir];
if (dn->color == RB_RED)
goto rotate_sibling;
cn = s->child[dir]; 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; 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; s->color = RB_RED;
p->color = RB_BLACK; node = p;
return; } while ((p = node->parent));
}
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;
rotate_sibling:
RBTreeRotate(tree, s, 1 - dir);
s->color = RB_RED; s->color = RB_RED;
node = p; cn->color = RB_BLACK;
} while ((p = node->parent)); dn = s;
s = cn;
rotate_sibling: rotate_parent:
RBTreeRotate(tree, s, 1 - dir); RBTreeRotate(tree, p, dir);
s->color = RB_RED; s->color = p->color;
cn->color = RB_BLACK; p->color = RB_BLACK;
dn = s; dn->color = RB_BLACK;
s = cn; }
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 *node = tree->root;
RBNode *nearest = tree->root; RBNode *nearest = tree->root;
u32 nearest_diff = UINT32_MAX;
while (true) while (true)
{ {
if (node == tree->nil)
if (node->key == key)
break; break;
if (node->left == tree->nil && node->right == tree->nil) u32 diff = Abs(node->key - key);
break;
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; 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) static b32 RBTreeSearch(RBTree *tree, u32 key, RBNode **out_node)

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
// ::DataStructures::Macros::Header:: // ::DataStructures::RedBlackTree::Header::
#define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT) #define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT)
#define RBQueuePop(f, l) SLLQueuePop(P_RB_DN_NIL, f, l)
// ::DataStructures::RedBlackTree::Header:: #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 typedef enum RBNodeColor_e
{ {
@ -18,6 +19,18 @@ typedef enum RBNodeDir_e
RB_RIGHT, RB_RIGHT,
} RBNodeDir; } RBNodeDir;
typedef struct RBDataNode
{
rawptr data;
struct RBDataNode *next;
} RBDataNode;
typedef struct RBBucket
{
RBDataNode *first;
RBDataNode *last;
} RBBucket;
typedef struct RBNode typedef struct RBNode
{ {
union union
@ -31,7 +44,7 @@ typedef struct RBNode
}; };
struct RBNode *parent; struct RBNode *parent;
u32 key; u32 key;
rawptr data; RBBucket bucket;
RBNodeColor color; RBNodeColor color;
} RBNode; } RBNode;
@ -42,11 +55,12 @@ typedef struct RBTree
} RBTree; } RBTree;
static void RBTreeInit (RBTree *tree); 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 RBNode *RBTreeFindOrInsert(RBTree *tree, u32 key, rawptr value);
static b32 RBTreeSearchNearest(RBTree *tree, u32 key, RBNode **node); static b32 RBTreeSearchNearest(RBTree *tree, u32 key, RBNode **node);
static b32 RBTreeSearch (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 RBTreeLeftRotate (RBTree *tree, RBNode *node);
static void RBTreeRightRotate(RBTree *tree, RBNode *node); static void RBTreeRightRotate(RBTree *tree, RBNode *node);
static void RBTreeRotate (RBTree *tree, RBNode *node, RBNodeDir dir); 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:: // ::DataStructures::HashTable::Functions::Header::
#define HTQueuePop(f, l) SLLQueuePop(&HT_NIL, f, l) #define HTQueuePop(f, l) SLLQueuePop(P_HT_NIL, f, l)
#define HTQueuePush(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) #define HTQueuePush(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n)
#define HTQueuePushFront(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) #define HTQueuePushFront(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n)
typedef struct KeyValuePair typedef struct KeyValuePair
{ {

View File

@ -150,6 +150,8 @@ void MemCpy(rawptr dst, rawptr src, usize len);
#define Clamp(v, min, max) MathGeneric(Clamp, (v, min, max)) #define Clamp(v, min, max) MathGeneric(Clamp, (v, min, max))
#define Abs(v) MathGeneric(Abs, (v))
#define DefMin(T) \ #define DefMin(T) \
T T##Min(T l, T r) \ 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)); \ return Min(max, Max(v, min)); \
} }
#define DefAbs(T) \
T T##Abs(T v) \
{ \
return v < (T)0 ? -v : v; \
}
// ::Util::Hashing::Functions::Header:: // ::Util::Hashing::Functions::Header::
u64 static inline HashFromString(String8 string); u64 static inline HashFromString(String8 string);