├── Makefile ├── README.rst ├── avl_tree.c ├── avl_tree.h ├── package.json └── tests ├── CuTest.c ├── CuTest.h ├── make-tests.sh └── test_avl_tree.c /Makefile: -------------------------------------------------------------------------------- 1 | GCOV_OUTPUT = *.gcda *.gcno *.gcov 2 | GCOV_CCFLAGS = -fprofile-arcs -ftest-coverage 3 | CC = gcc 4 | CCFLAGS = -I. -Itests -g -Werror -W -fno-omit-frame-pointer -fno-common -fsigned-char $(GCOV_CCFLAGS) 5 | 6 | 7 | all: test 8 | 9 | main.c: 10 | sh tests/make-tests.sh tests/test_*.c > main.c 11 | 12 | test: main.c avl_tree.o tests/test_avl_tree.c tests/CuTest.c main.c 13 | $(CC) $(CCFLAGS) -o $@ $^ 14 | ./test 15 | gcov main.c tests/test_avl_tree.c avl_tree.c 16 | 17 | avl_tree.o: avl_tree.c 18 | $(CC) $(CCFLAGS) -c -o $@ $^ 19 | 20 | clean: 21 | rm -f main.c avl_tree.o test $(GCOV_OUTPUT) 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Example Usage 2 | ------------- 3 | http://github.com/willemt/YABTorrent/blob/master/src/bt_blacklist.c 4 | 5 | Tradeoffs 6 | --------- 7 | In comparison to red-black trees, AVL trees have slower insertion and removal but faster retrieval. 8 | -------------------------------------------------------------------------------- /avl_tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "avl_tree.h" 7 | 8 | #define max(x,y) ((x) < (y) ? (y) : (x)) 9 | 10 | static int __child_l(const int idx) 11 | { 12 | return idx * 2 + 1; 13 | } 14 | 15 | static int __child_r(const int idx) 16 | { 17 | return idx * 2 + 2; 18 | } 19 | 20 | static int __parent(const int idx) 21 | { 22 | #if 0 23 | if (idx == 0) return *(int*)NULL; 24 | #endif 25 | assert(idx != 0); 26 | return (idx - 1) / 2; 27 | } 28 | 29 | static void __print(avltree_t* me, int idx, int d) 30 | { 31 | int i; 32 | 33 | for (i=0; isize <= idx || !me->nodes[idx].key) 38 | { 39 | printf("\n"); 40 | return; 41 | } 42 | 43 | printf("%lx\n", (unsigned long int)me->nodes[idx].key); 44 | __print(me, __child_l(idx),d+1); 45 | __print(me, __child_r(idx),d+1); 46 | } 47 | 48 | void avltree_print(avltree_t* me) 49 | { 50 | printf("AVL Tree:\n"); 51 | __print(me,0,0); 52 | } 53 | 54 | void avltree_print2(avltree_t* me) 55 | { 56 | int i; 57 | 58 | for (i=0;isize; i++) 59 | printf("%lx%c", (unsigned long int)me->nodes[i].key, i==me->size ? '|' : ' '); 60 | printf("\n"); 61 | } 62 | 63 | static void __enlarge(avltree_t* me) 64 | { 65 | int ii, end; 66 | node_t *array_n; 67 | 68 | /* double capacity */ 69 | me->size *= 2; 70 | array_n = malloc(me->size * sizeof(node_t)); 71 | 72 | /* copy old data across to new array */ 73 | for (ii = 0, end = avltree_count(me); ii < end; ii++) 74 | { 75 | if (me->nodes[ii].key) 76 | memcpy(&array_n[ii], &me->nodes[ii], sizeof(node_t)); 77 | else 78 | array_n[ii].key = NULL; 79 | } 80 | 81 | /* swap arrays */ 82 | free(me->nodes); 83 | me->nodes = array_n; 84 | } 85 | 86 | avltree_t* avltree_new(long (*cmp)( 87 | const void *e1, 88 | const void *e2)) 89 | { 90 | avltree_t* me; 91 | 92 | assert(cmp); 93 | 94 | me = calloc(1,sizeof(avltree_t)); 95 | me->size = 40; 96 | me->nodes = calloc(me->size, sizeof(node_t)); 97 | me->cmp = cmp; 98 | return me; 99 | } 100 | 101 | static int __count(avltree_t* me, int idx) 102 | { 103 | if (me->size <= idx || !me->nodes[idx].key) 104 | return 0; 105 | return __count(me, __child_l(idx)) + __count(me, __child_r(idx)) + 1; 106 | } 107 | 108 | int avltree_count(avltree_t* me) 109 | { 110 | // return __count(me,0); 111 | return me->count; 112 | } 113 | 114 | int avltree_size(avltree_t* me) 115 | { 116 | return me->size; 117 | } 118 | 119 | static int __height(avltree_t* me, int idx) 120 | { 121 | if (idx >= me->size || !me->nodes[idx].key) return 0; 122 | return max( 123 | __height(me,__child_l(idx)) + 1, 124 | __height(me,__child_r(idx)) + 1); 125 | } 126 | 127 | int avltree_height(avltree_t* me) 128 | { 129 | return __height(me,0); 130 | } 131 | 132 | static void __shift_up(avltree_t* me, int idx, int towards) 133 | { 134 | if (!me->nodes[idx].key) 135 | return; 136 | 137 | memcpy(&me->nodes[towards], &me->nodes[idx], sizeof(node_t)); 138 | me->nodes[idx].key = NULL; 139 | __shift_up(me, __child_l(idx), __child_l(towards)); 140 | __shift_up(me, __child_r(idx), __child_r(towards)); 141 | } 142 | 143 | static void __shift_down(avltree_t* me, int idx, int towards) 144 | { 145 | if (!me->nodes[idx].key || idx >= me->size) 146 | return; 147 | 148 | __shift_down(me, __child_l(idx), __child_l(towards)); 149 | __shift_down(me, __child_r(idx), __child_r(towards)); 150 | memcpy(&me->nodes[towards], &me->nodes[idx], sizeof(node_t)); 151 | } 152 | 153 | void avltree_rotate_right(avltree_t* me, int idx) 154 | { 155 | /* A Partial 156 | * Move X out of the way so that Y can take its spot */ 157 | __shift_down(me,__child_r(idx),__child_r(__child_r(idx))); 158 | memcpy(&me->nodes[__child_r(idx)], &me->nodes[idx], sizeof(node_t)); 159 | 160 | /* B */ 161 | __shift_down(me,__child_r(__child_l(idx)), __child_l(__child_r(idx))); 162 | me->nodes[__child_r(__child_l(idx))].key = NULL; 163 | 164 | /* A Final 165 | * Move Y into X's old spot */ 166 | __shift_up(me,__child_l(idx), idx); 167 | } 168 | 169 | void* avltree_get(avltree_t* me, const void* k) 170 | { 171 | int i; 172 | 173 | for (i=0; i < me->size; ) 174 | { 175 | int r; 176 | node_t *n; 177 | 178 | n = &me->nodes[i]; 179 | 180 | /* couldn't find it */ 181 | if (!n->key) 182 | return NULL; 183 | 184 | r = me->cmp(n->key,k); 185 | 186 | if (r==0) 187 | { 188 | return n->val; 189 | } 190 | else if (r < 0) 191 | { 192 | i = __child_l(i); 193 | } 194 | else if (r > 0) 195 | { 196 | i = __child_r(i); 197 | } 198 | else 199 | { 200 | assert(0); 201 | } 202 | } 203 | 204 | /* couldn't find it */ 205 | return NULL; 206 | } 207 | 208 | void* avltree_get_from_idx(avltree_t* me, int idx) 209 | { 210 | return me->nodes[idx].key; 211 | } 212 | 213 | void avltree_rotate_left(avltree_t* me, int idx) 214 | { 215 | int p; 216 | 217 | p = __parent(idx); 218 | 219 | /* A Partial 220 | * Move Y out of the way so that X can take its spot */ 221 | __shift_down(me, __child_l(p), __child_l(__child_l(p))); 222 | memcpy(&me->nodes[__child_l(p)], &me->nodes[p], sizeof(node_t)); 223 | 224 | /* B */ 225 | __shift_down(me, __child_l(idx), __child_r(__child_l(p))); 226 | me->nodes[__child_l(idx)].key = NULL; 227 | 228 | /* A Final 229 | * Move Y into X's old spot */ 230 | __shift_up(me, idx, p); 231 | } 232 | 233 | static void __rebalance(avltree_t* me, int idx) 234 | { 235 | 236 | while (1) 237 | { 238 | if (2 <= abs( 239 | __height(me, __child_l(idx)) - 240 | __height(me, __child_r(idx)))) 241 | { 242 | /* balance factor left node */ 243 | int bf_r; 244 | 245 | bf_r = __height(me, __child_l(__child_r(idx))) - 246 | __height(me, __child_r(__child_r(idx))); 247 | 248 | if (bf_r == -1) 249 | { 250 | avltree_rotate_left(me,__child_r(idx)); 251 | } 252 | else 253 | { 254 | avltree_rotate_left(me,__child_r(idx)); 255 | avltree_rotate_right(me,__child_r(idx)); 256 | } 257 | } 258 | 259 | if (0 == idx) break; 260 | idx = __parent(idx); 261 | } 262 | } 263 | 264 | static int __previous_ordered_node(avltree_t* me, int idx) 265 | { 266 | int prev,i; 267 | 268 | for (prev = -1, i = __child_l(idx); 269 | /* array isn't that big, or key is null -> we don't have this child */ 270 | i < me->size && me->nodes[i].key; 271 | prev = i, i = __child_r(i) 272 | ); 273 | 274 | return prev; 275 | } 276 | 277 | void* avltree_remove(avltree_t* me, void* k) 278 | { 279 | int i; 280 | 281 | for (i=0; i < me->size; ) 282 | { 283 | long r; 284 | node_t *n; 285 | 286 | n = &me->nodes[i]; 287 | 288 | /* couldn't find it */ 289 | if (!n->key) 290 | return NULL; 291 | 292 | r = me->cmp(n->key,k); 293 | 294 | if (r==0) 295 | { 296 | /* replacement */ 297 | int rep; 298 | 299 | me->count -= 1; 300 | 301 | k = n->key; 302 | 303 | rep = __previous_ordered_node(me,i); 304 | if (-1 == rep) 305 | { 306 | /* make sure the node is now blank */ 307 | n->key = NULL; 308 | } 309 | else 310 | { 311 | /* have r's left node become right node of r's parent. 312 | * NOTE: r by definition shouldn't have a right child */ 313 | __shift_up(me, __child_l(rep), __child_r(__parent(rep))); 314 | 315 | /* have r replace deleted node */ 316 | __shift_up(me,rep,i); 317 | } 318 | 319 | if (i!=0) 320 | __rebalance(me,__parent(i)); 321 | 322 | return k; 323 | } 324 | else if (r < 0) 325 | { 326 | i = __child_l(i); 327 | } 328 | else if (r > 0) 329 | { 330 | i = __child_r(i); 331 | } 332 | else 333 | { 334 | assert(0); 335 | } 336 | } 337 | 338 | /* couldn't find it */ 339 | return NULL; 340 | } 341 | 342 | void avltree_empty(avltree_t* me) 343 | { 344 | int i; 345 | 346 | for (i=0; isize; i++) 347 | { 348 | me->nodes[i].key = NULL; 349 | } 350 | } 351 | 352 | void avltree_insert(avltree_t* me, void* k, void* v) 353 | { 354 | int i; 355 | node_t* n; 356 | 357 | for (i=0; i < me->size; ) 358 | { 359 | n = &me->nodes[i]; 360 | 361 | /* found an empty slot */ 362 | if (!n->key) 363 | { 364 | n->key = k; 365 | n->val = v; 366 | me->count += 1; 367 | 368 | if (0 == i) 369 | return; 370 | 371 | __rebalance(me,__parent(i)); 372 | return; 373 | } 374 | 375 | long r = me->cmp(n->key,k); 376 | 377 | if (r==0) 378 | { 379 | /* we don't need to rebalance because we just overwrite this slot */ 380 | n->val = v; 381 | return; 382 | } 383 | else if (r < 0) 384 | { 385 | i = __child_l(i); 386 | } 387 | else if (r > 0) 388 | { 389 | i = __child_r(i); 390 | } 391 | else 392 | { 393 | assert(0); 394 | } 395 | } 396 | 397 | /* we're outside of the loop because we need to enlarge */ 398 | __enlarge(me); 399 | n = &me->nodes[i]; 400 | n->key = k; 401 | n->val = v; 402 | me->count += 1; 403 | } 404 | 405 | void* avltree_iterator_peek(avltree_t * h, avltree_iterator_t * iter) 406 | { 407 | if (iter->current_node < h->size) 408 | { 409 | node_t *next; 410 | 411 | next = &h->nodes[++iter->current_node]; 412 | if (next->key) 413 | return next; 414 | } 415 | 416 | return NULL; 417 | } 418 | 419 | void* avltree_iterator_peek_value(avltree_t * h, avltree_iterator_t * iter) 420 | { 421 | return avltree_get(h,avltree_iterator_peek(h,iter)); 422 | } 423 | 424 | int avltree_iterator_has_next(avltree_t * h, avltree_iterator_t * iter) 425 | { 426 | return NULL != avltree_iterator_peek(h,iter); 427 | } 428 | 429 | void *avltree_iterator_next_value(avltree_t * h, avltree_iterator_t * iter) 430 | { 431 | void* k; 432 | 433 | k = avltree_iterator_next(h,iter); 434 | if (!k) return NULL; 435 | return avltree_get(h,k); 436 | } 437 | 438 | void *avltree_iterator_next(avltree_t * h, avltree_iterator_t * iter) 439 | { 440 | node_t *n; 441 | node_t *next; 442 | 443 | assert(iter); 444 | 445 | n = &h->nodes[iter->current_node]; 446 | 447 | while (iter->current_node < h->size - 1) 448 | { 449 | next = &h->nodes[++iter->current_node]; 450 | if (next->key) 451 | break; 452 | } 453 | #if 0 454 | while (1) 455 | { 456 | next_id = __child_l(iter->current_node) 457 | next = &h->nodes[next_id]; 458 | if (!next->key) 459 | { 460 | next_id = __child_r(iter->current_node) 461 | next = &h->nodes[next_id]; 462 | if (!next->key) 463 | { 464 | int descendant; 465 | 466 | parent = __parent(iter->current_node); 467 | next_id = __parent(iter->current_node) 468 | while (__child_r(next_id) == parent) 469 | { 470 | parent = __parent(iter->current_node); 471 | next_id = __parent(iter->current_node) 472 | next_id = __child_r(next_id) 473 | next = &h->nodes[next_id]; 474 | } 475 | 476 | } 477 | } 478 | } 479 | #endif 480 | 481 | return n; 482 | } 483 | 484 | void avltree_iterator(avltree_t * h __attribute__((unused)), 485 | avltree_iterator_t * iter) 486 | { 487 | iter->current_node = 0; 488 | } 489 | 490 | -------------------------------------------------------------------------------- /avl_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef AVL_TREE_H 2 | #define AVL_TREE_H 3 | 4 | typedef struct { 5 | void* key; 6 | void* val; 7 | } node_t; 8 | 9 | typedef struct { 10 | /* size of array */ 11 | int size; 12 | int count; 13 | long (*cmp)( 14 | const void *e1, 15 | const void *e2); 16 | node_t *nodes; 17 | } avltree_t; 18 | 19 | typedef struct { 20 | int current_node; 21 | } avltree_iterator_t; 22 | 23 | avltree_t* avltree_new(long (*cmp)(const void *e1, const void *e2)); 24 | 25 | void* avltree_remove(avltree_t* me, void* k); 26 | 27 | int avltree_count(avltree_t* me); 28 | 29 | int avltree_size(avltree_t* me); 30 | 31 | int avltree_height(avltree_t* me); 32 | 33 | void avltree_empty(avltree_t* me); 34 | 35 | void avltree_insert(avltree_t* me, void* k, void* v); 36 | 37 | void* avltree_get(avltree_t* me, const void* k); 38 | 39 | void* avltree_get_from_idx(avltree_t* me, int idx); 40 | 41 | /** 42 | * Rotate on X: 43 | * Y = X's parent 44 | * Step A: Y becomes left child of X 45 | * Step B: X's left child's becomes Y's right child */ 46 | void avltree_rotate_left(avltree_t* me, int idx); 47 | 48 | /** 49 | * Rotate on X: 50 | * Y = X's left child 51 | * Step A: X becomes right child of X's left child 52 | * Step B: X's left child's right child becomes X's left child */ 53 | void avltree_rotate_right(avltree_t* me, int idx); 54 | 55 | 56 | /** 57 | * Initialise a new hash iterator over this hash 58 | * It is NOT safe to remove items while iterating. */ 59 | void avltree_iterator(avltree_t * h, avltree_iterator_t * iter); 60 | 61 | /** 62 | * Iterate to the next item on an iterator 63 | * @return next item key from iterator */ 64 | void *avltree_iterator_next(avltree_t * h, avltree_iterator_t * iter); 65 | 66 | /** 67 | * Iterate to the next item on an iterator 68 | * @return next item value from iterator */ 69 | void *avltree_iterator_next_value(avltree_t * h, avltree_iterator_t * iter); 70 | 71 | int avltree_iterator_has_next(avltree_t * h, avltree_iterator_t * iter); 72 | 73 | void* avltree_iterator_peek_value(avltree_t * h, avltree_iterator_t * iter); 74 | 75 | void* avltree_iterator_peek(avltree_t * h, avltree_iterator_t * iter); 76 | 77 | #endif /* AVL_TREE_H */ 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "array-avl-tree", 3 | "version": "0.0.1", 4 | "repo": "willemt/array-avl-tree", 5 | "description": "self balancing tree with slower inserts/removals than a red-black tree, but faster retrieval", 6 | "keywords": ["AVL tree", "self balancing", "set", "data structure"], 7 | "license": "BSD", 8 | "src": ["avl_tree.c", "avl_tree.h"] 9 | } 10 | -------------------------------------------------------------------------------- /tests/CuTest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "CuTest.h" 9 | 10 | /*-------------------------------------------------------------------------* 11 | * CuStr 12 | *-------------------------------------------------------------------------*/ 13 | 14 | char* CuStrAlloc(int size) 15 | { 16 | char* newStr = (char*) malloc( sizeof(char) * (size) ); 17 | return newStr; 18 | } 19 | 20 | char* CuStrCopy(const char* old) 21 | { 22 | int len = strlen(old); 23 | char* newStr = CuStrAlloc(len + 1); 24 | strcpy(newStr, old); 25 | return newStr; 26 | } 27 | 28 | /*-------------------------------------------------------------------------* 29 | * CuString 30 | *-------------------------------------------------------------------------*/ 31 | 32 | void CuStringInit(CuString* str) 33 | { 34 | str->length = 0; 35 | str->size = STRING_MAX; 36 | str->buffer = (char*) malloc(sizeof(char) * str->size); 37 | str->buffer[0] = '\0'; 38 | } 39 | 40 | CuString* CuStringNew(void) 41 | { 42 | CuString* str = (CuString*) malloc(sizeof(CuString)); 43 | str->length = 0; 44 | str->size = STRING_MAX; 45 | str->buffer = (char*) malloc(sizeof(char) * str->size); 46 | str->buffer[0] = '\0'; 47 | return str; 48 | } 49 | 50 | void CuStringResize(CuString* str, int newSize) 51 | { 52 | str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); 53 | str->size = newSize; 54 | } 55 | 56 | void CuStringAppend(CuString* str, const char* text) 57 | { 58 | int length; 59 | 60 | if (text == NULL) { 61 | text = "NULL"; 62 | } 63 | 64 | length = strlen(text); 65 | if (str->length + length + 1 >= str->size) 66 | CuStringResize(str, str->length + length + 1 + STRING_INC); 67 | str->length += length; 68 | strcat(str->buffer, text); 69 | } 70 | 71 | void CuStringAppendChar(CuString* str, char ch) 72 | { 73 | char text[2]; 74 | text[0] = ch; 75 | text[1] = '\0'; 76 | CuStringAppend(str, text); 77 | } 78 | 79 | void CuStringAppendFormat(CuString* str, const char* format, ...) 80 | { 81 | va_list argp; 82 | char buf[HUGE_STRING_LEN]; 83 | va_start(argp, format); 84 | vsprintf(buf, format, argp); 85 | va_end(argp); 86 | CuStringAppend(str, buf); 87 | } 88 | 89 | void CuStringInsert(CuString* str, const char* text, int pos) 90 | { 91 | int length = strlen(text); 92 | if (pos > str->length) 93 | pos = str->length; 94 | if (str->length + length + 1 >= str->size) 95 | CuStringResize(str, str->length + length + 1 + STRING_INC); 96 | memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); 97 | str->length += length; 98 | memcpy(str->buffer + pos, text, length); 99 | } 100 | 101 | /*-------------------------------------------------------------------------* 102 | * CuTest 103 | *-------------------------------------------------------------------------*/ 104 | 105 | void CuTestInit(CuTest* t, const char* name, TestFunction function) 106 | { 107 | t->name = CuStrCopy(name); 108 | t->failed = 0; 109 | t->ran = 0; 110 | t->message = NULL; 111 | t->function = function; 112 | t->jumpBuf = NULL; 113 | } 114 | 115 | CuTest* CuTestNew(const char* name, TestFunction function) 116 | { 117 | CuTest* tc = CU_ALLOC(CuTest); 118 | CuTestInit(tc, name, function); 119 | return tc; 120 | } 121 | 122 | void CuTestRun(CuTest* tc) 123 | { 124 | printf(" running %s\n", tc->name); 125 | 126 | jmp_buf buf; 127 | tc->jumpBuf = &buf; 128 | if (setjmp(buf) == 0) 129 | { 130 | tc->ran = 1; 131 | (tc->function)(tc); 132 | } 133 | tc->jumpBuf = 0; 134 | } 135 | 136 | static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) 137 | { 138 | char buf[HUGE_STRING_LEN]; 139 | 140 | sprintf(buf, "%s:%d: ", file, line); 141 | CuStringInsert(string, buf, 0); 142 | 143 | tc->failed = 1; 144 | tc->message = string->buffer; 145 | if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); 146 | } 147 | 148 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) 149 | { 150 | CuString string; 151 | 152 | CuStringInit(&string); 153 | if (message2 != NULL) 154 | { 155 | CuStringAppend(&string, message2); 156 | CuStringAppend(&string, ": "); 157 | } 158 | CuStringAppend(&string, message); 159 | CuFailInternal(tc, file, line, &string); 160 | } 161 | 162 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) 163 | { 164 | if (condition) return; 165 | CuFail_Line(tc, file, line, NULL, message); 166 | } 167 | 168 | void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 169 | const char* expected, const char* actual) 170 | { 171 | CuString string; 172 | if ((expected == NULL && actual == NULL) || 173 | (expected != NULL && actual != NULL && 174 | strcmp(expected, actual) == 0)) 175 | { 176 | return; 177 | } 178 | 179 | CuStringInit(&string); 180 | if (message != NULL) 181 | { 182 | CuStringAppend(&string, message); 183 | CuStringAppend(&string, ": "); 184 | } 185 | CuStringAppend(&string, "expected <"); 186 | CuStringAppend(&string, expected); 187 | CuStringAppend(&string, "> but was <"); 188 | CuStringAppend(&string, actual); 189 | CuStringAppend(&string, ">"); 190 | CuFailInternal(tc, file, line, &string); 191 | } 192 | 193 | void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 194 | int expected, int actual) 195 | { 196 | char buf[STRING_MAX]; 197 | if (expected == actual) return; 198 | sprintf(buf, "expected <%d> but was <%d>", expected, actual); 199 | CuFail_Line(tc, file, line, message, buf); 200 | } 201 | 202 | void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 203 | double expected, double actual, double delta) 204 | { 205 | char buf[STRING_MAX]; 206 | if (fabs(expected - actual) <= delta) return; 207 | sprintf(buf, "expected <%lf> but was <%lf>", expected, actual); 208 | CuFail_Line(tc, file, line, message, buf); 209 | } 210 | 211 | void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 212 | void* expected, void* actual) 213 | { 214 | char buf[STRING_MAX]; 215 | if (expected == actual) return; 216 | sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); 217 | CuFail_Line(tc, file, line, message, buf); 218 | } 219 | 220 | 221 | /*-------------------------------------------------------------------------* 222 | * CuSuite 223 | *-------------------------------------------------------------------------*/ 224 | 225 | void CuSuiteInit(CuSuite* testSuite) 226 | { 227 | testSuite->count = 0; 228 | testSuite->failCount = 0; 229 | } 230 | 231 | CuSuite* CuSuiteNew(void) 232 | { 233 | CuSuite* testSuite = CU_ALLOC(CuSuite); 234 | CuSuiteInit(testSuite); 235 | return testSuite; 236 | } 237 | 238 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) 239 | { 240 | assert(testSuite->count < MAX_TEST_CASES); 241 | testSuite->list[testSuite->count] = testCase; 242 | testSuite->count++; 243 | } 244 | 245 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) 246 | { 247 | int i; 248 | for (i = 0 ; i < testSuite2->count ; ++i) 249 | { 250 | CuTest* testCase = testSuite2->list[i]; 251 | CuSuiteAdd(testSuite, testCase); 252 | } 253 | } 254 | 255 | void CuSuiteRun(CuSuite* testSuite) 256 | { 257 | int i; 258 | for (i = 0 ; i < testSuite->count ; ++i) 259 | { 260 | CuTest* testCase = testSuite->list[i]; 261 | CuTestRun(testCase); 262 | if (testCase->failed) { testSuite->failCount += 1; } 263 | } 264 | } 265 | 266 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary) 267 | { 268 | int i; 269 | for (i = 0 ; i < testSuite->count ; ++i) 270 | { 271 | CuTest* testCase = testSuite->list[i]; 272 | CuStringAppend(summary, testCase->failed ? "F" : "."); 273 | } 274 | CuStringAppend(summary, "\n\n"); 275 | } 276 | 277 | void CuSuiteDetails(CuSuite* testSuite, CuString* details) 278 | { 279 | int i; 280 | int failCount = 0; 281 | 282 | if (testSuite->failCount == 0) 283 | { 284 | int passCount = testSuite->count - testSuite->failCount; 285 | const char* testWord = passCount == 1 ? "test" : "tests"; 286 | CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); 287 | } 288 | else 289 | { 290 | if (testSuite->failCount == 1) 291 | CuStringAppend(details, "There was 1 failure:\n"); 292 | else 293 | CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); 294 | 295 | for (i = 0 ; i < testSuite->count ; ++i) 296 | { 297 | CuTest* testCase = testSuite->list[i]; 298 | if (testCase->failed) 299 | { 300 | failCount++; 301 | CuStringAppendFormat(details, "%d) %s: %s\n", 302 | failCount, testCase->name, testCase->message); 303 | } 304 | } 305 | CuStringAppend(details, "\n!!!FAILURES!!!\n"); 306 | 307 | CuStringAppendFormat(details, "Runs: %d ", testSuite->count); 308 | CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); 309 | CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /tests/CuTest.h: -------------------------------------------------------------------------------- 1 | #ifndef CU_TEST_H 2 | #define CU_TEST_H 3 | 4 | #include 5 | #include 6 | 7 | /* CuString */ 8 | 9 | char* CuStrAlloc(int size); 10 | char* CuStrCopy(const char* old); 11 | 12 | #define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) 13 | 14 | #define HUGE_STRING_LEN 8192 15 | #define STRING_MAX 256 16 | #define STRING_INC 256 17 | 18 | typedef struct 19 | { 20 | int length; 21 | int size; 22 | char* buffer; 23 | } CuString; 24 | 25 | void CuStringInit(CuString* str); 26 | CuString* CuStringNew(void); 27 | void CuStringRead(CuString* str, const char* path); 28 | void CuStringAppend(CuString* str, const char* text); 29 | void CuStringAppendChar(CuString* str, char ch); 30 | void CuStringAppendFormat(CuString* str, const char* format, ...); 31 | void CuStringInsert(CuString* str, const char* text, int pos); 32 | void CuStringResize(CuString* str, int newSize); 33 | 34 | /* CuTest */ 35 | 36 | typedef struct CuTest CuTest; 37 | 38 | typedef void (*TestFunction)(CuTest *); 39 | 40 | struct CuTest 41 | { 42 | const char* name; 43 | TestFunction function; 44 | int failed; 45 | int ran; 46 | const char* message; 47 | jmp_buf *jumpBuf; 48 | }; 49 | 50 | void CuTestInit(CuTest* t, const char* name, TestFunction function); 51 | CuTest* CuTestNew(const char* name, TestFunction function); 52 | void CuTestRun(CuTest* tc); 53 | 54 | /* Internal versions of assert functions -- use the public versions */ 55 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); 56 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); 57 | void CuAssertStrEquals_LineMsg(CuTest* tc, 58 | const char* file, int line, const char* message, 59 | const char* expected, const char* actual); 60 | void CuAssertIntEquals_LineMsg(CuTest* tc, 61 | const char* file, int line, const char* message, 62 | int expected, int actual); 63 | void CuAssertDblEquals_LineMsg(CuTest* tc, 64 | const char* file, int line, const char* message, 65 | double expected, double actual, double delta); 66 | void CuAssertPtrEquals_LineMsg(CuTest* tc, 67 | const char* file, int line, const char* message, 68 | void* expected, void* actual); 69 | 70 | /* public assert functions */ 71 | 72 | #define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) 73 | #define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) 74 | #define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) 75 | 76 | #define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 77 | #define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 78 | #define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 79 | #define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 80 | #define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) 81 | #define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) 82 | #define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 83 | #define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 84 | 85 | #define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) 86 | #define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) 87 | 88 | /* CuSuite */ 89 | 90 | #define MAX_TEST_CASES 1024 91 | 92 | #define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) 93 | 94 | typedef struct 95 | { 96 | int count; 97 | CuTest* list[MAX_TEST_CASES]; 98 | int failCount; 99 | 100 | } CuSuite; 101 | 102 | 103 | void CuSuiteInit(CuSuite* testSuite); 104 | CuSuite* CuSuiteNew(void); 105 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); 106 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); 107 | void CuSuiteRun(CuSuite* testSuite); 108 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary); 109 | void CuSuiteDetails(CuSuite* testSuite, CuString* details); 110 | 111 | #endif /* CU_TEST_H */ 112 | -------------------------------------------------------------------------------- /tests/make-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Auto generate single AllTests file for CuTest. 4 | # Searches through all *.c files in the current directory. 5 | # Prints to stdout. 6 | # Author: Asim Jalis 7 | # Date: 01/08/2003 8 | 9 | FILES=$1 10 | 11 | #if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi 12 | 13 | echo ' 14 | 15 | /* This is auto-generated code. Edit at your own peril. */ 16 | #include 17 | #include "CuTest.h" 18 | 19 | ' 20 | 21 | cat $FILES | grep '^void Test' | 22 | sed -e 's/(.*$//' \ 23 | -e 's/$/(CuTest*);/' \ 24 | -e 's/^/extern /' 25 | 26 | echo \ 27 | ' 28 | 29 | void RunAllTests(void) 30 | { 31 | CuString *output = CuStringNew(); 32 | CuSuite* suite = CuSuiteNew(); 33 | 34 | ' 35 | cat $FILES | grep '^void Test' | 36 | sed -e 's/^void //' \ 37 | -e 's/(.*$//' \ 38 | -e 's/^/ SUITE_ADD_TEST(suite, /' \ 39 | -e 's/$/);/' 40 | 41 | echo \ 42 | ' 43 | CuSuiteRun(suite); 44 | CuSuiteSummary(suite, output); 45 | CuSuiteDetails(suite, output); 46 | printf("%s\\n", output->buffer); 47 | } 48 | 49 | int main() 50 | { 51 | RunAllTests(); 52 | return 0; 53 | } 54 | ' 55 | -------------------------------------------------------------------------------- /tests/test_avl_tree.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "CuTest.h" 9 | 10 | #include "avl_tree.h" 11 | 12 | static long __uint_compare( 13 | const void *e1, 14 | const void *e2 15 | ) 16 | { 17 | return e2 - e1; 18 | } 19 | 20 | void TestAVLTree_new_has_zero_nodes( 21 | CuTest * tc 22 | ) 23 | { 24 | avltree_t *t; 25 | 26 | t = avltree_new(__uint_compare); 27 | 28 | CuAssertTrue(tc, 0 == avltree_count(t)); 29 | } 30 | 31 | void TestAVLTree_insert_increases_count( 32 | CuTest * tc 33 | ) 34 | { 35 | avltree_t *t; 36 | 37 | t = avltree_new(__uint_compare); 38 | 39 | avltree_insert(t,(void*)10,(void*)1); 40 | CuAssertTrue(tc, 1 == avltree_count(t)); 41 | } 42 | 43 | void TestAVLTree_remove_increases_count( 44 | CuTest * tc 45 | ) 46 | { 47 | avltree_t *t; 48 | 49 | t = avltree_new(__uint_compare); 50 | 51 | avltree_insert(t,(void*)10,(void*)1); 52 | avltree_remove(t,(void*)10); 53 | CuAssertTrue(tc, 0 == avltree_count(t)); 54 | } 55 | 56 | void TestAVLTree_insert_increases_height( 57 | CuTest * tc 58 | ) 59 | { 60 | avltree_t *t; 61 | 62 | t = avltree_new(__uint_compare); 63 | 64 | avltree_insert(t,(void*)10,(void*)1); 65 | CuAssertTrue(tc, 1 == avltree_height(t)); 66 | avltree_insert(t,(void*)11,(void*)1); 67 | CuAssertTrue(tc, 2 == avltree_height(t)); 68 | } 69 | 70 | void TestAVLTree_rotate_left_keeps_count( 71 | CuTest * tc 72 | ) 73 | { 74 | avltree_t *t; 75 | 76 | t = avltree_new(__uint_compare); 77 | 78 | avltree_insert(t,(void*)10,(void*)1); 79 | avltree_insert(t,(void*)8,(void*)1); 80 | avltree_insert(t,(void*)12,(void*)1); 81 | avltree_insert(t,(void*)11,(void*)1); 82 | avltree_insert(t,(void*)13,(void*)1); 83 | avltree_rotate_left(t,2); 84 | CuAssertTrue(tc, 12 == (int)avltree_get_from_idx(t,0)); 85 | CuAssertTrue(tc, 10 == (int)avltree_get_from_idx(t,1)); 86 | CuAssertTrue(tc, 8 == (int)avltree_get_from_idx(t,3)); 87 | CuAssertTrue(tc, 11 == (int)avltree_get_from_idx(t,4)); 88 | CuAssertTrue(tc, 13 == (int)avltree_get_from_idx(t,2)); 89 | CuAssertTrue(tc, 5 == avltree_count(t)); 90 | CuAssertTrue(tc, 3 == avltree_height(t)); 91 | } 92 | 93 | void TestAVLTree_rotate_right_keeps_count( 94 | CuTest * tc 95 | ) 96 | { 97 | avltree_t *t; 98 | 99 | t = avltree_new(__uint_compare); 100 | 101 | avltree_insert(t,(void*)12,(void*)1); 102 | avltree_insert(t,(void*)10,(void*)1); 103 | avltree_insert(t,(void*)13,(void*)1); 104 | avltree_insert(t,(void*)11,(void*)1); 105 | avltree_insert(t,(void*)8,(void*)1); 106 | avltree_rotate_right(t,0); 107 | CuAssertTrue(tc, 10 == (int)avltree_get_from_idx(t,0)); 108 | CuAssertTrue(tc, 8 == (int)avltree_get_from_idx(t,1)); 109 | CuAssertTrue(tc, 12 == (int)avltree_get_from_idx(t,2)); 110 | CuAssertTrue(tc, 11 == (int)avltree_get_from_idx(t,5)); 111 | CuAssertTrue(tc, 13 == (int)avltree_get_from_idx(t,6)); 112 | CuAssertTrue(tc, 5 == avltree_count(t)); 113 | CuAssertTrue(tc, 3 == avltree_height(t)); 114 | } 115 | 116 | void TestAVLTree_double_rotate_keeps_count( 117 | CuTest * tc 118 | ) 119 | { 120 | avltree_t *t; 121 | 122 | t = avltree_new(__uint_compare); 123 | 124 | avltree_insert(t,(void*)12,(void*)1); 125 | avltree_insert(t,(void*)10,(void*)1); 126 | avltree_insert(t,(void*)13,(void*)1); 127 | avltree_insert(t,(void*)11,(void*)1); 128 | avltree_insert(t,(void*)8,(void*)1); 129 | avltree_rotate_right(t,0); 130 | avltree_rotate_left(t,2); 131 | CuAssertTrue(tc, 12 == (int)avltree_get_from_idx(t,0)); 132 | CuAssertTrue(tc, 10 == (int)avltree_get_from_idx(t,1)); 133 | CuAssertTrue(tc, 8 == (int)avltree_get_from_idx(t,3)); 134 | CuAssertTrue(tc, 11 == (int)avltree_get_from_idx(t,4)); 135 | CuAssertTrue(tc, 13 == (int)avltree_get_from_idx(t,2)); 136 | CuAssertTrue(tc, 5 == avltree_count(t)); 137 | CuAssertTrue(tc, 3 == avltree_height(t)); 138 | } 139 | 140 | void TestAVLTree_inserting_a_list_maintains_logn_height( 141 | CuTest * tc 142 | ) 143 | { 144 | avltree_t *t; 145 | 146 | t = avltree_new(__uint_compare); 147 | 148 | avltree_insert(t,(void*)10,(void*)1); 149 | avltree_insert(t,(void*)11,(void*)1); 150 | CuAssertTrue(tc, 2 == avltree_height(t)); 151 | avltree_insert(t,(void*)12,(void*)1); 152 | CuAssertTrue(tc, 2 == avltree_height(t)); 153 | avltree_insert(t,(void*)13,(void*)1); 154 | CuAssertTrue(tc, 3 == avltree_height(t)); 155 | avltree_insert(t,(void*)14,(void*)1); 156 | CuAssertTrue(tc, 3 == avltree_height(t)); 157 | avltree_insert(t,(void*)15,(void*)1); 158 | CuAssertTrue(tc, 3 == avltree_height(t)); 159 | } 160 | 161 | void TestAVLTree_remove_keeps_tree_balanced( 162 | CuTest * tc 163 | ) 164 | { 165 | avltree_t *t; 166 | 167 | t = avltree_new(__uint_compare); 168 | 169 | avltree_insert(t,(void*)12,(void*)1); 170 | avltree_insert(t,(void*)10,(void*)1); 171 | avltree_insert(t,(void*)13,(void*)1); 172 | avltree_insert(t,(void*)11,(void*)1); 173 | avltree_insert(t,(void*)8,(void*)1); 174 | avltree_remove(t,(void*)10); 175 | CuAssertTrue(tc, 12 == (int)avltree_get_from_idx(t,0)); 176 | CuAssertTrue(tc, 8 == (int)avltree_get_from_idx(t,1)); 177 | CuAssertTrue(tc, 13 == (int)avltree_get_from_idx(t,2)); 178 | CuAssertTrue(tc, 11 == (int)avltree_get_from_idx(t,4)); 179 | CuAssertTrue(tc, 4 == avltree_count(t)); 180 | CuAssertTrue(tc, 3 == avltree_height(t)); 181 | } 182 | 183 | --------------------------------------------------------------------------------