Gears-C/src/ds.c

641 lines
13 KiB
C

// ::DataStructures::Globals::Start::
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;
// ::DataStructures::Globals::End::
// ::DataStructures::RedBlackTree::Functions::Start::
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 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(u64 key, rawptr value)
{
RBNode *node = FLMemAllocZeroed(sizeof(RBNode));
node->parent = node->left = node->right = P_RB_NIL;
node->color = RB_BLACK;
node->key = key;
RBTreePushDataNode(node->bucket.first, node->bucket.last, value);
return node;
}
static void RBTreeInsert(RBTree *tree, u64 key, rawptr value)
{
RBNode *node = P_RB_NIL;
node->left = node->right = tree->nil;
node->color = RB_RED;
if (tree->root == tree->nil)
{
node->color = RB_BLACK;
node->parent = tree->nil;
tree->root = node;
}
else
{
RBNode *curr_node = tree->root;
while (true)
{
Assert(curr_node != tree->nil, "Current Node is NIL");
if (curr_node->key == key)
{
RBTreePushDataNode(curr_node->bucket.first, curr_node->bucket.last, value);
break;
}
else if (curr_node->key < key)
{
if (curr_node->right == tree->nil)
{
node = RBTreeInitNode(key, value);
node->parent = curr_node;
curr_node->right = node;
break;
}
else
{
curr_node = curr_node->right;
}
}
else
{
if (curr_node->left == tree->nil)
{
node = RBTreeInitNode(key, value);
node->parent = curr_node;
curr_node->left = node;
break;
}
else
{
curr_node = curr_node->left;
}
}
}
}
if (node->parent->color != RB_BLACK && node != P_RB_NIL)
RBTreeCorrect(tree, node);
}
static void RBTreeCorrect(RBTree *tree, RBNode *node)
{
RBNode *gp = node->parent->parent;
RBNode *p = node->parent;
do
{
if (node == tree->root)
{
node->color = RB_BLACK;
break;
}
if (gp == tree->nil)
{
p->color = RB_BLACK;
break;
}
RBNodeDir dir = NodeDir(p);
RBNode *unc = gp->child[1 - dir];
if (unc == tree->nil || unc->color == RB_BLACK)
{
if (node == p->child[1 - dir])
{
RBTreeRotate(tree, p, dir);
node = p;
p = gp->child[dir];
}
RBTreeRotate(tree, gp, 1 - dir);
p->color = RB_BLACK;
gp->color = RB_RED;
break;
}
p->color = RB_BLACK;
unc->color = RB_BLACK;
gp->color = RB_RED;
node = gp;
gp = node->parent->parent;
} while ((p = node->parent));
}
static void RBTreeDelete(RBTree *tree, u64 key, rawptr value)
{
RBNode *node = NULL;
Assert(RBTreeSearch(tree, key, &node), "Unable to find node in RBTreeDelete");
if (node->bucket.first->data != value)
{
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 (data_node != P_RB_DN_NIL)
{
if (data_node->data == value)
{
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->bucket = ln->bucket;
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->bucket = node->left->bucket;
node->left = tree->nil;
}
else if (node->color == RB_BLACK && node->right != tree->nil)
{
node->key = node->right->key;
node->bucket = node->right->bucket;
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];
cn = s->child[dir];
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;
node = p;
} while ((p = node->parent));
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;
}
}
}
static b32 RBTreeSearchNearest(RBTree *tree, u64 key, RBNode **out_node)
{
if (tree->root == tree->nil) return false;
RBNode *node = tree->root;
RBNode *nearest = tree->root;
u64 nearest_diff = UINT64_MAX;
while (true)
{
if (node == tree->nil)
break;
u64 diff = node->key - key;
diff = Absu64(diff);
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, u64 key, RBNode **out_node)
{
if (tree->root == tree->nil) return false;
b32 found = false;
RBNode *node = tree->root;
while (true)
{
if (node->key == key)
{
found = true;
break;
}
if (node == tree->nil)
break;
if (node->key < key)
node = node->right;
else
node = node->left;
}
if (found)
*out_node = node;
return found;
}
static inline void RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node)
{
if (node->parent == tree->nil)
tree->root = placed_node;
else if (node == node->parent->left)
node->parent->left = placed_node;
else
node->parent->right = placed_node;
placed_node->parent = node->parent;
}
static void RBTreeRotate(RBTree *tree, RBNode *node, RBNodeDir dir)
{
RBNode *p = node->parent;
RBNode *root = node->child[1 - dir];
RBNode *child = root->child[dir];
node->child[1 - dir] = child;
if (child != tree->nil)
child->parent = node;
root->child[dir] = node;
root->parent = p;
node->parent = root;
if (p != tree->nil)
p->child[node == p->right] = root;
else
tree->root = root;
}
static void RBTreeLeftRotate(RBTree *tree, RBNode *node)
{
RBNode *right = node->right;
if (right->left != tree->nil)
node->right = right->left;
if (node->parent == tree->nil)
tree->root = right;
else if (node->parent->left == node)
node->parent->left = right;
else
node->parent->right = right;
right->parent = node->parent;
right->left = node;
node->parent = right;
}
static void RBTreeRightRotate(RBTree *tree, RBNode *node)
{
RBNode *left = node->left;
if (left->right != tree->nil)
node->left = left->right;
if (node->parent == tree->nil)
tree->root = left;
else if (node->parent->left == node)
node->parent->left = left;
else
node->parent->right = left;
left->parent = node->parent;
left->right = node;
node->parent = left;
}
// ::DataStructures::RedBlackTree::Functions::End::
// ::DataStructures::HashTable::Functions::Start::
static void HashTableInit(HashTable *table, u32 init_size)
{
table->cap = init_size;
table->count = 0;
table->free_lists.first = P_HT_NIL;
table->free_lists.last = P_HT_NIL;
table->lists = FLMemAlloc(sizeof(HashList) * init_size);
for (u32 i = 0; i < init_size; i++)
{
table->lists[i].first = P_HT_NIL;
table->lists[i].last = P_HT_NIL;
}
}
static void HashTableConcatInPlace(HashList *list, HashList *to_concat)
{
SLLConcatInPlaceNoCount(list, to_concat);
}
static void HashTableClear(HashTable *table)
{
table->count = 0;
for (u32 i = 0; i < table->count; i++)
{
HashTableConcatInPlace(&table->free_lists, &table->lists[i]);
}
}
static HashNode *HashListPop(HashList *list)
{
HashNode *result = list->first;
HTQueuePop(list->first, list->last);
return result;
}
static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value)
{
HashNode *node = NULL;
if (table->free_lists.first != P_HT_NIL)
node = HashListPop(&table->free_lists);
else
node = FLMemAlloc(sizeof(HashNode));
node->next = P_HT_NIL;
node->v = value;
u64 index = hash % table->cap;
HTQueuePush(table->lists[index].first, table->lists[index].last, node);
table->count += 1;
return node;
}
static HashNode *HashTablePushU64U32(HashTable *table, u64 key, u32 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u32 = value });
}
static HashNode *HashTablePushU64U64(HashTable *table, u64 key, u64 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
}
static HashNode *HashTablePushU64String8(HashTable *table, u64 key, String8 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_string = value });
}
static HashNode *HashTablePushU64Rawptr(HashTable *table, u64 key, rawptr value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_rawptr = value });
}
static HashNode *HashTablePushU64U64Split(HashTable *table, u64 key, u32 upper, u32 lower)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64_split = { .upper = upper, .lower = lower }});
}
static HashNode *HashTablePushRawptrU64(HashTable *table, rawptr key, u64 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_rawptr = key, .value_u64 = value });
}
static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key)
{
KeyValuePair *result = NULL;
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
result = &node->v;
break;
}
}
return result;
}
static KeyValuePair *HashTableSearchRawptr(HashTable *table, rawptr key)
{
KeyValuePair *result = NULL;
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_rawptr == key)
{
result = &node->v;
break;
}
}
return result;
}
static void HashTableDeleteU64(HashTable *table, u64 key)
{
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
HashNode *prev = P_HT_NIL;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
if (prev != P_HT_NIL)
prev->next = node->next;
node->v.key_u64 = 0;
node->v.value_u64 = 0;
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
break;
}
}
}
static rawptr HashTableDeleteU64Rawptr(HashTable *table, u64 key)
{
rawptr value = NULL;
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
HashNode *prev = P_HT_NIL;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
if (prev != P_HT_NIL)
prev->next = node->next;
value = node->v.value_rawptr;
node->v.key_u64 = 0;
node->v.value_rawptr = NULL;
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
break;
}
}
return value;
}
static U64Split HashTableDeleteU64U64Split(HashTable *table, u64 key)
{
U64Split value = { .upper = UINT32_MAX };
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
HashNode *prev = P_HT_NIL;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
if (prev != P_HT_NIL)
prev->next = node->next;
value.upper = node->v.value_u64_split.upper;
value.lower = node->v.value_u64_split.lower;
node->v.key_u64 = 0;
node->v.value_u64_split.upper = 0;
node->v.value_u64_split.lower = 0;
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
break;
}
}
return value;
}
// ::DataStructures::HashTable::Functions::End::