// ::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::