├── .gitignore ├── .clang-format ├── README.md ├── Makefile ├── list.h ├── LICENSE ├── rb.h ├── avl.h ├── ht.h ├── tests ├── list.c ├── ht.c ├── rb.c └── avl.c ├── ht.c ├── list.c ├── rb.c └── avl.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | Language: Cpp 3 | MaxEmptyLinesToKeep: 3 4 | IndentCaseLabels: false 5 | AllowShortIfStatementsOnASingleLine: false 6 | AllowShortCaseLabelsOnASingleLine: false 7 | AllowShortLoopsOnASingleLine: false 8 | DerivePointerAlignment: false 9 | PointerAlignment: Right 10 | SpaceAfterCStyleCast: true 11 | TabWidth: 4 12 | UseTab: Never 13 | IndentWidth: 4 14 | BreakBeforeBraces: Linux 15 | AccessModifierOffset: -4 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # intrusive-ds 2 | 3 | ## About 4 | 5 | A collection of intrusive data-structures for C 6 | 7 | ## Motivation 8 | 9 | Intrusive data structures are much better for cache locality, utilize less 10 | allocations and allow for various optimizations like removing an object from a 11 | doubly-linked list in constant time. 12 | 13 | ## Supported Data Structures 14 | 15 | * Doubly-linked list 16 | * AVL tree 17 | * Red-black tree 18 | * Hash table 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := \ 2 | -Wall -std=c11 \ 3 | -I. -MMD 4 | 5 | OBJS := \ 6 | avl.o \ 7 | ht.o \ 8 | list.o \ 9 | rb.o 10 | 11 | deps := $(OBJS:%.o=%.d) 12 | 13 | TESTS := \ 14 | tests/avl \ 15 | tests/ht \ 16 | tests/list \ 17 | tests/rb 18 | 19 | tests/%: tests/%.o 20 | $(CC) $(CFLAGS) -o $@ $^ $(OBJS) 21 | deps += $(TESTS:%=%.d) 22 | 23 | all: $(OBJS) 24 | 25 | UNAME_S := $(shell uname -s) 26 | ifeq ($(UNAME_S),Darwin) 27 | PRINTF = printf 28 | else 29 | PRINTF = env printf 30 | endif 31 | 32 | PASS_COLOR = \e[32;01m 33 | NO_COLOR = \e[0m 34 | tests/%.done: tests/% 35 | @$(PRINTF) "*** Validating $< ***\n" 36 | @./$< && $(PRINTF) "\t$(PASS_COLOR)[ Verified ]$(NO_COLOR)\n" 37 | check: $(OBJS) $(addsuffix .done, $(TESTS)) 38 | 39 | clean: 40 | $(RM) $(deps) $(OBJS) $(TESTS) $(TESTS:%=%.o) 41 | 42 | -include $(deps) 43 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_HDR 2 | #define LIST_HDR 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | typedef struct link_internal link_t; 11 | typedef struct list_internal list_t; 12 | 13 | struct link_internal { 14 | link_t *prev, *next; 15 | }; 16 | 17 | struct list_internal { 18 | link_t *head, *tail; 19 | }; 20 | 21 | void list_init(list_t *list); 22 | 23 | void list_push_front(list_t *list, link_t *link); 24 | void list_push_back(list_t *list, link_t *link); 25 | void list_insert_before(list_t *list, link_t *before, link_t *link); 26 | void list_insert_after(list_t *list, link_t *after, link_t *link); 27 | 28 | link_t *list_pop_front(list_t *list); 29 | link_t *list_pop_back(list_t *list); 30 | 31 | void list_remove(list_t *list, link_t *link); 32 | 33 | link_t *list_head(const list_t *list); 34 | link_t *list_tail(const list_t *list); 35 | 36 | link_t *list_next(const link_t *link); 37 | link_t *list_prev(const link_t *link); 38 | 39 | #define list_ref(ELEMENT, TYPE, MEMBER) \ 40 | ((TYPE *) ((unsigned char *) (ELEMENT) -offsetof(TYPE, MEMBER))) 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 National Cheng Kung University, Taiwan. 2 | Copyright (c) 2014 Dale Weiler. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /rb.h: -------------------------------------------------------------------------------- 1 | #ifndef RB_HDR 2 | #define RB_HDR 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | typedef struct rb_node_internal rb_node_t; 12 | typedef struct rb_tree_internal rb_tree_t; 13 | 14 | struct rb_node_internal { 15 | uintptr_t parent; 16 | rb_node_t *right, *left; 17 | }; 18 | 19 | struct rb_tree_internal { 20 | rb_node_t *root; 21 | void *aux; 22 | }; 23 | 24 | typedef int (*rb_compare_t)(const rb_node_t *lhs, 25 | const rb_node_t *rhs, 26 | const void *aux); 27 | 28 | void rb_init(rb_tree_t *tree, void *aux); 29 | 30 | void rb_insert(rb_tree_t *tree, rb_node_t *node, rb_compare_t compare); 31 | void rb_remove(rb_tree_t *tree, rb_node_t *node); 32 | 33 | rb_node_t *rb_search(rb_tree_t *tree, rb_node_t *node, rb_compare_t compare); 34 | 35 | rb_node_t *rb_head(const rb_tree_t *tree); 36 | rb_node_t *rb_tail(const rb_tree_t *tree); 37 | 38 | rb_node_t *rb_next(const rb_node_t *tree); 39 | rb_node_t *rb_prev(const rb_node_t *tree); 40 | 41 | #define rb_ref(ELEMENT, TYPE, MEMBER) \ 42 | ((TYPE *) ((unsigned char *) (ELEMENT) -offsetof(TYPE, MEMBER))) 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /avl.h: -------------------------------------------------------------------------------- 1 | #ifndef AVL_HDR 2 | #define AVL_HDR 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | typedef struct avl_node_internal avl_node_t; 12 | typedef struct avl_tree_internal avl_tree_t; 13 | 14 | struct avl_node_internal { 15 | uintptr_t parent; 16 | avl_node_t *left, *right; 17 | avl_node_t *prev, *next; 18 | }; 19 | 20 | struct avl_tree_internal { 21 | avl_node_t *root; 22 | void *aux; 23 | }; 24 | 25 | typedef int (*avl_compare_t)(const avl_node_t *a, 26 | const avl_node_t *b, 27 | const void *aux); 28 | 29 | void avl_init(avl_tree_t *tree, void *aux); 30 | 31 | void avl_insert(avl_tree_t *tree, avl_node_t *node, avl_compare_t compare); 32 | void avl_remove(avl_tree_t *tree, avl_node_t *node); 33 | 34 | avl_node_t *avl_search(avl_tree_t *tree, 35 | avl_node_t *node, 36 | avl_compare_t compare); 37 | 38 | avl_node_t *avl_head(const avl_tree_t *tree); 39 | avl_node_t *avl_tail(const avl_tree_t *tree); 40 | 41 | avl_node_t *avl_next(const avl_node_t *node); 42 | avl_node_t *avl_prev(const avl_node_t *node); 43 | 44 | #define avl_ref(ELEMENT, TYPE, MEMBER) \ 45 | ((TYPE *) ((unsigned char *) (ELEMENT) -offsetof(TYPE, MEMBER))) 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /ht.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_HDR 2 | #define HASH_HDR 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | typedef struct hashnode_internal hashnode_t; 12 | typedef struct hashtable_internal hashtable_t; 13 | 14 | struct hashnode_internal { 15 | hashnode_t *next; 16 | size_t keylen; 17 | void *key; 18 | }; 19 | 20 | struct hashtable_internal { 21 | size_t (*hash)(const void *key, size_t keylen); 22 | size_t size; 23 | hashnode_t **nodes; 24 | }; 25 | 26 | bool hashtable_init(hashtable_t *table, 27 | size_t pow2size, 28 | size_t (*hash)(const void *key, size_t keylen)); 29 | void hashtable_destroy(hashtable_t *table); 30 | void hashtable_insert(hashtable_t *table, 31 | hashnode_t *node, 32 | void *key, 33 | size_t keylen); 34 | hashnode_t *hashtable_internalearch(hashtable_t *table, 35 | const void *key, 36 | size_t keylen); 37 | hashnode_t *hashtable_search(hashtable_t *table, 38 | const void *key, 39 | size_t keylen); 40 | void hashtable_remove(hashtable_t *table, const void *key, size_t keylen); 41 | 42 | #define hashtable_ref(ELEMENT, TYPE, MEMBER) \ 43 | ((TYPE *) ((unsigned char *) (ELEMENT) -offsetof(TYPE, MEMBER))) 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /tests/list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | const char *message; 9 | link_t link; 10 | } test_list_t; 11 | 12 | int list() 13 | { 14 | list_t list; 15 | list_init(&list); 16 | 17 | test_list_t a = {"Hello", {NULL, NULL}}; 18 | test_list_t b = {"Intrusive", {NULL, NULL}}; 19 | test_list_t c = {"World", {NULL, NULL}}; 20 | 21 | list_push_back(&list, &a.link); 22 | list_push_back(&list, &b.link); 23 | list_push_back(&list, &c.link); 24 | 25 | struct { 26 | char *msg1, *msg2, *msg3; 27 | } expected[3] = { 28 | {"Hello", "Intrusive", "(None)"}, 29 | {"Intrusive", "World", "Hello"}, 30 | {"World", "(None)", "Intrusive"}, 31 | }; 32 | int i = 0; 33 | 34 | link_t *node = list_head(&list); 35 | while (node) { 36 | link_t *next = list_next(node); 37 | link_t *prev = list_prev(node); 38 | test_list_t *c = list_ref(node, test_list_t, link); 39 | test_list_t *n = next ? list_ref(next, test_list_t, link) : NULL; 40 | test_list_t *p = prev ? list_ref(prev, test_list_t, link) : NULL; 41 | 42 | assert(!strcmp(expected[i].msg1, c->message)); 43 | assert(!strcmp(expected[i].msg2, n ? n->message : "(None)")); 44 | assert(!strcmp(expected[i].msg3, p ? p->message : "(None)")); 45 | i++; 46 | 47 | node = next; 48 | } 49 | return 0; 50 | } 51 | 52 | int main() 53 | { 54 | return list(); 55 | } 56 | -------------------------------------------------------------------------------- /tests/ht.c: -------------------------------------------------------------------------------- 1 | #include "ht.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | const char *message; 9 | hashnode_t node; 10 | } test_hash_t; 11 | 12 | size_t hash_func(const void *key, size_t keylen) 13 | { 14 | // One character keys for test, you can implement a more complex hash 15 | // function here 16 | return ((const char *) key)[0]; 17 | } 18 | 19 | int hash(void) 20 | { 21 | hashtable_t hash; 22 | 23 | test_hash_t a = {"Hello", {NULL, 0, NULL}}; 24 | test_hash_t b = {"Intrusive", {NULL, 0, NULL}}; 25 | test_hash_t c = {"World", {NULL, 0, NULL}}; 26 | 27 | hashtable_init(&hash, 10, &hash_func); 28 | 29 | hashtable_insert(&hash, &a.node, "a", 2); 30 | hashtable_insert(&hash, &b.node, "b", 2); 31 | hashtable_insert(&hash, &c.node, "c", 2); 32 | 33 | hashnode_t *ga = hashtable_search(&hash, "a", 2); 34 | hashnode_t *gb = hashtable_search(&hash, "b", 2); 35 | hashnode_t *gc = hashtable_search(&hash, "c", 2); 36 | 37 | test_hash_t *aa = hashtable_ref(ga, test_hash_t, node); 38 | test_hash_t *bb = hashtable_ref(gb, test_hash_t, node); 39 | test_hash_t *cc = hashtable_ref(gc, test_hash_t, node); 40 | 41 | char *expected[3] = { 42 | "Hello", 43 | "Intrusive", 44 | "World", 45 | }; 46 | 47 | assert(!strcmp(expected[0], aa->message)); 48 | assert(!strcmp(expected[1], bb->message)); 49 | assert(!strcmp(expected[2], cc->message)); 50 | 51 | hashtable_destroy(&hash); 52 | return 0; 53 | } 54 | 55 | int main() 56 | { 57 | return hash(); 58 | } 59 | -------------------------------------------------------------------------------- /tests/rb.c: -------------------------------------------------------------------------------- 1 | #include "rb.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | int number; 9 | rb_node_t node; 10 | } test_rb_t; 11 | 12 | int test_rb_compare(const rb_node_t *lhs, const rb_node_t *rhs, const void *aux) 13 | { 14 | const test_rb_t *a = rb_ref(lhs, test_rb_t, node); 15 | const test_rb_t *b = rb_ref(rhs, test_rb_t, node); 16 | if (a->number < b->number) 17 | return -1; 18 | if (a->number > b->number) 19 | return 1; 20 | return 0; 21 | } 22 | 23 | int rb() 24 | { 25 | rb_tree_t tree; 26 | rb_init(&tree, NULL); 27 | 28 | test_rb_t a = {1, {0, NULL, NULL}}; 29 | test_rb_t b = {2, {0, NULL, NULL}}; 30 | test_rb_t c = {3, {0, NULL, NULL}}; 31 | 32 | rb_insert(&tree, &a.node, &test_rb_compare); 33 | rb_insert(&tree, &b.node, &test_rb_compare); 34 | rb_insert(&tree, &c.node, &test_rb_compare); 35 | 36 | int expected[4][2] = { 37 | [1] = {2, -1}, 38 | [2] = {3, 1}, 39 | [3] = {-1, 2}, 40 | }; 41 | 42 | rb_node_t *node = rb_head(&tree); 43 | while (node) { 44 | rb_node_t *next = rb_next(node); 45 | rb_node_t *prev = rb_prev(node); 46 | test_rb_t *c = rb_ref(node, test_rb_t, node); 47 | test_rb_t *n = next ? rb_ref(next, test_rb_t, node) : NULL; 48 | test_rb_t *p = prev ? rb_ref(prev, test_rb_t, node) : NULL; 49 | 50 | assert(expected[c->number][0] == (n ? n->number : -1)); 51 | assert(expected[c->number][1] == (p ? p->number : -1)); 52 | 53 | node = next; 54 | } 55 | return 0; 56 | } 57 | 58 | int main() 59 | { 60 | return rb(); 61 | } 62 | -------------------------------------------------------------------------------- /tests/avl.c: -------------------------------------------------------------------------------- 1 | #include "avl.h" 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | int number; 8 | avl_node_t node; 9 | } test_avl_t; 10 | 11 | static int test_avl_compare(const avl_node_t *lhs, 12 | const avl_node_t *rhs, 13 | const void *aux) 14 | { 15 | const test_avl_t *a = avl_ref(lhs, test_avl_t, node); 16 | const test_avl_t *b = avl_ref(rhs, test_avl_t, node); 17 | if (a->number < b->number) 18 | return -1; 19 | if (a->number > b->number) 20 | return 1; 21 | return 0; 22 | } 23 | 24 | int avl() 25 | { 26 | avl_tree_t tree; 27 | avl_init(&tree, NULL); 28 | 29 | test_avl_t a = {1, {0, NULL, NULL, NULL, NULL}}; 30 | test_avl_t b = {2, {0, NULL, NULL, NULL, NULL}}; 31 | test_avl_t c = {3, {0, NULL, NULL, NULL, NULL}}; 32 | 33 | avl_insert(&tree, &a.node, &test_avl_compare); 34 | avl_insert(&tree, &b.node, &test_avl_compare); 35 | avl_insert(&tree, &c.node, &test_avl_compare); 36 | 37 | int expected[4][2] = { 38 | [1] = {2, -1}, 39 | [2] = {3, 1}, 40 | [3] = {-1, 2}, 41 | }; 42 | 43 | avl_node_t *node = avl_head(&tree); 44 | while (node) { 45 | avl_node_t *next = avl_next(node); 46 | avl_node_t *prev = avl_prev(node); 47 | test_avl_t *c = avl_ref(node, test_avl_t, node); 48 | test_avl_t *n = next ? avl_ref(next, test_avl_t, node) : NULL; 49 | test_avl_t *p = prev ? avl_ref(prev, test_avl_t, node) : NULL; 50 | 51 | assert(expected[c->number][0] == (n ? n->number : -1)); 52 | assert(expected[c->number][1] == (p ? p->number : -1)); 53 | 54 | node = next; 55 | } 56 | return 0; 57 | } 58 | 59 | int main() 60 | { 61 | return avl(); 62 | } 63 | -------------------------------------------------------------------------------- /ht.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ht.h" 7 | 8 | static hashnode_t *hash_node_find(hashnode_t *node, 9 | const void *key, 10 | size_t keylen) 11 | { 12 | while (node) { 13 | if (keylen != node->keylen) { 14 | node = node->next; 15 | continue; 16 | } 17 | if (!memcmp(node->key, key, keylen)) 18 | return node; 19 | node = node->next; 20 | } 21 | return NULL; 22 | } 23 | 24 | static void hash_node_init(hashnode_t *node, void *key, size_t keylen) 25 | { 26 | node->key = key; 27 | node->keylen = keylen; 28 | node->next = NULL; 29 | } 30 | 31 | static inline size_t hash_node_bin(size_t bins, size_t keyhash) 32 | { 33 | return keyhash & (bins - 1); 34 | } 35 | 36 | bool hashtable_init(hashtable_t *table, 37 | size_t pow2size, 38 | size_t (*hash)(const void *key, size_t keylen)) 39 | { 40 | assert(pow2size < sizeof(int) * 8); 41 | table->hash = hash; 42 | table->size = (1 << pow2size); 43 | table->nodes = calloc(sizeof(hashnode_t *), table->size); 44 | return table->nodes; 45 | } 46 | 47 | void hashtable_destroy(hashtable_t *table) 48 | { 49 | table->hash = NULL; 50 | table->size = 0; 51 | free(table->nodes); 52 | } 53 | 54 | void hashtable_insert(hashtable_t *table, 55 | hashnode_t *node, 56 | void *key, 57 | size_t keylen) 58 | { 59 | hash_node_init(node, key, keylen); 60 | size_t hash = table->hash(node->key, node->keylen); 61 | size_t bin = hash_node_bin(table->size, hash); 62 | hashnode_t *head = table->nodes[bin]; 63 | if (!head) { 64 | table->nodes[bin] = node; 65 | return; 66 | } 67 | if (hash_node_find(head, node->key, node->keylen)) 68 | return; 69 | table->nodes[bin] = node; 70 | node->next = head; 71 | } 72 | 73 | hashnode_t *hashtable_search(hashtable_t *table, const void *key, size_t keylen) 74 | { 75 | size_t hash = table->hash(key, keylen); 76 | size_t bin = hash_node_bin(table->size, hash); 77 | hashnode_t *node = table->nodes[bin]; 78 | return hash_node_find(node, key, keylen); 79 | } 80 | 81 | void hashtable_remove(hashtable_t *table, const void *key, size_t keylen) 82 | { 83 | size_t hash = table->hash(key, keylen); 84 | size_t bin = hash_node_bin(table->size, hash); 85 | hashnode_t *current = table->nodes[bin]; 86 | hashnode_t *prev = NULL; 87 | while (current) { 88 | if (keylen != current->keylen) { 89 | prev = current; 90 | current = current->next; 91 | continue; 92 | } 93 | if (!memcmp(current->key, key, keylen)) { 94 | if (prev) { 95 | prev->next = current->next; 96 | } else { 97 | table->nodes[bin] = current->next; 98 | } 99 | current->next = NULL; 100 | return; 101 | } 102 | prev = current; 103 | current = current->next; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | 3 | void list_init(list_t *list) 4 | { 5 | list->head = list->tail = NULL; 6 | } 7 | 8 | void list_push_front(list_t *list, link_t *link) 9 | { 10 | list_remove(list, link); 11 | 12 | if (list->head) { 13 | list->head->prev = link; 14 | link->prev = NULL; 15 | link->next = list->head; 16 | list->head = link; 17 | } else { 18 | list->head = link; 19 | list->tail = link; 20 | link->next = NULL; 21 | link->prev = NULL; 22 | } 23 | } 24 | 25 | void list_push_back(list_t *list, link_t *link) 26 | { 27 | list_remove(list, link); 28 | 29 | if (list->tail) { 30 | list->tail->next = link; 31 | link->prev = list->tail; 32 | link->next = NULL; 33 | list->tail = link; 34 | } else { 35 | list->head = link; 36 | list->tail = link; 37 | link->next = NULL; 38 | link->prev = NULL; 39 | } 40 | } 41 | 42 | void list_insert_before(list_t *list, link_t *before, link_t *link) 43 | { 44 | if (before != link) { 45 | list_remove(list, link); 46 | 47 | link->prev = before->prev; 48 | link->next = before; 49 | if (before->prev) { 50 | before->prev->next = link; 51 | } else { 52 | list->head = link; 53 | } 54 | before->prev = link; 55 | } 56 | } 57 | 58 | void list_insert_after(list_t *list, link_t *after, link_t *link) 59 | { 60 | if (after != link) { 61 | list_remove(list, link); 62 | 63 | link->next = after->next; 64 | link->prev = after; 65 | if (after->next) { 66 | after->next->prev = link; 67 | } else { 68 | list->tail = link; 69 | } 70 | after->next = link; 71 | } 72 | } 73 | 74 | link_t *list_pop_front(list_t *list) 75 | { 76 | link_t *link = list->head; 77 | if (!link) { 78 | return NULL; 79 | } 80 | if (link->next) { 81 | link->next->prev = link->prev; 82 | } 83 | if (link->prev) { 84 | link->prev->next = link->next; 85 | } 86 | if (list->head == link) { 87 | list->head = link->next; 88 | } 89 | if (list->tail == link) { 90 | list->tail = link->prev; 91 | } 92 | return link; 93 | } 94 | 95 | link_t *list_pop_back(list_t *list) 96 | { 97 | link_t *link = list->tail; 98 | if (!link) 99 | return NULL; 100 | if (link->next) 101 | link->next->prev = link->prev; 102 | if (link->prev) 103 | link->prev->next = link->next; 104 | if (list->head == link) 105 | list->head = link->next; 106 | if (list->tail == link) 107 | list->tail = link->prev; 108 | return link; 109 | } 110 | 111 | void list_remove(list_t *list, link_t *link) 112 | { 113 | if (!link) 114 | return; 115 | if (link->next) 116 | link->next->prev = link->prev; 117 | if (link->prev) 118 | link->prev->next = link->next; 119 | if (list->head == link) 120 | list->head = link->next; 121 | if (list->tail == link) 122 | list->tail = link->prev; 123 | } 124 | 125 | link_t *list_head(const list_t *list) 126 | { 127 | return list->head; 128 | } 129 | 130 | link_t *list_tail(const list_t *list) 131 | { 132 | return list->tail; 133 | } 134 | 135 | link_t *list_next(const link_t *link) 136 | { 137 | return link->next; 138 | } 139 | 140 | link_t *list_prev(const link_t *link) 141 | { 142 | return link->prev; 143 | } 144 | -------------------------------------------------------------------------------- /rb.c: -------------------------------------------------------------------------------- 1 | #include "rb.h" 2 | #include 3 | #include 4 | 5 | #ifndef __has_feature 6 | #define __has_feature(x) 0 7 | #endif 8 | 9 | #if __STDC_VERSION__ >= 201112L || \ 10 | (__has_feature(c_static_assert) && __has_feature(c_alignof)) 11 | _Static_assert(_Alignof(rb_node_t) >= 4, "Incompatible rb_node_t alignment"); 12 | #elif __GNUC__ 13 | typedef char __rb_node_align[!!(__alignof__(rb_node_t) > 4) * 2 - 1]; 14 | #else 15 | /* clang-format off */ 16 | typedef char __rb_node_align[ 17 | !!(offsetof(struct { char c; rb_node_t t; }, t) > 4) * 2 - 1]; 18 | /* clang-format on */ 19 | #endif 20 | 21 | #define RB_RED 0 22 | #define RB_BLACK 1 23 | 24 | #define rb_parent(R) ((rb_node_t *) ((uintptr_t)((R)->parent) & ~3)) 25 | #define rb_color(R) ((uintptr_t)(R)->parent & 1) 26 | #define rb_is_red(R) (!rb_color(R)) 27 | #define rb_is_black(R) rb_color(R) 28 | #define rb_set_red(R) \ 29 | do { \ 30 | rb_set_color((R), RB_RED); \ 31 | } while (0) 32 | #define rb_set_black(R) \ 33 | do { \ 34 | rb_set_color((R), RB_BLACK); \ 35 | } while (0) 36 | 37 | static inline void rb_set_parent(rb_node_t *rb, rb_node_t *p) 38 | { 39 | rb->parent = (rb->parent & 3) | (uintptr_t) p; 40 | } 41 | static inline void rb_set_color(rb_node_t *rb, int color) 42 | { 43 | rb->parent = ((rb->parent & ~1) | (uintptr_t) color); 44 | } 45 | 46 | static inline void rb_tree_init(rb_tree_t *tree, rb_node_t *node) 47 | { 48 | tree->root = node; 49 | if (!node) 50 | return; 51 | rb_set_color(node, RB_BLACK); 52 | node->left = NULL; 53 | node->right = NULL; 54 | } 55 | 56 | static inline void rb_link_node(rb_node_t *node, 57 | rb_node_t *parent, 58 | rb_node_t **link) 59 | { 60 | node->parent = (uintptr_t) parent; 61 | node->left = NULL; 62 | node->right = NULL; 63 | *link = node; 64 | } 65 | 66 | static void rb_rotate_left(rb_node_t *node, rb_tree_t *tree) 67 | { 68 | rb_node_t *right = node->right; 69 | rb_node_t *parent = rb_parent(node); 70 | 71 | if ((node->right = right->left)) { 72 | rb_set_parent(right->left, node); 73 | } 74 | right->left = node; 75 | 76 | rb_set_parent(right, parent); 77 | 78 | if (parent) { 79 | if (node == parent->left) { 80 | parent->left = right; 81 | } else { 82 | parent->right = right; 83 | } 84 | } else { 85 | tree->root = right; 86 | } 87 | rb_set_parent(node, right); 88 | } 89 | 90 | static void rb_rotate_right(rb_node_t *node, rb_tree_t *tree) 91 | { 92 | rb_node_t *left = node->left; 93 | rb_node_t *parent = rb_parent(node); 94 | 95 | if ((node->left = left->right)) 96 | rb_set_parent(left->right, node); 97 | left->right = node; 98 | rb_set_parent(left, parent); 99 | 100 | if (parent) { 101 | if (node == parent->right) { 102 | parent->right = left; 103 | } else { 104 | parent->left = left; 105 | } 106 | } else { 107 | tree->root = left; 108 | } 109 | rb_set_parent(node, left); 110 | } 111 | 112 | static void rb_insert_color(rb_node_t *node, rb_tree_t *tree) 113 | { 114 | rb_node_t *parent; 115 | while ((parent = rb_parent(node)) && rb_is_red(parent)) { 116 | rb_node_t *gparent = rb_parent(parent); 117 | if (parent == gparent->left) { 118 | rb_node_t *uncle = gparent->right; 119 | if (uncle && rb_is_red(uncle)) { 120 | rb_set_black(uncle); 121 | rb_set_black(parent); 122 | rb_set_red(gparent); 123 | node = gparent; 124 | continue; 125 | } 126 | if (parent->right == node) { 127 | rb_node_t *tmp; 128 | rb_rotate_left(parent, tree); 129 | tmp = parent; 130 | parent = node; 131 | node = tmp; 132 | } 133 | rb_set_black(parent); 134 | rb_set_red(gparent); 135 | rb_rotate_right(gparent, tree); 136 | } else { 137 | rb_node_t *uncle = gparent->left; 138 | if (uncle && rb_is_red(uncle)) { 139 | rb_set_black(uncle); 140 | rb_set_black(parent); 141 | rb_set_red(gparent); 142 | node = gparent; 143 | continue; 144 | } 145 | if (parent->left == node) { 146 | rb_node_t *tmp; 147 | rb_rotate_right(parent, tree); 148 | tmp = parent; 149 | parent = node; 150 | node = tmp; 151 | } 152 | rb_set_black(parent); 153 | rb_set_red(gparent); 154 | rb_rotate_left(gparent, tree); 155 | } 156 | } 157 | rb_set_black(tree->root); 158 | } 159 | 160 | #define rb_empty_black(NODE) (!(NODE) || rb_is_black((NODE))) 161 | 162 | static bool rb_erase_left(rb_node_t *node, rb_node_t *parent, rb_tree_t *tree) 163 | { 164 | rb_node_t *other = parent->right; 165 | if (rb_is_red(other)) { 166 | rb_set_black(other); 167 | rb_set_red(parent); 168 | rb_rotate_left(parent, tree); 169 | other = parent->right; 170 | } 171 | if (rb_empty_black(other->left) || rb_empty_black(other->right)) { 172 | rb_set_red(other); 173 | node = parent; 174 | parent = rb_parent(node); 175 | } else { 176 | if (rb_empty_black(other->right)) { 177 | rb_set_black(other->left); 178 | rb_set_red(other); 179 | rb_rotate_right(other, tree); 180 | other = parent->right; 181 | } 182 | rb_set_color(other, rb_color(parent)); 183 | rb_set_black(parent); 184 | rb_set_black(other->right); 185 | rb_rotate_left(parent, tree); 186 | node = tree->root; 187 | return true; 188 | } 189 | return false; 190 | } 191 | 192 | static bool rb_erase_right(rb_node_t *node, rb_node_t *parent, rb_tree_t *tree) 193 | { 194 | rb_node_t *other = parent->left; 195 | if (rb_is_red(other)) { 196 | rb_set_black(other); 197 | rb_set_red(parent); 198 | rb_rotate_right(parent, tree); 199 | other = parent->left; 200 | } 201 | if (rb_empty_black(other->left) || rb_empty_black(other->right)) { 202 | rb_set_red(other); 203 | node = parent; 204 | parent = rb_parent(node); 205 | } else { 206 | if (rb_empty_black(other->left)) { 207 | rb_set_black(other->right); 208 | rb_set_red(other); 209 | rb_rotate_left(other, tree); 210 | other = parent->left; 211 | } 212 | rb_set_color(other, rb_color(parent)); 213 | rb_set_black(parent); 214 | rb_set_black(other->left); 215 | rb_rotate_right(parent, tree); 216 | node = tree->root; 217 | return true; 218 | } 219 | return false; 220 | } 221 | 222 | static void rb_erase_color(rb_node_t *node, rb_node_t *parent, rb_tree_t *tree) 223 | { 224 | while ((!node || rb_is_black(node)) && node != tree->root) { 225 | if (parent->left == node && rb_erase_left(node, parent, tree)) 226 | break; 227 | if (rb_erase_right(node, parent, tree)) 228 | break; 229 | } 230 | if (node) 231 | rb_set_black(node); 232 | } 233 | 234 | static rb_node_t *rb_insert_try(rb_tree_t *tree, 235 | rb_node_t *node, 236 | rb_compare_t compare) 237 | { 238 | rb_node_t **p = &tree->root; 239 | rb_node_t *parent = NULL; 240 | while (*p) { 241 | parent = *p; 242 | int cmp = compare(node, *p, tree->aux); 243 | if (0 == cmp) 244 | return *p; 245 | if (cmp < 0) { 246 | p = &(*p)->left; 247 | } else { 248 | p = &(*p)->right; 249 | } 250 | } 251 | if (parent) { 252 | rb_link_node(node, parent, p); 253 | } else { 254 | rb_tree_init(tree, node); 255 | } 256 | return NULL; 257 | } 258 | 259 | void rb_init(rb_tree_t *tree, void *aux) 260 | { 261 | tree->root = NULL; 262 | tree->aux = aux; 263 | } 264 | 265 | void rb_insert(rb_tree_t *tree, rb_node_t *node, rb_compare_t compare) 266 | { 267 | if (rb_insert_try(tree, node, compare)) 268 | return; 269 | rb_insert_color(node, tree); 270 | } 271 | 272 | rb_node_t *rb_search(rb_tree_t *tree, rb_node_t *node, rb_compare_t compare) 273 | { 274 | rb_node_t *n = tree->root; 275 | while (n) { 276 | int cmp = compare(node, n, tree->aux); 277 | if (0 == cmp) 278 | return n; 279 | if (cmp < 0) { 280 | n = n->left; 281 | } else { 282 | n = n->right; 283 | } 284 | } 285 | return NULL; 286 | } 287 | 288 | void rb_remove(rb_tree_t *tree, rb_node_t *node) 289 | { 290 | rb_node_t *child, *parent; 291 | int color; 292 | 293 | if (!node->left) { 294 | child = node->right; 295 | } else if (!node->right) { 296 | child = node->left; 297 | } else { 298 | rb_node_t *old = node; 299 | rb_node_t *left; 300 | 301 | node = node->right; 302 | while ((left = node->left)) 303 | node = left; 304 | if (rb_parent(old)) { 305 | if (rb_parent(old)->left == old) { 306 | rb_parent(old)->left = node; 307 | } else { 308 | rb_parent(old)->right = node; 309 | } 310 | } else { 311 | tree->root = node; 312 | } 313 | 314 | child = node->right; 315 | parent = rb_parent(node); 316 | color = rb_color(node); 317 | 318 | if (parent == old) { 319 | parent = node; 320 | } else { 321 | if (child) 322 | rb_set_parent(child, parent); 323 | parent->left = child; 324 | node->right = old->right; 325 | rb_set_parent(old->right, node); 326 | } 327 | node->parent = old->parent; 328 | node->left = old->left; 329 | rb_set_parent(old->left, node); 330 | goto color; 331 | } 332 | 333 | parent = rb_parent(node); 334 | color = rb_color(node); 335 | 336 | if (child) 337 | rb_set_parent(child, parent); 338 | if (parent) { 339 | if (parent->left == node) { 340 | parent->left = child; 341 | } else { 342 | parent->right = child; 343 | } 344 | } else { 345 | tree->root = child; 346 | } 347 | 348 | color: 349 | if (color == RB_BLACK) 350 | rb_erase_color(child, parent, tree); 351 | } 352 | 353 | rb_node_t *rb_head(const rb_tree_t *tree) 354 | { 355 | rb_node_t *n = tree->root; 356 | if (!n) 357 | return NULL; 358 | while (n->left) 359 | n = n->left; 360 | return n; 361 | } 362 | 363 | rb_node_t *rb_tail(const rb_tree_t *tree) 364 | { 365 | rb_node_t *n = tree->root; 366 | if (!n) 367 | return NULL; 368 | while (n->right) 369 | n = n->right; 370 | return n; 371 | } 372 | 373 | rb_node_t *rb_next(const rb_node_t *node) 374 | { 375 | rb_node_t *parent; 376 | if (rb_parent(node) == node) 377 | return NULL; 378 | if (node->right) { 379 | node = node->right; 380 | while (node->left) 381 | node = node->left; 382 | return (rb_node_t *) node; 383 | } 384 | while ((parent = rb_parent(node)) && node == parent->right) 385 | node = parent; 386 | return parent; 387 | } 388 | 389 | rb_node_t *rb_prev(const rb_node_t *node) 390 | { 391 | rb_node_t *parent; 392 | if (rb_parent(node) == node) 393 | return NULL; 394 | if (node->left) { 395 | node = node->left; 396 | while (node->right) 397 | node = node->right; 398 | return (rb_node_t *) node; 399 | } 400 | while ((parent = rb_parent(node)) && node == parent->left) 401 | node = parent; 402 | return parent; 403 | } 404 | -------------------------------------------------------------------------------- /avl.c: -------------------------------------------------------------------------------- 1 | #include "avl.h" 2 | #include 3 | 4 | #ifndef __has_feature 5 | #define __has_feature(x) 0 6 | #endif 7 | 8 | #if __STDC_VERSION__ >= 201112L || \ 9 | (__has_feature(c_static_assert) && __has_feature(c_alignof)) 10 | _Static_assert(_Alignof(avl_node_t) >= 4, "Incompatible avl_node_t alignment"); 11 | #elif __GNUC__ 12 | typedef char __avl_node_align[!!(__alignof__(avl_node_t) > 4) * 2 - 1]; 13 | #else 14 | /* clang-format off */ 15 | typedef char __avl_node_align[ 16 | !!(offsetof(struct { char c; avl_node_t t; }, t) > 4) * 2 - 1]; 17 | /* clang-format on */ 18 | #endif 19 | 20 | static int avl_abs(int n) 21 | { 22 | int mask = (unsigned) n >> ((sizeof(int) * 8) - 1); 23 | return (mask + n) ^ mask; 24 | } 25 | 26 | static inline int avl_max(int lhs, int rhs) 27 | { 28 | return lhs > rhs ? lhs : rhs; 29 | } 30 | 31 | static inline void avl_set_parent(avl_node_t *node, avl_node_t *parent) 32 | { 33 | node->parent = (uintptr_t) parent | (node->parent & 3); 34 | } 35 | 36 | static inline avl_node_t *avl_get_parent(const avl_node_t *const node) 37 | { 38 | return (avl_node_t *) (node->parent & ~3); 39 | } 40 | 41 | static inline void avl_set_factor(avl_node_t *node, int factor) 42 | { 43 | node->parent = (uintptr_t) avl_get_parent(node) | (uintptr_t)(factor + 1); 44 | } 45 | 46 | static inline int avl_get_factor(const avl_node_t *const node) 47 | { 48 | return ((int) (node->parent & 3)) - 1; 49 | } 50 | 51 | static inline int avl_get_balance(const avl_node_t *const node) 52 | { 53 | return node ? avl_get_factor(node) : 0; 54 | } 55 | 56 | static avl_node_t *avl_rotate_ll(avl_node_t *parent, 57 | int pfactor, 58 | int *cfactor, 59 | int *difference) 60 | { 61 | avl_node_t *child = parent->left; 62 | 63 | int cleft = !!child->left; 64 | int cright = !!child->right; 65 | int pright = 0; 66 | if (*cfactor < 0) { 67 | cleft = cright - *cfactor; 68 | pright = cleft + 1 + pfactor; 69 | if (difference) { 70 | *difference = 71 | avl_max(cleft, avl_max(cright, pright) + 1) - (cleft + 1); 72 | } 73 | } else { 74 | cright = cleft + *cfactor; 75 | pright = cright + 1 + pfactor; 76 | if (difference) { 77 | *difference = 78 | avl_max(cleft, avl_max(cright, pright) + 1) - (cright + 1); 79 | } 80 | } 81 | *cfactor = (avl_max(cright, pright) + 1) - cleft; 82 | avl_set_factor(parent, pright - cright); 83 | 84 | parent->left = child->right; 85 | if (child->right) 86 | avl_set_parent(child->right, parent); 87 | child->right = parent; 88 | avl_set_parent(child, avl_get_parent(parent)); 89 | avl_set_parent(parent, child); 90 | 91 | return child; 92 | } 93 | 94 | static avl_node_t *avl_rotate_rr(avl_node_t *parent, 95 | int pfactor, 96 | int *cfactor, 97 | int *difference) 98 | { 99 | avl_node_t *child = parent->right; 100 | 101 | int cleft = !!child->left; 102 | int cright = !!child->right; 103 | int pleft = 0; 104 | if (*cfactor < 0) { 105 | cleft = cright - *cfactor; 106 | pleft = cleft + 1 - pfactor; 107 | if (difference) { 108 | *difference = 109 | avl_max(cright, avl_max(cleft, pleft) + 1) - (cleft - 1); 110 | } 111 | } else { 112 | cright = cleft + *cfactor; 113 | pleft = cright + 1 - pfactor; 114 | if (difference) { 115 | *difference = 116 | avl_max(cright, avl_max(cleft, pleft) + 1) - (cright + 1); 117 | } 118 | } 119 | *cfactor = cright - (avl_max(cleft, pleft) + 1); 120 | avl_set_factor(parent, cleft - pleft); 121 | 122 | parent->right = child->left; 123 | if (child->left) { 124 | avl_set_parent(child->left, parent); 125 | } 126 | child->left = parent; 127 | avl_set_parent(child, avl_get_parent(parent)); 128 | avl_set_parent(parent, child); 129 | 130 | return child; 131 | } 132 | 133 | static inline avl_node_t *avl_rotate_lr(avl_node_t *parent, int pfactor) 134 | { 135 | avl_node_t *child = parent->left; 136 | 137 | int cfactor = 0; 138 | int difference = 0; 139 | if (child->right) { 140 | cfactor = avl_get_factor(child->right); 141 | parent->left = 142 | avl_rotate_rr(child, avl_get_factor(child), &cfactor, &difference); 143 | } else { 144 | cfactor = avl_get_factor(child); 145 | } 146 | 147 | avl_node_t *node = 148 | avl_rotate_ll(parent, pfactor - difference, &cfactor, NULL); 149 | avl_set_factor(node, cfactor); 150 | return node; 151 | } 152 | 153 | static inline avl_node_t *avl_rotate_rl(avl_node_t *parent, int pfactor) 154 | { 155 | avl_node_t *child = parent->right; 156 | 157 | int cfactor = 0; 158 | int difference = 0; 159 | if (child->left) { 160 | cfactor = avl_get_factor(child->left); 161 | parent->right = 162 | avl_rotate_ll(child, avl_get_factor(child), &cfactor, &difference); 163 | } else { 164 | cfactor = avl_get_factor(child); 165 | } 166 | 167 | avl_node_t *node = 168 | avl_rotate_rr(parent, pfactor + difference, &cfactor, NULL); 169 | avl_set_factor(node, cfactor); 170 | return node; 171 | } 172 | 173 | static avl_node_t *avl_balance(avl_node_t *node, int factor) 174 | { 175 | if (!node) 176 | return NULL; 177 | int difference = avl_get_balance(node) + factor; 178 | if (difference < -1 && node->left) { 179 | if (avl_get_balance(node->left) <= 0) { 180 | int child = avl_get_factor(node->left); 181 | node = avl_rotate_ll(node, difference, &child, NULL); 182 | avl_set_factor(node, child); 183 | } else { 184 | node = avl_rotate_lr(node, difference); 185 | } 186 | } else if (difference > 1 && node->right) { 187 | if (avl_get_balance(node->right) >= 1) { 188 | int child = avl_get_factor(node->right); 189 | node = avl_rotate_rr(node, difference, &child, NULL); 190 | avl_set_factor(node, child); 191 | } else { 192 | node = avl_rotate_rl(node, difference); 193 | } 194 | } else { 195 | avl_set_factor(node, avl_get_factor(node) + factor); 196 | } 197 | return node; 198 | } 199 | 200 | void avl_init(avl_tree_t *tree, void *aux) 201 | { 202 | tree->root = NULL; 203 | tree->aux = aux; 204 | } 205 | 206 | avl_node_t *avl_head(const avl_tree_t *tree) 207 | { 208 | avl_node_t *head = NULL; 209 | for (avl_node_t *node = tree->root; node; node = node->left) 210 | head = node; 211 | return head; 212 | } 213 | 214 | avl_node_t *avl_tail(const avl_tree_t *tree) 215 | { 216 | avl_node_t *tail = NULL; 217 | for (avl_node_t *node = tree->root; node; node = node->right) 218 | tail = node; 219 | return tail; 220 | } 221 | 222 | avl_node_t *avl_next(const avl_node_t *node) 223 | { 224 | return node ? node->next : NULL; 225 | } 226 | 227 | avl_node_t *avl_prev(const avl_node_t *node) 228 | { 229 | return node ? node->prev : NULL; 230 | } 231 | 232 | avl_node_t *avl_search(avl_tree_t *tree, 233 | avl_node_t *node, 234 | avl_compare_t compare) 235 | { 236 | for (avl_node_t *parent = tree->root; parent;) { 237 | int cmp = compare(parent, node, tree->aux); 238 | if (0 == cmp) 239 | return parent; 240 | if (cmp > 0) { 241 | parent = parent->left; 242 | } else { 243 | parent = parent->right; 244 | } 245 | } 246 | return NULL; 247 | } 248 | 249 | void avl_insert(avl_tree_t *tree, avl_node_t *node, avl_compare_t compare) 250 | { 251 | avl_node_t *parent = NULL; 252 | for (avl_node_t *current = tree->root; current;) { 253 | int cmp = compare(current, node, tree->aux); 254 | if (0 == cmp) 255 | return; 256 | parent = current; 257 | if (cmp > 0) { 258 | current = current->left; 259 | } else { 260 | current = current->right; 261 | } 262 | } 263 | 264 | avl_set_parent(node, parent); 265 | avl_set_factor(node, 0); 266 | 267 | node->left = NULL; 268 | node->right = NULL; 269 | node->prev = NULL; 270 | node->next = NULL; 271 | 272 | if (parent) { 273 | if (compare(parent, node, tree->aux) > 0) { 274 | parent->left = node; 275 | node->next = parent; 276 | node->prev = parent->prev; 277 | if (parent->prev) 278 | parent->prev->next = node; 279 | parent->prev = node; 280 | } else { 281 | parent->right = node; 282 | node->prev = parent; 283 | node->next = parent->next; 284 | if (parent->next) 285 | parent->next->prev = node; 286 | parent->next = node; 287 | } 288 | } else { 289 | tree->root = node; 290 | } 291 | 292 | int factor = 0; 293 | while (node) { 294 | parent = avl_get_parent(node); 295 | if (parent) { 296 | int oldfactor = avl_get_factor(node); 297 | if (parent->right == node) { 298 | node = avl_balance(node, factor); 299 | parent->right = node; 300 | } else { 301 | node = avl_balance(node, factor); 302 | parent->left = node; 303 | } 304 | 305 | if (!node->left && !node->right) { 306 | factor = parent->left == node ? -1 : 1; 307 | } else { 308 | factor = 0; 309 | if (avl_abs(oldfactor) < avl_abs(avl_get_factor(node))) { 310 | factor = parent->left == node ? -1 : 1; 311 | } 312 | } 313 | } else if (node == tree->root) { 314 | tree->root = avl_balance(tree->root, factor); 315 | break; 316 | } 317 | if (factor == 0) 318 | break; 319 | node = parent; 320 | } 321 | } 322 | 323 | void avl_remove(avl_tree_t *tree, avl_node_t *node) 324 | { 325 | if (!node) 326 | return; 327 | if (node->prev) 328 | node->prev->next = node->next; 329 | if (node->next) 330 | node->next->prev = node->prev; 331 | 332 | avl_node_t *next = avl_head(&((avl_tree_t){node->right, NULL})); 333 | avl_node_t *current = NULL; 334 | avl_node_t *parent = NULL; 335 | int factor = 0; 336 | if (next) { 337 | if (avl_get_parent(next)) { 338 | if (avl_get_parent(next) != node) { 339 | avl_get_parent(next)->left = next->right; 340 | if (next->right) { 341 | avl_set_parent(next->right, avl_get_parent(next)); 342 | } 343 | } 344 | } 345 | if (avl_get_parent(node)) { 346 | if (avl_get_parent(node)->left == node) { 347 | avl_get_parent(node)->left = next; 348 | } else { 349 | avl_get_parent(node)->right = next; 350 | } 351 | } 352 | 353 | if (node->right != next) { 354 | node->right = node->right; 355 | if (node->right) 356 | avl_set_parent(node->right, next); 357 | current = avl_get_parent(next); 358 | factor = 1; 359 | } else { 360 | current = next; 361 | factor = -1; 362 | } 363 | 364 | next->left = node->left; 365 | if (node->left) { 366 | avl_set_parent(node->left, next); 367 | } 368 | avl_set_parent(next, avl_get_parent(node)); 369 | avl_set_factor(next, avl_get_factor(node)); 370 | } else { 371 | parent = avl_get_parent(node); 372 | if (parent) { 373 | if (parent->left == node) { 374 | parent->left = node->left; 375 | factor = 1; 376 | } else { 377 | parent->right = node->left; 378 | factor = -1; 379 | } 380 | } 381 | if (node->left) 382 | avl_set_parent(node->left, parent); 383 | current = avl_get_parent(node); 384 | } 385 | 386 | if (tree->root == node) { 387 | tree->root = next; 388 | if (!next && node->left) 389 | tree->root = node->left; 390 | } 391 | 392 | while (current) { 393 | parent = avl_get_parent(current); 394 | if (parent) { 395 | int oldfactor = avl_get_factor(current); 396 | if (parent->right == current) { 397 | current = avl_balance(current, factor); 398 | parent->right = current; 399 | } else { 400 | current = avl_balance(current, factor); 401 | parent->left = current; 402 | } 403 | 404 | if (!current->left && !current->right) { 405 | factor = parent->left == current ? 1 : -1; 406 | } else { 407 | factor = 0; 408 | if (avl_abs(oldfactor) > avl_abs(avl_get_factor(current))) 409 | factor = parent->left == current ? 1 : -1; 410 | } 411 | } else if (current == tree->root) { 412 | tree->root = avl_balance(tree->root, factor); 413 | break; 414 | } 415 | if (factor == 0) 416 | break; 417 | current = parent; 418 | } 419 | } 420 | --------------------------------------------------------------------------------