├── .gitignore ├── README.md ├── src ├── primitives.h ├── lru_cache.h ├── stack.h ├── priority_queue.h ├── primitives.c ├── queue.h ├── matrix.h ├── bmp_image.h ├── linked_hashmap.h ├── dlinked_list.h ├── queue.c ├── stack.c ├── lru_cache.c ├── arraylist.h ├── set.h ├── linked_hashmap.c ├── priority_queue.c ├── avl_tree.h ├── hashmap.h ├── linked_list.h ├── arraylist.c ├── set.c ├── matrix.c ├── hashmap.c ├── linked_list.c ├── avl_tree.c ├── bmp_image.c └── dlinked_list.c └── tests ├── stack_tests.h ├── assert.h ├── arraylist_tests.h ├── assert.c ├── run_tests.c ├── stack_tests.c └── arraylist_tests.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.a 3 | *.o 4 | *.bmp 5 | .vscode 6 | *.out 7 | a 8 | run_tests 9 | objdump/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stdutil 2 | 3 | Generic data structure, and utilities library for the C programming language. 4 | -------------------------------------------------------------------------------- /src/primitives.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_PRIMITIVES_H 2 | #define UTIL_PRIMITIVES_H 3 | 4 | #include 5 | 6 | int *Integer(int i); 7 | 8 | double *Double(double d); 9 | 10 | float *Float(float f); 11 | 12 | char *Character(char c); 13 | 14 | short *Short(short s); 15 | 16 | long *Long(long l); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /tests/stack_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_STACK_TESTS_H 2 | #define STDUTIL_STACK_TESTS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../src/stack.h" 8 | #include "assert.h" 9 | #include "../src/primitives.h" 10 | 11 | bool test_create_stack(); 12 | 13 | bool test_stack_push(); 14 | 15 | bool test_stack_peek(); 16 | 17 | bool test_stack_pop(); 18 | 19 | bool test_stack_ensure_capacity(); 20 | 21 | #endif -------------------------------------------------------------------------------- /tests/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_ASSERT_H 2 | #define STDUTIL_ASSERT_H 3 | 4 | #include 5 | #include 6 | 7 | void int_assert_equal(int val0, int val1, int assert_code); 8 | 9 | void int_assert_nequal(int val0, int val1, int assert_code); 10 | 11 | void int_array_assert_equal(int **arr0, int *arr1, int size, int assert_code); 12 | 13 | void int_array_assert_nequal(int **arr0, int *arr1, int size, int assert_code); 14 | 15 | void bool_assert_equal(bool bool0, bool bool1, int assert_code); 16 | 17 | #endif -------------------------------------------------------------------------------- /src/lru_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_LRUCACHE_H 2 | #define STDUTIL_LRUCACHE_H 3 | 4 | #include 5 | #include "hashmap.h" 6 | #include "dlinked_list.h" 7 | typedef struct lru_cache { 8 | hashmap *node_map; 9 | dlinked_list *dll; 10 | size_t capacity; 11 | } lru_cache; 12 | 13 | lru_cache *create_cache(size_t capacity); 14 | 15 | void *cache_put(lru_cache *cache, void * element); 16 | 17 | void *cache_get(lru_cache *cache, void *element); 18 | 19 | void *cache_get_lru(lru_cache *cache); 20 | 21 | void *cache_get_mru(lru_cache *cache); 22 | 23 | #endif -------------------------------------------------------------------------------- /tests/arraylist_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_ARRAYLIST_TESTS_H 2 | #define STDUTIL_ARRAYLIST_TESTS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "assert.h" 8 | #include "limits.h" 9 | #include "../src/arraylist.h" 10 | #include "../src/primitives.h" 11 | 12 | bool test_create_arraylist(); 13 | 14 | bool test_create_arraylist_OOM(); 15 | 16 | bool test_al_add(); 17 | 18 | bool test_al_addAt(); 19 | 20 | bool test_al_set(); 21 | 22 | bool test_ensure_capacity(); 23 | 24 | bool test_al_get(); 25 | 26 | bool test_remove(); 27 | 28 | bool test_sort(); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_STACK_H 2 | #define UTIL_STACK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "arraylist.h" 8 | 9 | typedef struct stack { 10 | void **elements; 11 | size_t size, capacity; 12 | } stack; 13 | 14 | stack *create_stack(size_t initial_capacity); 15 | 16 | bool push(stack *target, void *element); 17 | 18 | void* peek(stack *target); 19 | 20 | void* pop(stack *target); 21 | 22 | size_t s_size(stack *target); 23 | 24 | size_t s_capacity(stack *target); 25 | 26 | bool s_ensure_capacity(stack *target, size_t new_capacity); 27 | 28 | void s_clear(stack *target); 29 | 30 | void s_delete(stack *target); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/priority_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_PRIORITYQUEUE_H 2 | #define STDUTIL_PRIORITYQUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct priority_queue { 9 | void **data; 10 | size_t size, capacity; 11 | 12 | signed char (*comparator) (void *loperand, void *roperand); 13 | } priority_queue; 14 | 15 | priority_queue *create_priority_queue(size_t capacity, signed char (*comparator) (void *loperand, void *roperand)); 16 | 17 | priority_queue *heapify(void **data, size_t size, signed char (*comparator) (void *loperand, void *roperand)); 18 | 19 | bool pq_add(priority_queue *queue, void *data); 20 | 21 | void *pq_remove(priority_queue *queue); 22 | 23 | void *pq_peek(priority_queue *queue); 24 | 25 | #endif -------------------------------------------------------------------------------- /src/primitives.c: -------------------------------------------------------------------------------- 1 | #include "primitives.h" 2 | 3 | int *Integer(int i) { 4 | int* ptr = (int*) malloc(sizeof(int)); 5 | *ptr = i; 6 | return ptr; 7 | } 8 | 9 | double *Double(double d) { 10 | double* ptr = (double*) malloc(sizeof(double)); 11 | *ptr = d; 12 | return ptr; 13 | } 14 | 15 | float *Float(float f) { 16 | float* ptr = (float*) malloc(sizeof(float)); 17 | *ptr = f; 18 | return ptr; 19 | } 20 | 21 | char *Character(char c) { 22 | char* ptr = (char*) malloc(sizeof(char)); 23 | *ptr = c; 24 | return ptr; 25 | } 26 | 27 | short *Short(short s) { 28 | short* ptr = (short*) malloc(sizeof(short)); 29 | *ptr = s; 30 | return ptr; 31 | } 32 | 33 | long *Long(long l) { 34 | long* ptr = (long*) malloc(sizeof(long)); 35 | *ptr = l; 36 | return ptr; 37 | } 38 | -------------------------------------------------------------------------------- /src/queue.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_QUEUE_H 2 | #define UTIL_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct queue { 10 | void **data; 11 | size_t front, size, capacity; 12 | } queue; 13 | 14 | queue *create_queue(size_t initialCapacity); 15 | 16 | /* 17 | Adds an element to the back of the queue. 18 | */ 19 | 20 | bool enqueue(queue *target, void *element); 21 | 22 | /* 23 | Removes an element from the front of the queue. 24 | */ 25 | 26 | void *dequeue(queue *target); 27 | 28 | /* 29 | Removes all data from queue. 30 | 31 | */ 32 | 33 | void q_clear(queue *target); 34 | 35 | /* 36 | Removes and frees all data from queue. 37 | */ 38 | 39 | void q_delete(queue *target); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_MATRIX_H 2 | #define STDUTIL_MATRIX_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct fMatrix { 12 | float *elements; 13 | size_t rows, cols; 14 | } fMatrix; 15 | 16 | fMatrix create_fMatrix(size_t rows, size_t cols); 17 | 18 | float fMatrix_get(fMatrix *mat, size_t row, size_t col); 19 | 20 | bool fMatrix_set(fMatrix *mat, size_t row, size_t col, float data); 21 | 22 | fMatrix fMatrix_multiply(fMatrix lmat, fMatrix rmat); 23 | 24 | fMatrix fMatrix_add(fMatrix lmat, fMatrix rmat); 25 | 26 | float fMatrix_determinant(fMatrix *mat); 27 | 28 | void fMatrix_scale(fMatrix *mat, float scalar); 29 | 30 | void fMatrix_print(fMatrix *mat); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/bmp_image.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_IMAGEBMP_H 2 | #define STDUTIL_IMAGEBMP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "matrix.h" 10 | 11 | typedef struct pixel { 12 | unsigned char R, G, B, A; 13 | } pixel; 14 | 15 | typedef struct bmp_image { 16 | size_t width, height, trailer_size; 17 | unsigned char *file_header, *bitmap_header, *trailer; 18 | pixel* pixels; 19 | } bmp_image; 20 | 21 | bmp_image openImageBMP(const char *path); 22 | 23 | pixel* pixel_at(bmp_image *image, unsigned int col, unsigned int row); 24 | 25 | bool save_bmp_image(bmp_image *image, const char *location); 26 | 27 | void dispose_bmp_image(bmp_image *image); 28 | 29 | bmp_image convolution(bmp_image *image, struct fMatrix *kernel); 30 | 31 | #endif -------------------------------------------------------------------------------- /tests/assert.c: -------------------------------------------------------------------------------- 1 | #include "assert.h" 2 | 3 | extern jmp_buf break_point; 4 | 5 | void int_assert_equal(int val0, int val1, int assert_code) { 6 | if (val0 != val1) { 7 | longjmp(break_point, assert_code); 8 | } 9 | } 10 | 11 | void int_assert_nequal(int val0, int val1, int assert_code) { 12 | if (val0 == val1) { 13 | longjmp(break_point, assert_code); 14 | } 15 | } 16 | 17 | void int_array_assert_equal(int **arr0, int *arr1, int size, int assert_code) { 18 | for (int i = 0; i < size; ++i) { 19 | if (*(arr0[i]) != arr1[i]) { 20 | longjmp(break_point, assert_code); 21 | } 22 | } 23 | } 24 | 25 | void int_array_assert_nequal(int **arr0, int *arr1, int size, int assert_code) { 26 | for (int i = 0; i < size; ++i) { 27 | if (*(arr0[i]) != arr1[i]) { 28 | return; 29 | } 30 | } 31 | longjmp(break_point, assert_code); 32 | } 33 | 34 | void bool_assert_equal(bool bool0, bool bool1, int assert_code) { 35 | if (bool0 != bool1) { 36 | longjmp(break_point, assert_code); 37 | } 38 | } -------------------------------------------------------------------------------- /src/linked_hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_LINKED_HASHMAP_H 2 | #define STDUTIL_LINKED_HASHMAP_H 3 | 4 | #include 5 | #include "arraylist.h" 6 | #include "hashmap.h" 7 | #include "dlinked_list.h" 8 | 9 | typedef struct linked_hashmap { 10 | hashmap *map; 11 | dlinked_list *list; 12 | } linked_hashmap; 13 | 14 | linked_hashmap *create_lhashmap(size_t initial_capacity, float lf); 15 | 16 | void *lhm_put(linked_hashmap *lhm, void *key, void *value); 17 | 18 | void *lhm_remove(linked_hashmap *lhm, void *key); 19 | 20 | void *lhm_get(linked_hashmap *lhm, void *key); 21 | 22 | bool lhm_contains_key(linked_hashmap *lhm, void *key); 23 | 24 | /** 25 | * @brief Returns an arraylist of keys not guaranteed to be in any particular order. 26 | */ 27 | 28 | arraylist *lhm_key_set(linked_hashmap *map); 29 | 30 | /** 31 | * @brief Returns an arraylist with values of the hashmap in the order they were inserted. 32 | */ 33 | 34 | 35 | arraylist *lhm_key_set(linked_hashmap *map); 36 | 37 | arraylist *lhm_values(linked_hashmap *map); 38 | 39 | void lhm_clear(linked_hashmap *map); 40 | 41 | void lhm_delete(linked_hashmap *map); 42 | 43 | dlist_node *iterator(linked_hashmap *map); 44 | 45 | #endif -------------------------------------------------------------------------------- /src/dlinked_list.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_DLINKEDLIST_H 2 | #define STDUTIL_DLINKEDLIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct dlist_node { 9 | struct dlist_node *next, *prev; 10 | void *data; 11 | } dlist_node; 12 | 13 | typedef struct dlinked_list { 14 | struct dlist_node *head, *tail, *iterator; 15 | size_t size; 16 | } dlinked_list; 17 | 18 | dlinked_list *array_to_dlinkedlist(void **array, size_t size); 19 | 20 | dlinked_list *create_dlinkedlist(); 21 | 22 | bool dll_add_first(dlinked_list *target, void* element); 23 | 24 | bool dll_add_last(dlinked_list *target, void* element); 25 | 26 | bool dll_add_at(dlinked_list *target, size_t position, void *element); 27 | 28 | void *dll_set(dlinked_list *target, size_t position, void *element); 29 | 30 | void *dll_get(dlinked_list *target, size_t index); 31 | 32 | void *dll_next(dlinked_list *target); 33 | 34 | bool dll_has_next(dlinked_list *target); 35 | 36 | void dll_reset(dlinked_list *target); 37 | 38 | void *dll_remove(dlinked_list *target, size_t position); 39 | 40 | void *dll_remove_first(dlinked_list *target); 41 | 42 | void *dll_remove_last(dlinked_list *target); 43 | 44 | dlist_node *dll_remove_node(dlinked_list *target, size_t position); 45 | 46 | void dll_clear(dlinked_list *target); 47 | 48 | void dll_delete(dlinked_list *target); 49 | 50 | #endif -------------------------------------------------------------------------------- /tests/run_tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "arraylist_tests.h" 4 | #include "stack_tests.h" 5 | #include "../src/dlinked_list.h" 6 | #include "../src/hashmap.h" 7 | #include "../src/lru_cache.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | test_create_arraylist(); 11 | test_create_arraylist_OOM(); 12 | test_al_add(); 13 | test_al_addAt(); 14 | test_al_set(); 15 | test_ensure_capacity(); 16 | test_al_get(); 17 | test_remove(); 18 | test_create_stack(); 19 | test_stack_push(); 20 | test_stack_peek(); 21 | test_stack_pop(); 22 | test_stack_ensure_capacity(); 23 | lru_cache *cache = create_cache(4); 24 | int *k = Integer(4); 25 | cache_put(cache, Integer(3)); 26 | cache_put(cache, k); 27 | cache_put(cache, Integer(5)); 28 | cache_put(cache, Integer(6)); 29 | 30 | printf("Before reputting 4:\n"); 31 | dlist_node *iterator = cache->dll->head; 32 | while (iterator) { 33 | int *data = (int *) iterator->data; 34 | printf("%d, ", *data); 35 | iterator = iterator->next; 36 | } 37 | printf("\n"); 38 | 39 | cache_put(cache, k); 40 | iterator = cache->dll->head; 41 | while (iterator) { 42 | int *data = (int *) iterator->data; 43 | printf("%d, ", *data); 44 | iterator = iterator->next; 45 | } 46 | printf("\n"); 47 | 48 | int *lru = (int *) cache_get_lru(cache); 49 | int *mru = (int *) cache_get_mru(cache); 50 | printf("MRU: %d, LRU: %d\n", *mru, *lru); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | #include "queue.h" 2 | 3 | queue *create_queue(size_t initialCapacity) { 4 | queue *q = (queue *) malloc(sizeof(queue)); 5 | if (!q) { 6 | return NULL; 7 | } 8 | q->data = (void **) malloc(initialCapacity * sizeof(void *)); 9 | if (!q->data) { 10 | free(q); 11 | return NULL; 12 | } 13 | memset(q->data, 0, initialCapacity * sizeof(void *)); 14 | q->capacity = initialCapacity; 15 | q->size = 0; 16 | q->front = 0; 17 | return q; 18 | } 19 | 20 | static bool resize(queue *target) { 21 | void **new_mem = (void **) malloc(2 * target->capacity * sizeof(void *)); 22 | if (!new_mem) { 23 | return false; 24 | } 25 | for (size_t i = 0; i < target->size; ++i) { 26 | new_mem[i] = target->data[(i + target->front) % target->capacity]; 27 | } 28 | free(target->data); 29 | target->data = new_mem; 30 | target->capacity = 2 * target->capacity; 31 | return true; 32 | } 33 | 34 | bool enqueue(queue *target, void *element) { 35 | if (target->size >= target->capacity && !resize(target)) { 36 | return false; 37 | } 38 | target->data[(target->front + target->size) % target->capacity] = element; 39 | ++target->size; 40 | return true; 41 | } 42 | 43 | void *dequeue(queue *target) { 44 | void *ret = NULL; 45 | if (target->size > 0) { 46 | ret = target->data[target->front]; 47 | target->front = (++target->front) % target->capacity; 48 | --target->size; 49 | } 50 | return ret; 51 | } 52 | 53 | void q_clear(queue *target) { 54 | target->front = 0; 55 | target->size = 0; 56 | } 57 | 58 | void q_delete(queue *target) { 59 | for (size_t i = 0; i < target->size; ++i) { 60 | free(target->data[(i + target->front) % target->capacity]); 61 | } 62 | target->front = 0; 63 | target->size = 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | #include "stack.h" 2 | 3 | static const int DEFAULT_CAPACITY = 10; 4 | 5 | static bool resize(stack *target, size_t new_capacity) { 6 | void **new_mem = (void **) malloc(new_capacity * sizeof(void *)); 7 | if (!new_mem) { 8 | return false; 9 | } 10 | memcpy(new_mem, target->elements, target->size * sizeof(void *)); 11 | free(target->elements); 12 | target->elements = new_mem; 13 | target->capacity = new_capacity; 14 | return true; 15 | } 16 | 17 | stack *create_stack(size_t initial_capacity) { 18 | if (initial_capacity == 0) { 19 | initial_capacity = DEFAULT_CAPACITY; 20 | } 21 | stack *s = (stack *) malloc(sizeof(stack)); 22 | if (!s) { 23 | return NULL; 24 | } 25 | void **mem = (void **) malloc(sizeof(void *) * initial_capacity); 26 | if (!mem) { 27 | free(s); 28 | return NULL; 29 | } 30 | s->size = 0; 31 | s->capacity = initial_capacity; 32 | s->elements = mem; 33 | return s; 34 | } 35 | 36 | bool push(stack *target, void *element) { 37 | if (target->size >= target->capacity && !resize(target, 2 * target->capacity)) { 38 | return false; 39 | } 40 | target->elements[target->size] = element; 41 | ++(target->size); 42 | return true; 43 | } 44 | 45 | void *peek(stack *target) { 46 | if (!target->size) { 47 | return NULL; 48 | } 49 | return target->elements[target->size - 1]; 50 | } 51 | 52 | void *pop(stack* target) { 53 | if (!target->size) { 54 | return NULL; 55 | } 56 | return target->elements[--(target->size)]; 57 | } 58 | 59 | size_t s_size(stack* target) { 60 | return target->size; 61 | } 62 | 63 | size_t s_capacity(stack* target) { 64 | return target->capacity; 65 | } 66 | 67 | bool s_ensure_capacity(stack* target, size_t new_capacity) { 68 | if (new_capacity < target->size) { 69 | return false; 70 | } 71 | return resize(target, new_capacity); 72 | } 73 | 74 | void s_clear(stack* target) { 75 | target->size = 0; 76 | } 77 | 78 | void s_delete(stack *target) { 79 | for (size_t i = 0; i < target->size; ++i) { 80 | free(target->elements[i]); 81 | } 82 | target->size = 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/lru_cache.c: -------------------------------------------------------------------------------- 1 | #include "lru_cache.h" 2 | 3 | lru_cache *create_cache(size_t capacity) { 4 | lru_cache *cache = (lru_cache *) malloc(sizeof(lru_cache)); 5 | if (!cache) { 6 | return NULL; 7 | } 8 | cache->dll = create_dlinkedlist(); 9 | if (!cache->dll) { 10 | free(cache); 11 | return NULL; 12 | } 13 | 14 | cache->node_map = create_hashmap(2 * capacity, 0.5f); 15 | if (!cache->node_map) { 16 | free(cache->dll); 17 | free(cache); 18 | return NULL; 19 | } 20 | cache->capacity = capacity; 21 | return cache; 22 | } 23 | 24 | void *cache_put(lru_cache *cache, void *element) { 25 | dlist_node *node = hm_get(cache->node_map, element); 26 | if (node) { 27 | if (node->prev) { 28 | node->prev->next = node->next; 29 | } else { 30 | return NULL; 31 | } 32 | if (node->next) { 33 | node->next->prev = node->prev; 34 | } else { 35 | cache->dll->tail = node->prev; 36 | } 37 | node->next = cache->dll->head; 38 | node->prev = NULL; 39 | cache->dll->head->prev = node; 40 | cache->dll->head = node; 41 | return NULL; 42 | } else { 43 | void *removed_key = NULL; 44 | if (cache->dll->size + 1 > cache->capacity) { 45 | removed_key = dll_remove_last(cache->dll); 46 | hm_remove(cache->node_map, removed_key); 47 | } 48 | dll_add_first(cache->dll, element); 49 | hm_put(cache->node_map, element, cache->dll->head); 50 | return removed_key; 51 | } 52 | } 53 | 54 | void *cache_get(lru_cache *cache, void *element) { 55 | dlist_node *node = hm_get(cache->node_map, element); 56 | if (node) { 57 | if (node->prev) { 58 | node->prev->next = node->next; 59 | } else { 60 | return NULL; 61 | } 62 | if (node->next) { 63 | node->next->prev = node->prev; 64 | } else { 65 | cache->dll->tail = node->prev; 66 | } 67 | node->next = cache->dll->head; 68 | node->prev = NULL; 69 | cache->dll->head->prev = node; 70 | cache->dll->head = node; 71 | return node->data; 72 | } 73 | return NULL; 74 | } 75 | 76 | void *cache_get_lru(lru_cache *cache) { 77 | return cache->dll->tail->data; 78 | } 79 | 80 | void *cache_get_mru(lru_cache *cache) { 81 | return cache->dll->head->data ; 82 | } -------------------------------------------------------------------------------- /src/arraylist.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_ARRAYLIST_H 2 | #define UTIL_ARRAYLIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | The 'ArrayList.h' and 'ArrayList.c' files provide the declarations and implementations of 13 | a generic, dynamically sized, array. 14 | 15 | */ 16 | 17 | typedef struct arraylist { 18 | void **elements; 19 | size_t size, capacity; 20 | } arraylist; 21 | 22 | /* 23 | Creates an ArrayList with an initial_capacity of [initial_capacity] 24 | */ 25 | 26 | arraylist *create_arraylist(size_t initial_capacity); 27 | 28 | /* 29 | Adds an element to the end of the arraylist. 30 | 31 | If the arraylist is at capacity, it will 32 | be resized to 2 * capacity, and the new element will be added. 33 | */ 34 | 35 | bool al_add(arraylist *target, void *element); 36 | 37 | /* 38 | Inserts an element to the ArrayList at the specified index. The specified index 39 | must be less than the ArrayList's size. 40 | */ 41 | 42 | bool al_add_at(arraylist *target, size_t position, void *element); 43 | 44 | /* 45 | Ensures that the ArrayList must be able to contain [new_capacity] number of elements. 46 | */ 47 | 48 | bool al_ensure_capacity(arraylist *target, size_t new_capacity); 49 | 50 | /* 51 | Assigns the element at index [position] to [element] 52 | calls free() on the existing element. 53 | 54 | Returns the data previously stored there 55 | */ 56 | 57 | void *al_set(arraylist* target, size_t position, void* element); 58 | 59 | /* 60 | Returns the element at index [position] of the ArrayList. 61 | */ 62 | 63 | void *al_get(arraylist *target, size_t position); 64 | 65 | /* 66 | Removes the element at index [position] of the ArrayList and returns it. 67 | It is up to the programmer to call free() the returned pointer. 68 | */ 69 | 70 | void *al_remove(arraylist *target, size_t position); 71 | 72 | /* 73 | Sorts the ArrayList using the quick sort algorithm. The programmer must provide a function for comparing two generic elements. 74 | 75 | The comparator function must return a negative number if cmpl < cmpr, 76 | a positive number if cmpl > cmpr, 77 | and 0 if cmpl == cmpr 78 | */ 79 | 80 | void sort(arraylist *target, int (*comparator)(const void *cmpl, const void *cmpr)); 81 | 82 | /* 83 | Deletes all contents of the ArrayList. Sets the size of the ArrayList to 0 84 | and calls free() on all of the elements stored within the ArrayList. 85 | */ 86 | 87 | void al_delete(arraylist *target); 88 | 89 | /* 90 | Removes all contents of the ArrayList, sets the size and capacity of the ArrayList to 0 91 | and sets all of the indices to null. 92 | */ 93 | 94 | void al_clear(arraylist *target); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/set.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_SET_H 2 | #define STDUTIL_SET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "hashmap.h" 9 | 10 | struct set_entry { 11 | void *data; 12 | bool removed; 13 | }; 14 | 15 | typedef struct set { 16 | 17 | /* Backing array for the elements in the set. */ 18 | 19 | struct set_entry *data; 20 | 21 | /* 22 | Number of elements within the set 23 | */ 24 | 25 | size_t cardinality, capacity; 26 | 27 | /* 28 | Hash function must return the same hash for two keys that are deemed equal by the comparator. 29 | 30 | Example: 31 | If comparator(key1, key2) == true, then hash_function(key1) == hash_function(key2). 32 | */ 33 | 34 | size_t (*hash_function)(const void* key); 35 | 36 | /* 37 | The programmer must implement an equivalence relation as a comparator function. That is, it must be: 38 | 39 | Let a, b, c be elements within set S. 40 | 41 | Reflexive: If comparator(a, b) is true, then comparator(b, a) must also be true. 42 | 43 | Transitive: If comparator(a, b) is true, and comparator(b, c) is true, then comparator(a, c) must also be true. 44 | 45 | Symmetric: comparator(a, a) must be true. 46 | */ 47 | 48 | bool (*comparator)(const void *l_operand, const void *r_operand); 49 | 50 | /* 51 | Load factor of the set, value between 0 and 1. Resizes the backing array of the set when size / capacity > lf 52 | */ 53 | 54 | float lf; 55 | 56 | } set; 57 | 58 | /* 59 | Initializes an empty set with the specified initial capacity using default hash function and comparator. 60 | */ 61 | 62 | struct set *create_set(size_t initial_capacity); 63 | 64 | /* 65 | Adds an element to the set. If the element was already present in the set, this function will leave the set unchanged and return false. 66 | If element was not already in the set, adds element to the set and returns true. 67 | 68 | Returns false if specified element is null or OOM exception occurs 69 | */ 70 | 71 | bool set_add(struct set *set, void *element); 72 | 73 | /* 74 | Removes an element from the set. If the element is present within the set, removes it and returns a pointer to the data it stored. 75 | If the element is not present within the set, leaves set unchanged and returns NULL. 76 | 77 | Returns NULL if specified element is NULL. 78 | */ 79 | 80 | void *set_remove(struct set *set, void *element); 81 | 82 | /* 83 | Returns true if the specified element is contained within the set, false otherwise. 84 | */ 85 | 86 | bool set_contains(struct set *set, void *element); 87 | 88 | /* 89 | Removes every element within the set. 90 | */ 91 | 92 | void set_clear(struct set *set); 93 | 94 | /* 95 | Removes and frees every element from within the set. 96 | */ 97 | 98 | void set_delete(struct set *set); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/linked_hashmap.c: -------------------------------------------------------------------------------- 1 | #include "linked_hashmap.h" 2 | 3 | linked_hashmap *create_lhashmap(size_t initial_capacity, float lf) { 4 | linked_hashmap *lhm = (linked_hashmap *) malloc(sizeof(linked_hashmap)); 5 | if (!lhm) { 6 | return NULL; 7 | } 8 | lhm->map = create_hashmap(initial_capacity, lf); 9 | if (!lhm->map) { 10 | free(lhm); 11 | return NULL; 12 | } 13 | lhm->list = create_dlinkedlist(); 14 | if (!lhm->list) { 15 | free(lhm->map); 16 | free(lhm); 17 | return NULL; 18 | } 19 | return lhm; 20 | } 21 | 22 | void *lhm_put(linked_hashmap *lhm, void *key, void *value) { 23 | dlist_node *node = hm_get(lhm->map, key); 24 | if (node) { 25 | /* Key already exists in the hashmap */ 26 | void *old_value = node->data; 27 | node->data = value; 28 | return old_value; 29 | } 30 | dll_add_last(lhm->list, value); 31 | hm_put(lhm->map, key, lhm->list->tail); 32 | return NULL; 33 | } 34 | 35 | void *lhm_remove(linked_hashmap *lhm, void *key) { 36 | dlist_node *node = hm_remove(lhm->map, key); 37 | 38 | void *data = NULL; 39 | if (node) { 40 | data = node->data; 41 | if (node->prev) { 42 | node->prev->next = node->next; 43 | } else { 44 | lhm->list->head = node->next; 45 | } 46 | 47 | if (node->next) { 48 | node->next->prev = node->prev; 49 | } else { 50 | lhm->list->tail = node->prev; 51 | } 52 | --lhm->list->size; 53 | data = node->data; 54 | free(node); 55 | } 56 | return data; 57 | } 58 | 59 | void *lhm_get(linked_hashmap *lhm, void *key) { 60 | dlist_node *node = hm_get(lhm->map, key); 61 | if (node) { 62 | return node->data; 63 | } 64 | return NULL; 65 | 66 | } 67 | 68 | bool lhm_contains_key(linked_hashmap *lhm, void *key) { 69 | return hm_get(lhm->map, key) != NULL; 70 | } 71 | 72 | arraylist *lhm_key_set(linked_hashmap *map) { 73 | return hm_key_set(map->map); 74 | } 75 | 76 | arraylist *lhm_values(linked_hashmap *map) { 77 | arraylist *ret = (arraylist *) malloc(sizeof(arraylist)); 78 | if (!ret) { 79 | return NULL; 80 | } 81 | 82 | void **data = (void **) malloc(sizeof(void *) * map->list->size); 83 | if (!data) { 84 | free(ret); 85 | return NULL; 86 | } 87 | ret->elements = data; 88 | ret->capacity = map->list->size; 89 | ret->size = map->list->size; 90 | 91 | dlist_node *iterator = map->list->head; 92 | size_t i = 0; 93 | while (iterator) { 94 | data[i] = iterator->data; 95 | iterator = iterator->next; 96 | ++i; 97 | } 98 | return ret; 99 | } 100 | 101 | void lhm_clear(linked_hashmap *map) { 102 | hm_clear(map->map); 103 | dll_clear(map->list); 104 | } 105 | 106 | void lhm_delete(linked_hashmap *map) { 107 | hm_delete(map->map); 108 | dll_delete(map->list); 109 | } 110 | 111 | dlist_node *iterator(linked_hashmap *map) { 112 | return map->list->iterator; 113 | } -------------------------------------------------------------------------------- /src/priority_queue.c: -------------------------------------------------------------------------------- 1 | #include "priority_queue.h" 2 | #include 3 | 4 | priority_queue *create_priority_queue(size_t capacity, signed char (*comparator) (void *loperand, void *roperand)) { 5 | priority_queue *pq = heapify(NULL, 0, comparator); 6 | return pq; 7 | } 8 | 9 | static void downheap(priority_queue *pq, size_t index) { 10 | if (index > pq->size / 2) { 11 | return; 12 | } 13 | void *current = pq->data[index], *leftChild = pq->data[2 * index], *rightChild = pq->data[2 * index + 1]; 14 | int leftDifference = pq->comparator(current, leftChild), rightDifference = 0; 15 | if (rightChild) { 16 | rightDifference = pq->comparator(current, rightChild); 17 | } 18 | if (leftDifference > 0 && rightDifference > 0) { 19 | if (pq->comparator(leftChild, rightChild) < 0) { 20 | pq->data[2 * index] = current; 21 | pq->data[index] = leftChild; 22 | downheap(pq, 2 * index); 23 | } else { 24 | pq->data[2 * index + 1] = current; 25 | pq->data[index] = rightChild; 26 | downheap(pq, 2 * index + 1); 27 | } 28 | } else if (leftDifference > 0) { 29 | pq->data[2 * index] = current; 30 | pq->data[index] = leftChild; 31 | downheap(pq, 2 * index); 32 | } else if (rightDifference > 0) { 33 | pq->data[2 * index + 1] = current; 34 | pq->data[index] = rightChild; 35 | downheap(pq, 2 * index + 1); 36 | } 37 | } 38 | 39 | priority_queue *heapify(void **data, size_t size, signed char (*comparator) (void *loperand, void *roperand)) { 40 | priority_queue *pq = (priority_queue *) malloc(sizeof(priority_queue)); 41 | if (!pq) { 42 | return NULL; 43 | } 44 | pq->capacity = 2 * size + 1; 45 | pq->data = (void **) malloc(pq->capacity * sizeof(void *)); 46 | if (!pq->data) { 47 | free(pq); 48 | return NULL; 49 | } 50 | pq->size = 0; 51 | pq->comparator = comparator; 52 | 53 | size_t j = 1; 54 | for (size_t i = 0; i < size; ++i) { 55 | if (data[i]) { 56 | pq->data[j] = data[i]; 57 | ++j; 58 | } 59 | } 60 | pq->size = j - 1; 61 | for (size_t i = pq->size / 2; i > 0; --i) { 62 | downheap(pq, i); 63 | } 64 | return pq; 65 | } 66 | 67 | static void upheap(priority_queue *pq, size_t index) { 68 | if (index <= 1) { 69 | return; 70 | } 71 | void *parent = pq->data[index / 2]; 72 | if (pq->comparator(pq->data[index], parent) < 0) { 73 | pq->data[index / 2] = pq->data[index]; 74 | pq->data[index] = parent; 75 | upheap(pq, index / 2); 76 | } 77 | } 78 | 79 | bool pq_add(priority_queue *queue, void *data) { 80 | if (queue->size + 1 >= queue->capacity) { 81 | queue->capacity *= 2; 82 | void **new_array = (void **) malloc(queue->capacity * sizeof(void *)); 83 | if (!new_array) { 84 | return false; 85 | } 86 | memcpy((void *) &(new_array[1]), (void *) &(queue->data[1]), queue->size); 87 | free(queue->data); 88 | queue->data = new_array; 89 | } 90 | ++queue->size; 91 | queue->data[queue->size] = data; 92 | upheap(queue, queue->size); 93 | return true; 94 | } 95 | 96 | void *pq_remove(priority_queue *queue) { 97 | void *value = queue->data[1]; 98 | queue->data[1] = queue->data[queue->size]; 99 | --queue->size; 100 | downheap(queue, 1); 101 | return value; 102 | } 103 | 104 | void *pq_peek(priority_queue *queue) { 105 | return queue->data[1]; 106 | } -------------------------------------------------------------------------------- /src/avl_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_BINARYTREE_H 2 | #define UTIL_BINARYTREE_H 3 | 4 | #include "arraylist.h" 5 | 6 | typedef struct treenode { 7 | 8 | /* 9 | Generic data to data contained in tree node 10 | */ 11 | 12 | void *data; 13 | 14 | /* 15 | Left and right respective children of the node. 16 | 17 | A value of 'NULL' represents no child. 18 | */ 19 | 20 | struct treenode *left, *right; 21 | 22 | /* 23 | Maximum number of tree levels below current node. 24 | */ 25 | 26 | unsigned char height; 27 | 28 | /* 29 | Balance factor: Difference of the heights of the left child and right child 30 | 31 | bf = left->height - right->height 32 | */ 33 | 34 | signed char bf; 35 | 36 | /* 37 | Number of copies of duplicate values stored in this treenode. 38 | */ 39 | 40 | unsigned int count; 41 | } treenode; 42 | 43 | typedef struct tree { 44 | 45 | /* 46 | Pointer to the root of the tree. 47 | */ 48 | 49 | treenode *root; 50 | 51 | /* 52 | Total number of nodes within the tree. 53 | */ 54 | 55 | size_t size; 56 | 57 | /* 58 | Compares the data stored in the tree. 59 | 60 | Must return a negative number if loperand < roperand, 61 | a positive number if loperand > roperand, 62 | zero if loperand = roperand. 63 | */ 64 | 65 | const signed char (*comparator)(const void *loperand, const void *roperand); 66 | } tree; 67 | 68 | /* 69 | Takes data contained in an array, and constructs a balanced tree. 70 | 71 | Leaves original array and elements of the original array unchanged. 72 | */ 73 | 74 | tree *create_tree(void **array, size_t size, const signed char (*comparator)(const void *loperand, const void *roperand)); 75 | 76 | /* 77 | Adds a new node containing the specified data to its correct position within the tree, and increments size. 78 | 79 | Maintains that the tree is balanced. 80 | */ 81 | 82 | void tree_add(tree *t, void *data); 83 | 84 | /* 85 | Removes and returns the node containing the specified data from the tree, and decrements size. 86 | 87 | Maintains that the tree is balanced. 88 | */ 89 | 90 | void *tree_remove(tree *t, void *data); 91 | 92 | /* 93 | Searches for and returns the data specified from the tree. 94 | 95 | Leaves the tree unchanged. 96 | */ 97 | 98 | void *tree_get(tree *t, void *data); 99 | 100 | /* 101 | Frees every node within the tree, sets root to NULL, and sets size to 0. 102 | 103 | Does not free data stored within the tree. 104 | */ 105 | 106 | void tree_clear(tree *t); 107 | 108 | /* 109 | Frees every node within the tree, sets root to NULL, and sets size to 0. 110 | 111 | Frees data stored within the tree. 112 | */ 113 | 114 | void tree_delete(tree *t); 115 | 116 | /* 117 | Returns an arraylist of data stored in the tree from a preorder traversal. 118 | */ 119 | 120 | arraylist *preorder(tree *t); 121 | 122 | /* 123 | Returns an arraylist of data stored in the tree from an inorder traversal. 124 | */ 125 | 126 | arraylist *inorder(tree *t); 127 | 128 | /* 129 | Returns an arraylist of data stored in the tree from a postorder traversal. 130 | */ 131 | 132 | arraylist *postorder(tree *t); 133 | 134 | /* 135 | Returns an arraylist of data stored in the tree from a levelorder traversal. 136 | */ 137 | 138 | arraylist *levelorder(tree *t); 139 | 140 | #endif -------------------------------------------------------------------------------- /src/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef STDUTIL_HASHMAP_H 2 | #define STDUTIL_HASHMAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "arraylist.h" 10 | 11 | typedef struct map_entry { 12 | void *key; 13 | void *value; 14 | bool removed; 15 | } map_entry; 16 | 17 | typedef struct hashmap { 18 | map_entry *table; 19 | size_t capacity, size; 20 | float load_factor; 21 | 22 | /* 23 | Hash function must return the same hash for two keys that are deemed equal by the comparator. 24 | 25 | Example: 26 | If comparator(key1, key2) == true, then hash_function(key1) == hash_function(key2). 27 | */ 28 | 29 | size_t (*hash_function)(const void *key); 30 | 31 | /* 32 | The programmer must implement an equivalence relation as a comparator function. That is, it must be: 33 | 34 | Let a, b, c be elements within set S. 35 | 36 | Reflexive: If comparator(a, b) is true, then comparator(b, a) must also be true. 37 | 38 | Transitive: If comparator(a, b) is true, and comparator(b, c) is true, then comparator(a, c) must also be true. 39 | 40 | Symmetric: comparator(a, a) must be true. 41 | */ 42 | 43 | bool (*comparator)(const void *key0, const void *key1); 44 | } hashmap; 45 | 46 | /* 47 | Creates an empty hashmap with specified initial capacity and loadfactor, using default hash function and comparator. 48 | 49 | It is recommended that the initial capacity be a prime number. 50 | 51 | It is up to the programmer to specify a function that returns a boolean which compares keys. 52 | */ 53 | 54 | hashmap *create_hashmap(size_t initial_capacity, float lf); 55 | 56 | /* 57 | Puts a specified key-value pair into the hashmap, returns the associated value if the key already exists, null otherwise. 58 | */ 59 | 60 | void *hm_put(hashmap *map, void *key, void *value); 61 | 62 | /* 63 | Removes the MapEntry with specified key, returns the key-value pair formerly stored there, null if key does not exist. 64 | */ 65 | 66 | map_entry *hm_remove(hashmap *map, void *key); 67 | 68 | /* 69 | Returns the value associated with a specified key, NULL if the hashmap does not contain the key. 70 | */ 71 | 72 | void *hm_get(hashmap *map, void *key); 73 | 74 | /* 75 | Returns true if a specified key is contained in the hashmap, false otherwise. 76 | */ 77 | 78 | bool hm_contains_key(hashmap *map, void *key); 79 | 80 | /* 81 | Returns an ArrayList of all keys stored in the hashmap 82 | */ 83 | 84 | arraylist *hm_key_set(hashmap *map); 85 | 86 | /* 87 | Returns an ArrayList of all values stored in the HashMap 88 | */ 89 | 90 | arraylist *hm_values(hashmap *map); 91 | 92 | /* 93 | Computes the hash of input "key" using the multiplicative hashing formula: h(K) = floor(aK mod W / (W/M)), 94 | where a and W are relatively prime and M = UINT_MAX, and a is a large number with random distribution of 0s and 1s. 95 | Generates values between [0, M - 1]. 96 | */ 97 | 98 | size_t default_hash_function(const void *key); 99 | 100 | /* 101 | Default comparator function, checks if pointers have the same value. 102 | */ 103 | 104 | bool default_comparator(const void *key0, const void *key1); 105 | 106 | /* 107 | Calls free() only on the hashmap entries. Sets every entry in the backing array to null. 108 | */ 109 | 110 | void hm_clear(hashmap *map); 111 | 112 | /* 113 | Calls free() on every key, value, and hashmap entry. Sets every entry in the backing array to null. 114 | */ 115 | 116 | void hm_delete(hashmap *map); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /src/linked_list.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_LINKEDLIST_H 2 | #define UTIL_LINKEDLIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct list_node { 9 | void *element; 10 | struct list_node *next; 11 | } list_node; 12 | 13 | typedef struct linked_list { 14 | list_node *head, *iterator, *tail; 15 | size_t size; 16 | } linked_list; 17 | 18 | /* 19 | Creates a linked list and initializes it to the size specified by 20 | [initial_size] by creating the necessary list nodes; 21 | */ 22 | 23 | linked_list *array_to_linkedlist(void **array, size_t size); 24 | 25 | /* 26 | Creates and initializes an empty linked list 27 | */ 28 | 29 | linked_list *create_linkedlist(); 30 | 31 | /* 32 | Creates a new list node with the specified data and prepends it to the front of the linked list. 33 | */ 34 | 35 | void ll_add_first(linked_list *target, void* element); 36 | 37 | /* 38 | Creates a new list node with the data specified by [element] and appends it 39 | to the end of the linked list. 40 | */ 41 | 42 | void ll_add_last(linked_list *target, void* element); 43 | 44 | /* 45 | Inserts a new list node with the data specified by [element] and inserts it to 46 | the position in the linked list specified by [position] 47 | */ 48 | 49 | void ll_add_at(linked_list *target, size_t position, void* element); 50 | 51 | /* 52 | Overwrites the data in the list node specified by [position] with the new 53 | data [element] 54 | */ 55 | 56 | void* ll_set(linked_list *target, size_t position, void* element); 57 | 58 | /* 59 | Returns the number of nodes in the linked list 60 | */ 61 | 62 | size_t ll_size(linked_list *target); 63 | 64 | /* 65 | Returns a pointer to the data stored in the list node specified by [index] 66 | */ 67 | 68 | void* ll_get(linked_list *target, size_t index); 69 | 70 | /* 71 | Returns the data stored in the list node that the iterator was originally pointing at 72 | then moves the iterator to the next node in the linked list. 73 | 74 | Once the iterator reaches the end of the list, it will return NULL and reset itself to the 75 | head of the linked list. 76 | */ 77 | 78 | void* ll_next(linked_list *target); 79 | 80 | /* 81 | Returns true if the iterator is not pointing to the last element of the linked list 82 | */ 83 | 84 | bool ll_has_next(linked_list *target); 85 | 86 | /* 87 | Resets the iterator to the head of the linked list. 88 | */ 89 | 90 | void ll_reset(linked_list *target); 91 | 92 | /* 93 | Frees the list node specified by [position] and returns the data stored by that list node. 94 | */ 95 | 96 | void* ll_remove(linked_list *target, size_t position); 97 | 98 | /* 99 | Removes and returns the list node. 100 | */ 101 | 102 | list_node *ll_remove_node(linked_list *target, size_t position); 103 | 104 | /* 105 | Frees every node within the linkedlist. Sets head, tail, and iterator to null. Sets size to 0. 106 | 107 | Leaves data within the linkedlist unchanged. 108 | */ 109 | 110 | void ll_clear(linked_list *target); 111 | 112 | /* 113 | Frees every node within the linkedlist. Sets head, tail, and iterator to null. Sets size to 0. 114 | 115 | Frees data within the linkedlist. 116 | */ 117 | 118 | void ll_delete(linked_list *target); 119 | 120 | /* 121 | Attaches the linked list [right_list] to the end of [left_list] 122 | 123 | right_list is NOT freed as a result of this operation 124 | */ 125 | 126 | void join(linked_list *left_list, linked_list *right_list); 127 | 128 | /* 129 | Splits the specified linkedlist at the index split (inclusive). 130 | 131 | Returns the split linked list. 132 | */ 133 | 134 | linked_list *split(linked_list *target, size_t split); 135 | 136 | #endif -------------------------------------------------------------------------------- /src/arraylist.c: -------------------------------------------------------------------------------- 1 | #include "arraylist.h" 2 | 3 | static const int DEFAULT_CAPACITY = 10; 4 | 5 | static bool resize(arraylist *target, size_t new_capacity) { 6 | void **new_mem = (void **) malloc(new_capacity * sizeof(void *)); 7 | if (!new_mem) { 8 | return false; 9 | } 10 | memcpy(new_mem, target->elements, sizeof(void *) * target->size); 11 | free(target->elements); 12 | target->elements = new_mem; 13 | target->capacity = new_capacity; 14 | return true; 15 | } 16 | 17 | arraylist *create_arraylist(size_t initial_capacity) { 18 | if (!initial_capacity) { 19 | initial_capacity = DEFAULT_CAPACITY; 20 | } 21 | arraylist *new = (arraylist *) malloc(sizeof(arraylist)); 22 | if (!new) { 23 | return NULL; 24 | } 25 | new->elements = (void **) calloc(initial_capacity, sizeof(void *)); 26 | if (!new->elements) { 27 | free(new); 28 | return NULL; 29 | } 30 | new->size = 0; 31 | new->capacity = initial_capacity; 32 | return new; 33 | } 34 | 35 | bool al_add(arraylist *target, void *element) { 36 | if (target->size >= target->capacity && !resize(target, 2 * target->capacity)) { 37 | return false; 38 | } 39 | target->elements[target->size] = element; 40 | ++(target->size); 41 | return true; 42 | } 43 | 44 | bool al_add_at(arraylist *target, size_t position, void *element) { 45 | if (position > target->size || (target->size >= target->capacity && !resize(target, 2 * target->capacity))) { 46 | return false; 47 | } 48 | 49 | for (size_t i = target->size; i > position; --i) { 50 | target->elements[i] = target->elements[i - 1]; 51 | } 52 | target->elements[position] = element; 53 | ++target->size; 54 | return true; 55 | } 56 | 57 | bool al_ensure_capacity(arraylist* target, size_t new_capacity) { 58 | if (new_capacity < target->size) { 59 | return false; 60 | } 61 | return resize(target, new_capacity); 62 | } 63 | 64 | void *al_set(arraylist *target, size_t position, void *element) { 65 | void *ret = NULL; 66 | if (position < target->size) { 67 | ret = target->elements[position]; 68 | target->elements[position] = element; 69 | } 70 | return ret; 71 | } 72 | 73 | void *al_get(arraylist *target, size_t position) { 74 | if (position < target->size) { 75 | return target->elements[position]; 76 | } 77 | return NULL; 78 | } 79 | 80 | void *al_remove(arraylist *target, size_t position) { 81 | void *ret = NULL; 82 | if (position < target->size) { 83 | ret = target->elements[position]; 84 | for (size_t i = position; i < target->size - 1; ++i) { 85 | target->elements[i] = target->elements[i + 1]; 86 | } 87 | --target->size; 88 | } 89 | return ret; 90 | } 91 | 92 | static void quicksort(arraylist *arr, size_t start, size_t end, int (*comparator)(const void* cmpl, const void* cmpr)) { 93 | if (end - start <= 1) { 94 | return; 95 | } 96 | size_t pivot = rand() % (end - start) + start; 97 | void *swap = arr->elements[pivot]; 98 | arr->elements[pivot] = arr->elements[start]; 99 | arr->elements[start] = swap; 100 | size_t i = start + 1, j = end - 1; 101 | while (i <= j) { 102 | while (i <= j && (*comparator)(arr->elements[start], arr->elements[i]) > 0) { 103 | ++i; 104 | } 105 | while (i <= j && (*comparator)(arr->elements[start], arr->elements[j]) < 0) { 106 | --j; 107 | } 108 | if (i <= j) { 109 | swap = arr->elements[j]; 110 | arr->elements[j] = arr->elements[i]; 111 | arr->elements[i] = swap; 112 | 113 | ++i; 114 | --j; 115 | } 116 | } 117 | swap = arr->elements[j]; 118 | arr->elements[j] = arr->elements[start]; 119 | arr->elements[start] = swap; 120 | quicksort(arr, start, j, comparator); 121 | quicksort(arr, j + 1, end, comparator); 122 | } 123 | 124 | void sort(arraylist *target, int (*comparator)(const void *cmpl, const void *cmpr)) { 125 | time_t t; 126 | srand((unsigned) time(&t)); 127 | quicksort(target, 0, target->size, comparator); 128 | } 129 | 130 | void al_delete(arraylist *target) { 131 | for (size_t i = 0; i < target->size; ++i) { 132 | free(target->elements[i]); 133 | } 134 | target->size = 0; 135 | } 136 | 137 | void al_clear(arraylist *target) { 138 | target->size = 0; 139 | } 140 | -------------------------------------------------------------------------------- /src/set.c: -------------------------------------------------------------------------------- 1 | #include "set.h" 2 | 3 | static bool resize(struct set *set) { 4 | size_t new_capacity = 2 * set->capacity + 1; 5 | struct set_entry *new_array = (struct set_entry*) malloc(new_capacity * sizeof(struct set_entry)); 6 | 7 | if (!new_array) { 8 | return false; 9 | } 10 | 11 | for (size_t i = 0; i < new_capacity; ++i) { 12 | new_array[i].data = NULL; 13 | new_array[i].removed = false; 14 | } 15 | 16 | size_t i = 0, j = 0; 17 | while (i < set->capacity && j < set->cardinality) { 18 | if (set->data[i].data) { 19 | if (!set->data[i].removed) { 20 | size_t index = set->hash_function(set->data[i].data) % new_capacity; 21 | while (new_array[index].data) { 22 | ++index; 23 | index = index % new_capacity; 24 | } 25 | new_array[index].data = set->data[i].data; 26 | ++j; 27 | } 28 | } 29 | ++i; 30 | } 31 | free(set->data); 32 | set->data = new_array; 33 | set->capacity = new_capacity; 34 | return true; 35 | } 36 | 37 | struct set *create_set(size_t initial_capacity) { 38 | struct set *set = (struct set *) malloc(sizeof(struct set)); 39 | if (!set) { 40 | return NULL; 41 | } 42 | set->data = (struct set_entry *) malloc(initial_capacity * sizeof(struct set_entry)); 43 | 44 | if (!set->data) { 45 | free(set); 46 | return NULL; 47 | } 48 | 49 | for (size_t i = 0; i < initial_capacity; ++i) { 50 | set->data[i].data = NULL; 51 | set->data[i].removed = false; 52 | } 53 | set->cardinality = 0; 54 | set->capacity = initial_capacity; 55 | set->lf = 0.67f; 56 | set->hash_function = &default_hash_function; 57 | set->comparator = &default_comparator; 58 | return set; 59 | } 60 | 61 | bool set_add(struct set *set, void *element) { 62 | if (!element) { 63 | return false; 64 | } 65 | 66 | if ((float) (set->cardinality + 1) / set->capacity > set->lf && !resize(set)) { 67 | /* OOM returns false */ 68 | return false; 69 | } 70 | 71 | size_t i = 0, j = 0, index = set->hash_function(element) % set->capacity, removedIndex; 72 | bool foundRemoved = false; 73 | while (i < set->capacity && (!foundRemoved || j < set->cardinality)) { 74 | if (!set->data[index].data) { 75 | if (foundRemoved) { 76 | set->data[removedIndex].data = element; 77 | set->data[removedIndex].removed = false; 78 | } else { 79 | set->data[index].data = element; 80 | } 81 | ++set->cardinality; 82 | return true; 83 | } else if (set->comparator(element, set->data[index].data)) { 84 | if (!set->data[index].removed) { 85 | return false; 86 | } else if (foundRemoved) { 87 | index = removedIndex; 88 | } 89 | set->data[index].data = element; 90 | set->data[index].removed = false; 91 | ++set->cardinality; 92 | return true; 93 | } else if (set->data[index].removed) { 94 | removedIndex = index; 95 | foundRemoved = true; 96 | } else { 97 | ++j; 98 | } 99 | ++i; 100 | index = ++index % set->capacity; 101 | } 102 | return false; 103 | } 104 | 105 | void *set_remove(struct set *set, void *element) { 106 | if (!element) { 107 | return NULL; 108 | } 109 | 110 | size_t i = 0, j = 0, index = set->hash_function(element) % set->capacity; 111 | while (i < set->capacity && j < set->cardinality) { 112 | if (!set->data[index].data) { 113 | return false; 114 | } else if (set->comparator(element, set->data[index].data)) { 115 | if (set->data[index].removed) { 116 | return NULL; 117 | } else { 118 | set->data[index].removed = true; 119 | --set->cardinality; 120 | return set->data[index].data; 121 | } 122 | } else if (!set->data[index].removed) { 123 | ++j; 124 | } 125 | ++i; 126 | ++index; 127 | index = index % set->capacity; 128 | } 129 | return NULL; 130 | } 131 | 132 | bool set_contains(struct set *set, void *element) { 133 | if (!element) { 134 | return false; 135 | } 136 | 137 | size_t i = 0, j = 0, index = set->hash_function(element) % set->capacity; 138 | while (i < set->capacity && j < set->cardinality) { 139 | if (!set->data[index].data) { 140 | return false; 141 | } else if (set->comparator(element, set->data[index].data)) { 142 | return !set->data[index].removed; 143 | } else if (!set->data[index].removed) { 144 | ++j; 145 | } 146 | ++i; 147 | ++index; 148 | index = index % set->capacity; 149 | } 150 | return false; 151 | } 152 | 153 | void set_clear(struct set *set) { 154 | for (size_t i = 0; i < set->capacity; ++i) { 155 | set->data[i].data = NULL; 156 | set->data[i].removed = false; 157 | } 158 | set->cardinality = 0; 159 | } 160 | 161 | void set_delete(struct set *set) { 162 | for (size_t i = 0; i < set->capacity; ++i) { 163 | free(set->data[i].data); 164 | set->data[i].data = NULL; 165 | set->data[i].removed = false; 166 | } 167 | set->cardinality = 0; 168 | } 169 | -------------------------------------------------------------------------------- /src/matrix.c: -------------------------------------------------------------------------------- 1 | #include "matrix.h" 2 | 3 | fMatrix create_fMatrix(size_t num_rows, size_t num_cols) { 4 | fMatrix matrix = {.elements = NULL, .rows = -1, .cols = -1}; 5 | matrix.elements = (float *) malloc(num_rows * num_cols * sizeof(float)); 6 | if (matrix.elements != NULL) { 7 | matrix.rows = num_rows; 8 | matrix.cols = num_cols; 9 | for (size_t i = 0; i < matrix.rows; ++i) { 10 | for (size_t j = 0; j < matrix.cols; ++j) { 11 | if (i == j) { 12 | matrix.elements[i * matrix.cols + j] = 1.0f; 13 | } else { 14 | matrix.elements[i * matrix.cols + j] = 0.0f; 15 | } 16 | } 17 | } 18 | } 19 | return matrix; 20 | } 21 | 22 | float fMatrix_get(fMatrix *mat, size_t row, size_t col) { 23 | return mat->elements[row * mat->rows + col]; 24 | } 25 | 26 | bool fMatrix_set(fMatrix *mat, size_t row, size_t col, float data) { 27 | if (row < mat->rows && col < mat->cols) { 28 | mat->elements[row * mat->cols + col] = data; 29 | return true; 30 | } else { 31 | return false; 32 | } 33 | } 34 | 35 | fMatrix fMatrix_multiply(fMatrix lmat, fMatrix rmat) { 36 | fMatrix matrix = {.elements = NULL, .rows = -1, .cols = -1}; 37 | if (lmat.cols == rmat.rows) { 38 | matrix.elements = malloc(lmat.rows * rmat.cols * sizeof(float)); 39 | if (matrix.elements == NULL) { 40 | return matrix; 41 | } 42 | matrix.rows = lmat.rows; 43 | matrix.cols = rmat.cols; 44 | for (size_t i = 0; i < matrix.rows * matrix.cols; ++i) { 45 | size_t r = i / matrix.cols, c = i % matrix.cols; 46 | float accumulator = 0; 47 | for (size_t j = 0; j < lmat.cols; ++j) { 48 | accumulator += lmat.elements[r * lmat.cols + j] * rmat.elements[j * rmat.cols + c]; 49 | } 50 | matrix.elements[i] = accumulator; 51 | } 52 | } 53 | return matrix; 54 | } 55 | 56 | fMatrix fMatrix_add(fMatrix lmat, fMatrix rmat) { 57 | fMatrix sum = {.elements = NULL, .rows = -1, .cols = -1}; 58 | if (lmat.cols == rmat.cols && lmat.rows == rmat.rows) { 59 | sum.elements = calloc(lmat.rows * lmat.cols, sizeof(float)); 60 | if (sum.elements == NULL) { 61 | return sum; 62 | } 63 | sum.rows = lmat.rows; 64 | sum.cols = lmat.cols; 65 | for (size_t i = 0; i < lmat.cols * lmat.rows; ++i) { 66 | sum.elements[i] = lmat.elements[i] + rmat.elements[i]; 67 | } 68 | } 69 | return sum; 70 | } 71 | 72 | static fMatrix *createSubMatrix(fMatrix *parent, size_t row, size_t col) { 73 | fMatrix *subMatrix = (fMatrix*) malloc(sizeof(fMatrix)); 74 | subMatrix->rows = parent->rows - 1; 75 | subMatrix->cols = parent->cols - 1; 76 | subMatrix->elements = (float*) malloc(subMatrix->rows * subMatrix->cols * sizeof(float)); 77 | for (unsigned int i = 0; i < parent->rows; ++i) { 78 | if (i == row) { 79 | continue; 80 | } 81 | int y_offset = 0; 82 | if (i > row) { 83 | y_offset = 1; 84 | } 85 | 86 | for (unsigned int j = 0; j < parent->cols; ++j) { 87 | if (j == col) { 88 | continue; 89 | } 90 | int x_offset = 0; 91 | if (j > col) { 92 | x_offset = 1; 93 | } 94 | fMatrix_set(subMatrix, i - y_offset, j - x_offset, fMatrix_get(parent, i, j)); 95 | } 96 | } 97 | return subMatrix; 98 | } 99 | 100 | float fMatrix_determinant(fMatrix *mat) { 101 | if (mat->rows != mat->cols) { 102 | return 0.0f; 103 | } 104 | if (mat->rows == 1) { 105 | return mat->elements[0]; 106 | } 107 | bool isNegative = false; 108 | float determinant = 0.0f; 109 | for (size_t i = 0; i < mat->cols; ++i) { 110 | fMatrix *subMatrix = createSubMatrix(mat, 0, i); 111 | float term = fMatrix_get(mat, 0, i) * fMatrix_determinant(subMatrix); 112 | free(subMatrix); 113 | 114 | if (isNegative) { 115 | determinant -= term; 116 | } else { 117 | determinant += term; 118 | } 119 | isNegative = !isNegative; 120 | } 121 | return determinant; 122 | } 123 | 124 | void fMatrix_scale(fMatrix *mat, float scalar) { 125 | for (size_t i = 0; i < mat->cols * mat->rows; ++i) { 126 | mat->elements[i] *= scalar; 127 | } 128 | } 129 | 130 | void fMatrix_print(fMatrix *mat) { 131 | char useless_buffer[16]; 132 | signed char max_length[mat->cols]; 133 | 134 | for (size_t i = 0; i < mat->cols; ++i) { 135 | max_length[i] = 0; 136 | for (size_t j = 0; j < mat->rows; ++j) { 137 | signed char length = (signed char)sprintf(useless_buffer, "%f", mat->elements[j * mat->cols + i]); 138 | if (length > max_length[i]) { 139 | max_length[i] = length; 140 | } 141 | } 142 | } 143 | for (size_t i = 0; i < mat->rows; ++i) { 144 | printf("[ "); 145 | for (size_t j = 0; j < mat->cols - 1; ++j) { 146 | signed char length = (signed char) sprintf(useless_buffer, "%f", mat->elements[i * mat->cols + j]); 147 | for (signed char k = 0; k < max_length[i] - length; ++k) { 148 | printf(" "); 149 | } 150 | printf("%.2f, ", mat->elements[i * mat->cols + j]); 151 | } 152 | signed char length = (signed char) sprintf(useless_buffer, "%f", mat->elements[mat->cols * (i + 1) - 1]); 153 | for (signed char k = 0; k < max_length[i] - length; ++k) { 154 | printf(" "); 155 | } 156 | printf("%.2f]\n", mat->elements[mat->cols * (i + 1) - 1]); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/hashmap.c: -------------------------------------------------------------------------------- 1 | #include "hashmap.h" 2 | 3 | static bool resize(hashmap *map) { 4 | size_t new_capacity = 2 * map->capacity + 1; 5 | map_entry *new_table = (map_entry *) calloc(new_capacity, sizeof(map_entry)); 6 | if (!new_table) { 7 | return false; 8 | } 9 | size_t i = 0, j = 0; 10 | while (i < map->capacity && j < map->size) { 11 | if (map->table[i].key) { 12 | if (!map->table[i].removed) { 13 | size_t index = map->hash_function(map->table[i].key) % new_capacity; 14 | while (new_table[index].key) { 15 | ++index; 16 | index = index % new_capacity; 17 | } 18 | new_table[index] = map->table[i]; 19 | ++j; 20 | } 21 | } 22 | } 23 | free(map->table); 24 | map->table = new_table; 25 | map->capacity = new_capacity; 26 | return true; 27 | } 28 | 29 | hashmap *create_hashmap(size_t initial_capacity, float lf) { 30 | hashmap *hm = (hashmap *) malloc(sizeof(hashmap)); 31 | if (!hm) { 32 | return NULL; 33 | } 34 | 35 | hm->table = (map_entry **) calloc(initial_capacity, sizeof(map_entry*)); 36 | if (!(hm->table)) { 37 | free(hm); 38 | return NULL; 39 | } 40 | hm->capacity = initial_capacity; 41 | hm->size = 0; 42 | hm->load_factor = lf; 43 | hm->hash_function = &default_hash_function; 44 | hm->comparator = &default_comparator; 45 | return hm; 46 | } 47 | 48 | void *hm_put(hashmap *map, void *key, void *value) { 49 | if ((((float) (map->size + 1)) / map->capacity > map->load_factor) && !resize(map)) { 50 | return NULL; 51 | } 52 | 53 | size_t i = 0, j = 0, index = map->hash_function(key) % map->capacity, removedIndex; 54 | bool foundRemoved = false; 55 | while (i < map->capacity && (!foundRemoved || j < map->size)) { 56 | if (!map->table[index].key) { 57 | if (foundRemoved) { 58 | index = removedIndex; 59 | } 60 | map->table[index].key = key; 61 | map->table[index].value = value; 62 | map->table[index].removed = false; 63 | ++map->size; 64 | return NULL; 65 | } else if (map->comparator(key, map->table[index].key)) { 66 | if (!map->table[index].removed) { 67 | void *value = map->table[index].value; 68 | map->table[index].value = value; 69 | return value; 70 | } else if (foundRemoved) { 71 | index = removedIndex; 72 | } 73 | map->table[index].key = key; 74 | map->table[index].value = value; 75 | map->table[index].removed = false; 76 | ++map->size; 77 | return NULL; 78 | } else if (map->table[index].removed) { 79 | removedIndex = index; 80 | foundRemoved = true; 81 | } else { 82 | ++j; 83 | } 84 | ++i; 85 | index = ++index % map->capacity; 86 | } 87 | return NULL; 88 | } 89 | 90 | map_entry *hm_remove(hashmap *map, void *key) { 91 | size_t i = 0, j = 0, index = map->hash_function(key) % map->capacity; 92 | while (i < map->capacity && j < map->size) { 93 | if (!map->table[index].key) { 94 | return NULL; 95 | } else if (map->comparator(key, map->table[index].key)) { 96 | if (map->table[index].removed) { 97 | return NULL; 98 | } else { 99 | map->table[index].removed = true; 100 | --map->size; 101 | return &(map->table[index]); 102 | } 103 | } else if (!map->table[index].removed) { 104 | ++j; 105 | } 106 | ++i; 107 | ++index; 108 | index = index % map->capacity; 109 | } 110 | return NULL; 111 | } 112 | 113 | void* hm_get(hashmap *map, void *key) { 114 | size_t i = 0, j = 0, index = map->hash_function(key) % map->capacity; 115 | while (i < map->capacity && j < map->size) { 116 | if (!map->table[index].key) { 117 | return NULL; 118 | } else if (map->comparator(key, map->table[index].key)) { 119 | if (map->table[index].removed) { 120 | return NULL; 121 | } else { 122 | return map->table[index].value; 123 | } 124 | } else if (!map->table[index].removed) { 125 | ++j; 126 | } 127 | ++i; 128 | ++index; 129 | index = index % map->capacity; 130 | } 131 | return NULL; 132 | } 133 | 134 | bool hm_contains_key(hashmap *map, void *key) { 135 | return hm_get(map, key) != NULL; 136 | } 137 | 138 | arraylist *hm_key_set(hashmap *map) { 139 | arraylist *keySet = create_arraylist(map->size); 140 | size_t i = 0, j = 0; 141 | while (i < map->capacity && j < map->size) { 142 | if (map->table[i].key && !map->table[i].removed) { 143 | al_add(keySet, map->table[i].key); 144 | ++j; 145 | } 146 | ++i; 147 | } 148 | return keySet; 149 | } 150 | 151 | arraylist *hm_values(hashmap *map) { 152 | arraylist *valueSet = create_arraylist(map->size); 153 | size_t i = 0, j = 0; 154 | while (i < map->capacity && j < map->size) { 155 | if (map->table[i].key && !map->table[i].removed) { 156 | al_add(valueSet, map->table[i].value); 157 | ++j; 158 | } 159 | ++i; 160 | } 161 | return valueSet; 162 | } 163 | 164 | static const unsigned int a = 48339, W = 97, M = UINT_MAX; 165 | 166 | size_t default_hash_function(const void *key) { 167 | unsigned long hash = (unsigned long) key; 168 | return (size_t) floor(((a * hash) % W) * (M / W)); 169 | } 170 | 171 | bool default_comparator(const void *key0, const void *key1) { 172 | return key0 == key1; 173 | } 174 | 175 | void hm_clear(hashmap *map) { 176 | for (size_t i = 0; i < map->capacity; ++i) { 177 | void *key = map->table[i].key; 178 | if (key && !map->table[i].removed) { 179 | free(key); 180 | map->table[i].key = NULL; 181 | } 182 | } 183 | map->size = 0; 184 | } 185 | 186 | void hm_delete(hashmap *map) { 187 | for (size_t i = 0; i < map->capacity; ++i) { 188 | void *key = map->table[i].key; 189 | if (key && !map->table[i].removed) { 190 | free(key); 191 | free(map->table[i].value); 192 | map->table[i].key = NULL; 193 | } 194 | } 195 | map->size = 0; 196 | } 197 | -------------------------------------------------------------------------------- /tests/stack_tests.c: -------------------------------------------------------------------------------- 1 | #include "stack_tests.h" 2 | 3 | jmp_buf break_point; 4 | 5 | bool test_create_stack() { 6 | printf("Test: \"create_stack(size_t capacity)\" is starting ... "); 7 | 8 | int assert_code; 9 | 10 | if ((assert_code = setjmp(break_point))) { 11 | printf("\x1b[31m failed!\x1b[0m\n\n"); 12 | switch(assert_code) { 13 | case 1: 14 | printf("stack->capacity is incorrect value."); 15 | break; 16 | case 2: 17 | printf("stack->size != 0 upon creation."); 18 | break; 19 | 20 | } 21 | printf("\n\n"); 22 | return false; 23 | } else { 24 | stack *s = create_stack(4); 25 | int_assert_equal(s->capacity, 4, 1); 26 | int_assert_equal(s->size, 0, 2); 27 | free(s); 28 | } 29 | 30 | printf("\x1b[32m passed!\x1b[0m\n\n"); 31 | return true; 32 | } 33 | 34 | bool test_stack_push() { 35 | printf("Test: \"push(stack *s, void *element)\" is starting ..."); 36 | 37 | int assert_code; 38 | 39 | if ((assert_code = setjmp(break_point))) { 40 | printf("\x1b[31m failed!\x1b[0m\n\n"); 41 | switch(assert_code) { 42 | case 1: 43 | printf("pushed elements do not appear in correct order."); 44 | break; 45 | case 2: 46 | printf("s->size is not correct value after after push."); 47 | break; 48 | case 3: 49 | printf("s->capacity is not correct value after push."); 50 | break; 51 | } 52 | printf("\n\n"); 53 | return false; 54 | } else { 55 | stack* s = create_stack(5); 56 | int correct_values[] = {3, 4, 5, 6, 7, 8}; 57 | push(s, Integer(3)); 58 | push(s, Integer(4)); 59 | push(s, Integer(5)); 60 | int_array_assert_equal((int **) s->elements, correct_values, 3, 1); 61 | int_assert_equal(s->size, 3, 2); 62 | push(s, Integer(6)); 63 | push(s, Integer(7)); 64 | push(s, Integer(8)); 65 | int_array_assert_equal((int **) s->elements, correct_values, 6, 1); 66 | int_assert_equal(s->size, 6, 2); 67 | int_assert_equal(s->capacity, 10, 3); 68 | } 69 | printf("\x1b[32m passed!\x1b[0m\n\n"); 70 | return true; 71 | } 72 | 73 | bool test_stack_peek() { 74 | printf("Test: \"peek(stack *s)\" is starting ..."); 75 | 76 | int assert_code; 77 | 78 | if ((assert_code = setjmp(break_point))) { 79 | printf("\x1b[31m failed!\x1b[0m\n\n"); 80 | switch(assert_code) { 81 | case 1: 82 | printf("pushed elements do not appear in correct order."); 83 | break; 84 | case 2: 85 | printf("s->size is not correct value after after push."); 86 | break; 87 | case 3: 88 | printf("peek(stack* target) does not return top element."); 89 | break; 90 | } 91 | printf("\n\n"); 92 | return false; 93 | } else { 94 | stack* s = create_stack(5); 95 | int correct_values[] = {3, 4, 5}; 96 | push(s, Integer(3)); 97 | push(s, Integer(4)); 98 | push(s, Integer(5)); 99 | int_array_assert_equal((int **) s->elements, correct_values, 3, 1); 100 | int_assert_equal(s->size, 3, 2); 101 | int_assert_equal(*((int *) peek(s)), 5, 3); 102 | } 103 | printf("\x1b[32m passed!\x1b[0m\n\n"); 104 | return true; 105 | } 106 | 107 | bool test_stack_pop() { 108 | printf("Test: \"pop(stack *s)\" is starting ..."); 109 | 110 | int assert_code; 111 | 112 | if ((assert_code = setjmp(break_point))) { 113 | printf("\x1b[31m failed!\x1b[0m\n\n"); 114 | switch(assert_code) { 115 | case 1: 116 | printf("pushed elements do not appear in correct order."); 117 | break; 118 | case 2: 119 | printf("s->size is not correct value after after push."); 120 | break; 121 | case 3: 122 | printf("pop(stack* target) does not return top element."); 123 | break; 124 | case 4: 125 | printf("pop(stack* target) does not decrement size."); 126 | break; 127 | } 128 | printf("\n\n"); 129 | return false; 130 | } else { 131 | stack* s = create_stack(5); 132 | int correct_values[] = {3, 4, 5}; 133 | push(s, Integer(3)); 134 | push(s, Integer(4)); 135 | push(s, Integer(5)); 136 | int_array_assert_equal((int **) s->elements, correct_values, 3, 1); 137 | int_assert_equal(s->size, 3, 2); 138 | int *top = pop(s); 139 | 140 | int_assert_equal(*top, 5, 3); 141 | 142 | int_assert_equal(s->size, 2, 4); 143 | } 144 | printf("\x1b[32m passed!\x1b[0m\n\n"); 145 | return true; 146 | 147 | } 148 | 149 | bool test_stack_ensure_capacity() { 150 | printf("Test: \"ensure_capacity(stack *s, size_t capacity)\" is starting ..."); 151 | 152 | int assert_code; 153 | 154 | if ((assert_code = setjmp(break_point))) { 155 | printf("\x1b[31m failed!\x1b[0m\n\n"); 156 | switch(assert_code) { 157 | printf("Exit code: %d", assert_code); 158 | } 159 | printf("\n\n"); 160 | return false; 161 | } else { 162 | stack* s = create_stack(5); 163 | push(s, Integer(3)); 164 | push(s, Integer(4)); 165 | bool_assert_equal(s_ensure_capacity(s, 1), false, 1); 166 | bool_assert_equal(s_ensure_capacity(s, 4), true, 2); 167 | int_assert_equal(s->size, 2, 3); 168 | int_assert_equal(s->capacity, 4, 4); 169 | 170 | bool_assert_equal(s_ensure_capacity(s, 10), true, 5); 171 | int_assert_equal(s->capacity, 10, 6); 172 | int_assert_equal(s->size, 2, 7); 173 | } 174 | printf("\x1b[32m passed!\x1b[0m\n\n"); 175 | return true; 176 | } -------------------------------------------------------------------------------- /src/linked_list.c: -------------------------------------------------------------------------------- 1 | #include "linked_list.h" 2 | 3 | linked_list *array_to_linkedlist(void **array, size_t size) { 4 | linked_list *linked_list = create_linkedlist(); 5 | if (!linked_list) { 6 | return NULL; 7 | } 8 | 9 | list_node **iterator = &(linked_list->head); 10 | for (size_t i = 0; i < size; ++i) { 11 | *iterator = (list_node*) malloc(sizeof(list_node)); 12 | if (!iterator) { 13 | ll_clear(linked_list); 14 | free(linked_list); 15 | return NULL; 16 | } 17 | linked_list->tail = *iterator; 18 | (*iterator)->element = array[i]; 19 | iterator = &((*iterator)->next); 20 | } 21 | *iterator = NULL; 22 | linked_list->iterator = linked_list->head; 23 | linked_list->size = size; 24 | return linked_list; 25 | } 26 | 27 | linked_list *create_linkedlist() { 28 | linked_list *ll = (linked_list *) malloc(sizeof(linked_list)); 29 | memset(ll, 0, sizeof(linked_list)); 30 | return ll; 31 | } 32 | 33 | void ll_add_first(linked_list *target, void *element) { 34 | list_node *node = (list_node*) malloc(sizeof(list_node)); 35 | node->element = element; 36 | node->next = target->head; 37 | target->head = node; 38 | ++target->size; 39 | } 40 | 41 | void ll_add_last(linked_list *target, void *element) { 42 | list_node *node = (list_node*) malloc(sizeof(list_node)); 43 | node->element = element; 44 | node->next = NULL; 45 | target->tail->next = node; 46 | target->tail = node; 47 | ++target->size; 48 | } 49 | 50 | void ll_add_at(linked_list *target, size_t position, void *element) { 51 | if (position > target->size) { 52 | return; 53 | } 54 | 55 | list_node **iterator = &(target->head); 56 | for (size_t i = 0; i < position; ++i) { 57 | iterator = &((*iterator)->next); 58 | } 59 | list_node *node = (list_node*) malloc(sizeof(list_node)); 60 | node->element = element; 61 | node->next = *iterator; 62 | 63 | *iterator = node; 64 | 65 | if (position == 0) { 66 | target->head = node; 67 | } else if (position == target->size) { 68 | target->tail = node; 69 | } 70 | ++target->size; 71 | } 72 | 73 | void *ll_set(linked_list *target, size_t position, void *element) { 74 | if (position >= target->size) { 75 | return NULL; 76 | } 77 | list_node *iterator = target->head; 78 | for (size_t i = 0; i < position; ++i) { 79 | iterator = iterator->next; 80 | } 81 | void *old_value = iterator->element; 82 | iterator->element = element; 83 | return old_value; 84 | } 85 | 86 | size_t ll_size(linked_list* target) { 87 | return target->size; 88 | } 89 | 90 | void *ll_get(linked_list *target, size_t index) { 91 | if (index >= target->size) { 92 | return NULL; 93 | } 94 | list_node *iterator = target->head; 95 | for (size_t i = 0; i < index; ++i) { 96 | iterator = iterator->next; 97 | } 98 | return iterator->element; 99 | } 100 | 101 | void *ll_next(linked_list *target) { 102 | void *ret = NULL; 103 | if (target->iterator) { 104 | ret = target->iterator->element; 105 | target->iterator = target->iterator->next; 106 | } else { 107 | target->iterator = target->head; 108 | } 109 | 110 | return ret; 111 | } 112 | 113 | bool ll_has_next(linked_list *target) { 114 | return target->iterator != NULL; 115 | } 116 | 117 | void ll_reset(linked_list *target) { 118 | target->iterator = target->head; 119 | } 120 | 121 | void *ll_remove(linked_list *target, size_t position) { 122 | if (position >= target->size) { 123 | return NULL; 124 | } 125 | 126 | list_node **iterator = &(target->head), *prev = NULL; 127 | for (size_t i = 0; i < position; ++i) { 128 | prev = *iterator; 129 | iterator = &((*iterator)->next); 130 | } 131 | 132 | if (position == target->size - 1) { 133 | target->tail = prev; 134 | } 135 | 136 | if (*iterator == target->iterator) { 137 | target->iterator = prev; 138 | } 139 | void *data = (*iterator)->element; 140 | list_node *toRemove = *iterator; 141 | *iterator = (*iterator)->next; 142 | free(toRemove); 143 | --target->size; 144 | return data; 145 | } 146 | 147 | list_node *ll_remove_node(linked_list *target, size_t position) { 148 | if (position >= target->size) { 149 | return NULL; 150 | } 151 | 152 | list_node **iterator = &(target->head), *prev = NULL; 153 | for (size_t i = 0; i < position; ++i) { 154 | prev = *iterator; 155 | iterator = &((*iterator)->next); 156 | } 157 | 158 | if (position == target->size - 1) { 159 | target->tail = prev; 160 | } 161 | 162 | if (*iterator == target->iterator) { 163 | target->iterator = prev; 164 | } 165 | list_node *to_remove = *iterator; 166 | *iterator = to_remove->next; 167 | to_remove->next = NULL; 168 | --target->size; 169 | return to_remove; 170 | } 171 | 172 | void ll_clear(linked_list *target) { 173 | list_node *iterator = target->head, *prev = NULL; 174 | while (iterator) { 175 | prev = iterator; 176 | iterator = iterator->next; 177 | free(prev); 178 | } 179 | target->head = NULL; 180 | target->tail = NULL; 181 | target->iterator = NULL; 182 | target->size = 0; 183 | } 184 | 185 | void ll_delete(linked_list *target) { 186 | list_node *iterator = target->head, *prev = NULL; 187 | while (iterator) { 188 | free(iterator->element); 189 | prev = iterator; 190 | iterator = iterator->next; 191 | free(prev); 192 | } 193 | target->head = NULL; 194 | target->tail = NULL; 195 | target->iterator = NULL; 196 | target->size = 0; 197 | } 198 | 199 | void join(linked_list* left_list, linked_list* right_list) { 200 | if (left_list->size != 0 && right_list->size != 0) { 201 | left_list->tail->next = right_list->head; 202 | left_list->tail = right_list->tail; 203 | left_list->size += right_list->size; 204 | } else if (right_list->size != 0) { 205 | left_list->head = right_list->head; 206 | left_list->tail = right_list->tail; 207 | left_list->size = right_list->size; 208 | } 209 | } 210 | 211 | linked_list *split(linked_list* target, size_t split) { 212 | linked_list *new = create_linkedlist(); 213 | if (split >= target->size) { 214 | return new; 215 | } 216 | list_node *iterator = target->head, *prev = NULL; 217 | 218 | for (size_t i = 0; i < split; ++i) { 219 | prev = iterator; 220 | iterator = iterator->next; 221 | } 222 | target->tail = prev; 223 | if (split == 0) { 224 | target->head = NULL; 225 | } 226 | new->head = iterator; 227 | new->iterator = new->head; 228 | new->size = target->size - split; 229 | target->size -= new->size; 230 | 231 | iterator = new->head; 232 | while (iterator) { 233 | prev = iterator; 234 | iterator = iterator->next; 235 | } 236 | new->tail = prev; 237 | return new; 238 | } -------------------------------------------------------------------------------- /src/avl_tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "avl_tree.h" 3 | #include "queue.h" 4 | 5 | static void update(treenode *node) { 6 | int leftHeight = -1; 7 | 8 | if (node->left) { 9 | leftHeight = node->left->height; 10 | } 11 | 12 | int rightHeight = -1; 13 | 14 | if (node->right) { 15 | rightHeight = node->right->height; 16 | } 17 | 18 | node->height = leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1; 19 | node->bf = (signed char) (leftHeight - rightHeight); 20 | } 21 | 22 | static treenode *leftRotation(treenode *node) { 23 | treenode *b = node->right; 24 | node->right = b->left; 25 | b->left = node; 26 | update(node); 27 | update(b); 28 | return b; 29 | } 30 | 31 | static treenode *rightRotation(treenode *node) { 32 | treenode *b = node->left; 33 | node->left = b->right; 34 | b->right = node; 35 | update(node); 36 | update(b); 37 | return b; 38 | } 39 | 40 | static treenode *leftRightRotation(treenode *node) { 41 | node->left = leftRotation(node->left); 42 | return rightRotation(node); 43 | } 44 | 45 | static treenode *rightLeftRotation(treenode *node) { 46 | node->right = rightRotation(node->right); 47 | return leftRotation(node); 48 | } 49 | 50 | static treenode *findSuccessor(treenode *node) { 51 | treenode *iterator = node->right; 52 | while (iterator->left) { 53 | iterator = iterator->left; 54 | } 55 | return iterator; 56 | } 57 | 58 | static treenode *addHelper(treenode *node, void *data, const signed char (*comparator)(const void *loperand, const void *roperand)) { 59 | if (!node) { 60 | treenode *child = (treenode*) malloc(sizeof(treenode)); 61 | child->left = NULL; 62 | child->right = NULL; 63 | child->data = data; 64 | child->height = 0; 65 | child->bf = 0; 66 | child->count = 1; 67 | return child; 68 | } 69 | 70 | signed char difference = comparator(data, node->data); 71 | if (difference < 0) { 72 | node->left = addHelper(node->left, data, comparator); 73 | } else if (difference > 0) { 74 | node->right = addHelper(node->right, data, comparator); 75 | } else { 76 | ++node->count; 77 | } 78 | update(node); 79 | if (node->bf > 1) { 80 | if (node->left->bf < 0) { 81 | node = leftRightRotation(node); 82 | } else { 83 | node = rightRotation(node); 84 | } 85 | } else if (node->bf < -1) { 86 | if (node->right->bf > 0) { 87 | node = rightLeftRotation(node); 88 | } else { 89 | node = leftRotation(node); 90 | } 91 | } 92 | return node; 93 | } 94 | 95 | static treenode *removeHelper(treenode *node, void *data, const signed char (*comparator)(const void *loperand, const void *roperand)) { 96 | if (!node) { 97 | return NULL; 98 | } 99 | signed char difference = comparator(data, node->data); 100 | if (difference < 0) { 101 | node->right = removeHelper(node->right, data, comparator); 102 | } else if (difference > 0) { 103 | node->left = removeHelper(node->left, data, comparator); 104 | } else if (node->count > 1) { 105 | --node->count; 106 | } else if (!node->left && !node->right) { 107 | return NULL; 108 | } else if (!node->left) { 109 | return node->right; 110 | } else if (!node->right) { 111 | return node->right; 112 | } else { 113 | treenode *successor = findSuccessor(node); 114 | node->data = successor->data; 115 | node->count = successor->count; 116 | successor->count = 1; 117 | node->right = removeHelper(node->right, successor->data, comparator); 118 | } 119 | update(node); 120 | if (node->bf > 1) { 121 | if (node->left->bf < 0) { 122 | node = leftRightRotation(node); 123 | } else { 124 | node = rightRotation(node); 125 | } 126 | } else if (node->bf < -1) { 127 | if (node->right->bf > 0) { 128 | node = rightLeftRotation(node); 129 | } else { 130 | node = leftRotation(node); 131 | } 132 | } 133 | return node; 134 | } 135 | 136 | static void *getHelper(treenode *node, void *data, const signed char (*comparator)(const void *loperand, const void *roperand)) { 137 | if (!node) { 138 | return NULL; 139 | } 140 | 141 | signed char difference = comparator(data, node->data); 142 | if (difference < 0) { 143 | return getHelper(node->left, data, comparator); 144 | } else if (difference > 0) { 145 | return getHelper(node->right, data, comparator); 146 | } else { 147 | return node->data; 148 | } 149 | } 150 | 151 | struct tree *create_tree(void **array, size_t size, const signed char (*comparator)(const void *loperand, const void *roperand)) { 152 | struct tree *tree = (struct tree *) malloc(sizeof(struct tree)); 153 | tree->root = NULL; 154 | tree->size = 0; 155 | tree->comparator = comparator; 156 | 157 | for (size_t i = 0; i < size; ++i) { 158 | tree_add(tree, array[i]); 159 | } 160 | 161 | return tree; 162 | } 163 | 164 | void tree_add(struct tree *tree, void *data) { 165 | if (!data) { 166 | return; 167 | } 168 | tree->root = addHelper(tree->root, data, tree->comparator); 169 | ++tree->size; 170 | } 171 | 172 | void *tree_remove(struct tree *tree, void *data) { 173 | if (!data) { 174 | return NULL; 175 | } 176 | 177 | void *found = getHelper(tree->root, data, tree->comparator); 178 | if (!found) { 179 | return NULL; 180 | } 181 | 182 | tree->root = removeHelper(tree->root, data, tree->comparator); 183 | --tree->size; 184 | return found; 185 | } 186 | 187 | void *tree_get(struct tree *tree, void *data) { 188 | if (!data) { 189 | return NULL; 190 | } 191 | return getHelper(tree->root, data, tree->comparator); 192 | } 193 | 194 | static void tree_clear_helper(treenode *node) { 195 | if (!node) { 196 | return; 197 | } 198 | 199 | tree_clear_helper(node->left); 200 | tree_clear_helper(node->right); 201 | free(node); 202 | } 203 | 204 | void tree_clear(struct tree *tree) { 205 | tree_clear_helper(tree->root); 206 | tree->root = NULL; 207 | tree->size = 0; 208 | } 209 | 210 | static void tree_delete_helper(treenode *node) { 211 | if (!node) { 212 | return; 213 | } 214 | 215 | tree_delete_helper(node->left); 216 | tree_delete_helper(node->right); 217 | free(node->data); 218 | free(node); 219 | } 220 | 221 | void tree_delete(struct tree *tree) { 222 | tree_delete_helper(tree->root); 223 | tree->root = NULL; 224 | tree->size = 0; 225 | } 226 | 227 | static void preorderHelper(treenode *node, arraylist *collection) { 228 | if (!node) { 229 | return; 230 | } 231 | al_add(collection, node->data); 232 | preorderHelper(node->left, collection); 233 | preorderHelper(node->right, collection); 234 | } 235 | 236 | arraylist *preorder(struct tree *tree) { 237 | arraylist *collection = create_arraylist(tree->size); 238 | preorderHelper(tree->root, collection); 239 | return collection; 240 | } 241 | 242 | static void inorderHelper(treenode *node, arraylist *collection) { 243 | if (!node) { 244 | return; 245 | } 246 | inorderHelper(node->left, collection); 247 | al_add(collection, node->data); 248 | inorderHelper(node->right, collection); 249 | } 250 | 251 | arraylist *inorder(struct tree *tree) { 252 | arraylist *collection = create_arraylist(tree->size); 253 | inorderHelper(tree->root, collection); 254 | return collection; 255 | } 256 | 257 | static void postorderHelper(treenode *node, arraylist *collection) { 258 | if (!node) { 259 | return; 260 | } 261 | postorderHelper(node->left, collection); 262 | postorderHelper(node->right, collection); 263 | al_add(collection, node->data); 264 | } 265 | 266 | arraylist *postorder(struct tree *tree) { 267 | arraylist *collection = create_arraylist(tree->size); 268 | postorderHelper(tree->root, collection); 269 | return collection; 270 | } 271 | 272 | arraylist *levelorder(struct tree *tree) { 273 | queue *node_queue = create_queue(8); 274 | arraylist *data = create_arraylist(tree->size); 275 | 276 | enqueue(node_queue, tree->root); 277 | 278 | while (node_queue->size > 0) { 279 | treenode *current = (treenode *) dequeue(node_queue); 280 | al_add(data, current->data); 281 | 282 | if (current->left) { 283 | enqueue(node_queue, current->left); 284 | } 285 | 286 | if (current->right) { 287 | enqueue(node_queue, current->right); 288 | } 289 | } 290 | q_clear(node_queue); 291 | return data; 292 | } -------------------------------------------------------------------------------- /src/bmp_image.c: -------------------------------------------------------------------------------- 1 | #include "bmp_image.h" 2 | 3 | static const size_t FILE_HEADER_SIZE = 14; 4 | 5 | bmp_image openImageBMP(const char *path) 6 | { 7 | bmp_image image = {.width = 0, .height = 0, .file_header = NULL, .bitmap_header = NULL, .pixels = NULL, .trailer = NULL}; 8 | FILE* img = fopen(path, "rb"); 9 | if (img) { 10 | image.file_header = (unsigned char*) malloc(FILE_HEADER_SIZE * sizeof(unsigned char)); 11 | if (!image.file_header) { 12 | fclose(img); 13 | return image; 14 | } 15 | 16 | int n = fread(image.file_header, sizeof(unsigned char), FILE_HEADER_SIZE, img); 17 | if (n != FILE_HEADER_SIZE) { 18 | free(image.file_header); 19 | image.file_header = NULL; 20 | fclose(img); 21 | return image; 22 | } 23 | 24 | int pixel_array_offset = *(int*)&image.file_header[10]; 25 | image.bitmap_header = (unsigned char*) malloc((pixel_array_offset - FILE_HEADER_SIZE) * sizeof(unsigned char)); 26 | if (!image.bitmap_header) { 27 | free(image.file_header); 28 | image.file_header = NULL; 29 | fclose(img); 30 | return image; 31 | } 32 | 33 | n = fread(image.bitmap_header, sizeof(unsigned char), pixel_array_offset - FILE_HEADER_SIZE, img); 34 | if (n != pixel_array_offset - FILE_HEADER_SIZE) { 35 | free(image.file_header); 36 | image.file_header = NULL; 37 | free(image.bitmap_header); 38 | image.bitmap_header = NULL; 39 | fclose(img); 40 | return image; 41 | } 42 | image.width = *(int*)&image.bitmap_header[4]; 43 | image.height = *(int*)&image.bitmap_header[8]; 44 | 45 | image.pixels = (pixel*) malloc(image.width * image.height * sizeof(pixel)); 46 | if (!image.pixels) { 47 | free(image.file_header); 48 | image.file_header = NULL; 49 | free(image.bitmap_header); 50 | image.bitmap_header = NULL; 51 | fclose(img); 52 | return image; 53 | } 54 | short bpp = *(short*)&image.bitmap_header[14]; 55 | long int padding = ceil(bpp * image.width / 32.0) * 4 - image.width * bpp / 8; 56 | for (size_t row = 0; row < image.height; ++row) { 57 | for (size_t col = 0; col < image.width; ++col) { 58 | unsigned char *pixel_component = (unsigned char*) &image.pixels[row * image.width + col]; 59 | n = fread(pixel_component, sizeof(unsigned char), bpp / 8, img); 60 | if (n != bpp / 8) { 61 | free(image.file_header); 62 | image.file_header = NULL; 63 | free(image.bitmap_header); 64 | image.bitmap_header = NULL; 65 | free(image.pixels); 66 | image.pixels = NULL; 67 | image.width = 0; 68 | image.height = 0; 69 | fclose(img); 70 | return image; 71 | } 72 | } 73 | fseek(img, padding, SEEK_CUR); 74 | } 75 | size_t bytes_read = 0; 76 | unsigned char *trailer = (unsigned char*) malloc(1 * sizeof(unsigned char)); 77 | 78 | int byte = fgetc(img); 79 | while (byte != EOF) { 80 | trailer[bytes_read] = (unsigned char) byte; 81 | ++bytes_read; 82 | trailer = (unsigned char*) realloc(trailer, (bytes_read + 1) * sizeof(unsigned char)); 83 | if (!trailer) { 84 | free(image.file_header); 85 | image.file_header = NULL; 86 | free(image.bitmap_header); 87 | image.bitmap_header = NULL; 88 | free(image.pixels); 89 | image.pixels = NULL; 90 | free(trailer); 91 | image.trailer_size = 0; 92 | image.width = 0; 93 | image.height = 0; 94 | fclose(img); 95 | return image; 96 | } 97 | byte = fgetc(img); 98 | } 99 | image.trailer = trailer; 100 | image.trailer_size = bytes_read; 101 | fclose(img); 102 | } 103 | return image; 104 | } 105 | 106 | pixel* pixel_at(bmp_image* image, unsigned int col, unsigned int row) { 107 | unsigned int num_pixels = image->width * image->height; 108 | unsigned int index = row * image->width + image->width - col; 109 | return &(image->pixels[num_pixels - 1 - row * image->width - image->width + col]); 110 | } 111 | 112 | bool save_bmp_image(bmp_image* image, const char* location) { 113 | FILE* dest = fopen(location, "wb"); 114 | if (!dest) { 115 | return false; 116 | } 117 | fwrite(image->file_header, sizeof(unsigned char), FILE_HEADER_SIZE, dest); 118 | fwrite(image->bitmap_header, sizeof(unsigned char), *(int*)&image->bitmap_header[0], dest); 119 | 120 | short bpp = *(short *) &image->bitmap_header[14]; 121 | 122 | size_t padding = ceil(bpp * image->width / 32.0) * 4 - image->width * bpp / 8; 123 | unsigned char *buffer = (unsigned char*) malloc(padding * sizeof(unsigned char)); 124 | for (size_t i = 0; i < padding; ++i) { 125 | buffer[i] = 0; 126 | } 127 | 128 | for (size_t row = 0; row < image->height; ++row) { 129 | for (size_t col = 0; col < image->width; ++col) { 130 | unsigned char *pixel = (unsigned char*)&image->pixels[row * image->width + col]; 131 | fwrite(pixel, sizeof(unsigned char), bpp / 8, dest); 132 | } 133 | fwrite(buffer, sizeof(unsigned char), padding, dest); 134 | } 135 | fwrite(image->trailer, sizeof(unsigned char), image->trailer_size, dest); 136 | fclose(dest); 137 | return true; 138 | } 139 | 140 | void dispose_bmp_image(bmp_image* image) { 141 | image->width = 0; 142 | image->height = 0; 143 | free(image->file_header); 144 | image->file_header = NULL; 145 | free(image->bitmap_header); 146 | image->bitmap_header = NULL; 147 | free(image->pixels); 148 | image->pixels = NULL; 149 | } 150 | 151 | bmp_image convolution(bmp_image* image, struct fMatrix* kernel) { 152 | bmp_image convolved_image = {.width = 0, .height = 0, .file_header = NULL, .bitmap_header = NULL, .pixels = NULL}; 153 | 154 | if (kernel->rows % 2 == 0 || kernel->cols % 2 == 0) { 155 | return convolved_image; 156 | } 157 | 158 | convolved_image.file_header = (unsigned char*) malloc(FILE_HEADER_SIZE * sizeof(unsigned char)); 159 | if (!convolved_image.file_header) { 160 | return convolved_image; 161 | } 162 | 163 | convolved_image.width = image->width; 164 | convolved_image.height = image->height; 165 | memcpy(convolved_image.file_header, image->file_header, FILE_HEADER_SIZE * sizeof(unsigned char)); 166 | 167 | int pixel_array_offset = *(int*)&image->file_header[10]; 168 | convolved_image.bitmap_header = (unsigned char*) malloc((pixel_array_offset - FILE_HEADER_SIZE) * sizeof(unsigned char)); 169 | 170 | if (!convolved_image.bitmap_header) { 171 | free(convolved_image.file_header); 172 | convolved_image.file_header = NULL; 173 | convolved_image.width = 0; 174 | convolved_image.height = 0; 175 | return convolved_image; 176 | } 177 | memcpy(convolved_image.bitmap_header, image->bitmap_header, (pixel_array_offset - FILE_HEADER_SIZE) * sizeof(unsigned char)); 178 | 179 | short bpp = *(short*)&image->bitmap_header[14]; 180 | 181 | convolved_image.pixels = (pixel*) malloc(convolved_image.width * convolved_image.height * sizeof(pixel)); 182 | if (!convolved_image.pixels) { 183 | free(convolved_image.file_header); 184 | convolved_image.file_header = NULL; 185 | free(convolved_image.bitmap_header); 186 | convolved_image.bitmap_header = NULL; 187 | convolved_image.width = 0; 188 | convolved_image.height = 0; 189 | return convolved_image; 190 | } 191 | memset(convolved_image.pixels, 255, convolved_image.width * convolved_image.height * sizeof(pixel)); 192 | 193 | 194 | float *accumulator = (float*) malloc(bpp * sizeof(float) / 8); 195 | 196 | for (int row = 0; row < image->height; ++row) 197 | { 198 | for (int col = 0; col < image->width; ++col) 199 | { 200 | for (int i = 0; i < bpp / 8; ++i) { 201 | accumulator[i] = 0.0f; 202 | } 203 | 204 | for (int i = 0; i < kernel->rows; ++i) 205 | { 206 | for (int j = 0; j < kernel->cols; ++j) 207 | { 208 | int adjusted_row = row + i - (kernel->rows / 2); 209 | int adjusted_col = col + j - (kernel->cols / 2); 210 | if (adjusted_row >= 0 && adjusted_row < image->height && adjusted_col >= 0 && adjusted_col < image->width) 211 | { 212 | unsigned char *src_pixel = (unsigned char*) pixel_at(image, adjusted_col, adjusted_row); 213 | for (int k = 0; k < bpp / 8; ++k) { 214 | accumulator[k] += (float) src_pixel[k] * fMatrix_get(kernel, i, j); 215 | } 216 | } 217 | } 218 | } 219 | unsigned char *dest_pixel = (unsigned char*) pixel_at(&convolved_image, col, row); 220 | for (int i = 0; i < bpp / 8; ++i) { 221 | dest_pixel[i] = (unsigned char) ((int) round(fabsf(accumulator[i])) % 255); 222 | } 223 | 224 | } 225 | } 226 | return convolved_image; 227 | } 228 | -------------------------------------------------------------------------------- /src/dlinked_list.c: -------------------------------------------------------------------------------- 1 | #include "dlinked_list.h" 2 | 3 | dlinked_list *array_to_dlinkedlist(void **array, size_t size) { 4 | dlinked_list *dll = (dlinked_list *) malloc(sizeof(dlinked_list)); 5 | if (!dll) { 6 | return NULL; 7 | } 8 | dll->head = NULL; 9 | dll->iterator = NULL; 10 | 11 | dlist_node **iterator = &(dll->head), *prev = NULL; 12 | for (size_t i = 0; i < size; ++i) { 13 | dlist_node *node = (dlist_node *) malloc(sizeof(dlist_node)); 14 | if (!node) { 15 | dll_clear(dll); 16 | free(dll); 17 | return NULL; 18 | } 19 | node->data = array[i]; 20 | *iterator = node; 21 | node->prev = prev; 22 | 23 | iterator = &((*iterator)->next); 24 | prev = node; 25 | } 26 | *iterator = NULL; 27 | dll->tail = prev; 28 | dll->iterator = dll->head; 29 | dll->size = size; 30 | return dll; 31 | } 32 | 33 | dlinked_list *create_dlinkedlist() { 34 | dlinked_list *dll = (dlinked_list *) malloc(sizeof(dlinked_list)); 35 | if (!dll) { 36 | return NULL; 37 | } 38 | dll->size = 0; 39 | dll->head = NULL; 40 | dll->tail = NULL; 41 | dll->iterator = NULL; 42 | return dll; 43 | } 44 | 45 | bool dll_add_first(dlinked_list *target, void* element) { 46 | dlist_node *node = (dlist_node *) malloc(sizeof(dlist_node)); 47 | if (!node) { 48 | return false; 49 | } 50 | node->data = element; 51 | node->prev = NULL; 52 | node->next = target->head; 53 | 54 | if (target->head) { 55 | target->head->prev = node; 56 | target->head = node; 57 | } else { 58 | target->head = node; 59 | target->tail = node; 60 | } 61 | ++target->size; 62 | return true; 63 | } 64 | 65 | bool dll_add_last(dlinked_list *target, void* element) { 66 | dlist_node *node = (dlist_node *) malloc(sizeof(dlist_node)); 67 | if (!node) { 68 | return false; 69 | } 70 | node->data = element; 71 | node->next = NULL; 72 | node->prev = target->tail; 73 | 74 | if (target->tail) { 75 | target->tail->next = node; 76 | target->tail = node; 77 | } else { 78 | target->head = node; 79 | target->tail = node; 80 | } 81 | ++target->size; 82 | return true; 83 | } 84 | 85 | bool dll_add_at(dlinked_list *target, size_t position, void *element) { 86 | if (position < 0 || position > target->size) { 87 | return false; 88 | } 89 | 90 | dlist_node *node = (dlist_node *) malloc(sizeof(dlist_node)); 91 | if (!node) { 92 | return false; 93 | } 94 | node->data = element; 95 | 96 | dlist_node **iterator, *prev = NULL; 97 | if (position <= target->size / 2) { 98 | iterator = &(target->head); 99 | for (size_t i = 0; i < position; ++i) { 100 | prev = *iterator; 101 | iterator = &((*iterator)->next); 102 | } 103 | node->prev = prev; 104 | node->next = (*iterator); 105 | if (!target->tail) { 106 | target->tail = node; 107 | } else { 108 | (*iterator)->prev = node; 109 | } 110 | } else { 111 | iterator = &(target->tail); 112 | for (size_t i = target->size; i > position; --i) { 113 | prev = *iterator; 114 | iterator = &((*iterator)->prev); 115 | } 116 | node->next = prev; 117 | node->prev = (*iterator); 118 | (*iterator)->next = node; 119 | } 120 | *iterator = node; 121 | ++target->size; 122 | return true; 123 | } 124 | 125 | void *dll_set(dlinked_list *target, size_t position, void *element) { 126 | if (position < 0 || position >= target->size) { 127 | return NULL; 128 | } 129 | 130 | dlist_node *iterator; 131 | if (position <= target->size / 2) { 132 | iterator = target->head; 133 | for (size_t i = 0; i < position; ++i) { 134 | iterator = iterator->next; 135 | } 136 | } else { 137 | iterator = target->tail; 138 | for (size_t i = target->size - 1; i > position; --i) { 139 | iterator = iterator->prev; 140 | } 141 | } 142 | void *prev_data = iterator->data; 143 | iterator->data = element; 144 | return prev_data; 145 | } 146 | 147 | void *dll_get(dlinked_list *target, size_t position) { 148 | if (position < 0 || position >= target->size) { 149 | return NULL; 150 | } 151 | 152 | dlist_node *iterator; 153 | if (position <= target->size / 2) { 154 | iterator = target->head; 155 | for (size_t i = 0; i < position; ++i) { 156 | iterator = iterator->next; 157 | } 158 | } else { 159 | iterator = target->tail; 160 | for (size_t i = target->size - 1; i > position; --i) { 161 | iterator = iterator->prev; 162 | } 163 | } 164 | return iterator->data; 165 | } 166 | 167 | void *dll_next(dlinked_list *target) { 168 | void *ret = NULL; 169 | if (target->iterator) { 170 | ret = target->iterator->data; 171 | target->iterator = target->iterator->next; 172 | } else { 173 | target->iterator = target->head; 174 | } 175 | return ret; 176 | } 177 | 178 | bool dll_has_next(dlinked_list *target) { 179 | return target->iterator != NULL; 180 | } 181 | 182 | void dll_reset(dlinked_list *target) { 183 | target->iterator = target->head; 184 | } 185 | 186 | void *dll_remove(dlinked_list *target, size_t position) { 187 | dlist_node *removed_node = dll_remove_node(target, position); 188 | void *removed_data = removed_node->data; 189 | free(removed_node); 190 | return removed_data; 191 | } 192 | 193 | void *dll_remove_first(dlinked_list *target) { 194 | if (target->size == 0) { 195 | return NULL; 196 | } 197 | dlist_node *to_remove = target->head; 198 | target->head = target->head->next; 199 | if (!target->head) { 200 | target->tail = NULL; 201 | } else { 202 | target->head->prev = NULL; 203 | } 204 | void *removed_data = to_remove->data; 205 | free(to_remove); 206 | --target->size; 207 | return removed_data; 208 | } 209 | 210 | void *dll_remove_last(dlinked_list *target) { 211 | if (target->size == 0) { 212 | return NULL; 213 | } 214 | dlist_node *to_remove = target->tail; 215 | target->tail = target->tail->prev; 216 | if (!target->tail) { 217 | target->head = NULL; 218 | } else { 219 | target->tail->next = NULL; 220 | } 221 | void *removed_data = to_remove->data; 222 | free(to_remove); 223 | --target->size; 224 | return removed_data; 225 | } 226 | 227 | dlist_node *dll_remove_node(dlinked_list *target, size_t position) { 228 | if (position < 0 || position >= target->size) { 229 | return NULL; 230 | } 231 | 232 | dlist_node **iterator, *to_remove, *prev = NULL; 233 | if (position <= target->size / 2) { 234 | iterator = &(target->head); 235 | for (size_t i = 0; i < position; ++i) { 236 | prev = *iterator; 237 | iterator = &((*iterator)->next); 238 | } 239 | to_remove = *iterator; 240 | *iterator = to_remove->next; 241 | if (*iterator) { 242 | (*iterator)->prev = prev; 243 | } else { 244 | target->tail = prev; 245 | } 246 | } else { 247 | iterator = &(target->tail); 248 | for (size_t i = target->size; i > position + 1; --i) { 249 | prev = *iterator; 250 | iterator = &((*iterator)->prev); 251 | } 252 | to_remove = *iterator; 253 | *iterator = to_remove->prev; 254 | (*iterator)->next = prev; 255 | } 256 | --target->size; 257 | return to_remove; 258 | } 259 | 260 | void dll_clear(dlinked_list *target) { 261 | dlist_node *iterator = target->head, *prev = NULL; 262 | while (iterator) { 263 | prev = iterator; 264 | iterator = iterator->next; 265 | free(prev); 266 | } 267 | target->head = NULL; 268 | target->tail = NULL; 269 | target->iterator = NULL; 270 | target->size = 0; 271 | } 272 | 273 | void dll_delete(dlinked_list *target) { 274 | dlist_node *iterator = target->head, *prev = NULL; 275 | while (iterator) { 276 | prev = iterator; 277 | iterator = iterator->next; 278 | free(prev->data); 279 | free(prev); 280 | } 281 | target->head = NULL; 282 | target->tail = NULL; 283 | target->iterator = NULL; 284 | target->size = 0; 285 | } -------------------------------------------------------------------------------- /tests/arraylist_tests.c: -------------------------------------------------------------------------------- 1 | #include "arraylist_tests.h" 2 | 3 | jmp_buf break_point; 4 | 5 | bool test_create_arraylist() { 6 | printf("Test: \"create_arraylist('size_t')\" starting ..."); 7 | 8 | int assert_code; 9 | 10 | if ((assert_code = setjmp(break_point))) { 11 | printf("\x1b[31m failed!\x1b[0m\n\n"); 12 | switch (assert_code) { 13 | case 1: 14 | printf("list->capacity != DEFAULT_CAPACITY when initial_capacity == 0.\n"); 15 | break; 16 | case 2: 17 | printf("list->size != 0 when \"create_arraylist('int')\" returns.\n"); 18 | break; 19 | case 3: 20 | printf("list->elements == NULL when \"create_arraylist('int')\" returns.\n"); 21 | break; 22 | } 23 | printf("\n"); 24 | return false; 25 | } else { 26 | arraylist *list = create_arraylist(0); 27 | int_assert_equal(list->capacity, 10, 1); 28 | int_assert_equal(list->size, 0, 2); 29 | int_assert_nequal((long) list->elements, 0, 3); 30 | free(list->elements); 31 | free(list); 32 | 33 | list = create_arraylist(5); 34 | int_assert_equal(list->capacity, 5, 4); 35 | int_assert_equal(list->size, 0, 2); 36 | int_assert_nequal((long) list->elements, 0, 3); 37 | free(list->elements); 38 | free(list); 39 | 40 | printf("\x1b[32m passed!\x1b[0m\n\n"); 41 | return true; 42 | } 43 | } 44 | 45 | bool test_create_arraylist_OOM() { 46 | printf("Test: \"create_arraylist(ULLONG_MAX)\" starting ..."); 47 | 48 | int assert_code; 49 | 50 | if ((assert_code = setjmp(break_point))) { 51 | printf("\x1b[31m failed!\x1b[0m\n\n"); 52 | switch (assert_code) { 53 | case 1: 54 | printf("list != NULL when \"create_arraylist(ULLONG_MAX)\" returns.\n"); 55 | break; 56 | } 57 | printf("\n"); 58 | return false; 59 | } else { 60 | 61 | arraylist *list = create_arraylist(ULLONG_MAX); 62 | 63 | int_assert_equal((long) list, 0, 1); 64 | printf("\x1b[32m passed!\x1b[0m\n\n"); 65 | return true; 66 | } 67 | } 68 | 69 | bool test_al_add() { 70 | printf("Test: \"al_add('arraylist *', 'void *')\" starting ..."); 71 | 72 | int assert_code; 73 | 74 | if ((assert_code = setjmp(break_point))) { 75 | printf("\x1b[31m failed!\x1b[0m\n\n"); 76 | switch (assert_code) { 77 | case 1: 78 | printf("list values not correctly populated by \"al_add('arraylist *', 'void *')\".\n"); 79 | break; 80 | case 2: 81 | printf("list->size not correctly updated by \"al_add('arraylist *', 'void *')\"\n"); 82 | break; 83 | case 3: 84 | printf("list->capacity should not have changed when only adding 3 values.\n"); 85 | break; 86 | case 4: 87 | printf("list->elements did not resize properly when more than list->capacity elements were added.\n"); 88 | break; 89 | case 5: 90 | printf("\"al_add('arraylist *','void *')\" does not maintain correct order of elements.\n"); 91 | 92 | break; 93 | } 94 | printf("\n"); 95 | return false; 96 | } else { 97 | arraylist *list = create_arraylist(10); 98 | al_add(list, Integer(3)); 99 | al_add(list, Integer(4)); 100 | al_add(list, Integer(5)); 101 | int_assert_equal(*((int *) (list->elements[0])), 3, 1); 102 | int_assert_equal(*((int *) (list->elements[1])), 4, 1); 103 | int_assert_equal(*((int *) (list->elements[2])), 5, 1); 104 | 105 | int_assert_equal(list->size, 3, 2); 106 | int_assert_equal(list->capacity, 10, 3); 107 | 108 | for (int i = 0; i < 10; ++i) { 109 | al_add(list, Integer(4)); 110 | } 111 | 112 | int_assert_equal(list->size, 13, 2); 113 | int_assert_equal(list->capacity, 20, 4); 114 | 115 | int correct_values[] = {3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; 116 | 117 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 5); 118 | 119 | al_delete(list); 120 | free(list); 121 | 122 | printf("\x1b[32m passed!\x1b[0m\n\n"); 123 | return true; 124 | } 125 | } 126 | 127 | bool test_al_addAt() { 128 | printf("Test: \"al_addAt('arraylist *', 'size_t' ,'void *')\" starting ..."); 129 | 130 | int assert_code; 131 | 132 | if ((assert_code = setjmp(break_point))) { 133 | printf("\x1b[31m failed!\x1b[0m\n\n"); 134 | switch (assert_code) { 135 | case 1: 136 | printf("\"al_addAt('arraylist *', 'size_t' ,'void *')\" does not maintain correct order of elements.\n"); 137 | break; 138 | case 2: 139 | printf("\"al_addAt('arraylist *', 'size_t' ,'void *')\" does not increase array size.\n"); 140 | break; 141 | case 3: 142 | printf("\"al_addAt('arraylist *', 'size_t' ,'void *')\" return incorrect status code.\n"); 143 | break; 144 | case 4: 145 | printf("\"al_addAt('arraylist *', 'size_t' ,'void *')\" does not correctly resize backing array.\n"); 146 | break; 147 | case 5: 148 | printf("\"al_addAt('arraylist *', 'size_t' ,'void *')\" does not return false when argument 'size_t' out of range.\n"); 149 | break; 150 | } 151 | printf("\n"); 152 | return false; 153 | } else { 154 | arraylist *list = create_arraylist(6); 155 | al_add(list, Integer(3)); 156 | al_add(list, Integer(4)); 157 | bool status = al_add_at(list, 1, Integer(5)); 158 | 159 | int_assert_equal(list->size, 3, 2); 160 | bool_assert_equal(status, true, 3); 161 | 162 | int correct_values[] = {3, 5, 4, -1, -1, -1, -1}; 163 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 1); 164 | 165 | status = al_add_at(list, 3, Integer(9)); 166 | bool_assert_equal(status, true, 3); 167 | int_assert_equal(list->size, 4, 2); 168 | 169 | correct_values[3] = 9; 170 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 1); 171 | 172 | al_add_at(list, 0, Integer(-3)); 173 | al_add_at(list, 0, Integer(-4)); 174 | al_add_at(list, 0, Integer(-5)); 175 | 176 | correct_values[0] = -5; 177 | correct_values[1] = -4; 178 | correct_values[2] = -3; 179 | correct_values[3] = 3; 180 | correct_values[4] = 5; 181 | correct_values[5] = 4; 182 | correct_values[6] = 9; 183 | 184 | int_assert_equal(list->size, 7, 2); 185 | int_assert_equal(list->capacity, 12, 4); 186 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 1); 187 | 188 | status = al_add_at(list, 999, Integer(10)); 189 | bool_assert_equal(status, false, 5); 190 | 191 | printf("\x1b[32m passed!\x1b[0m\n\n"); 192 | return true; 193 | } 194 | } 195 | 196 | bool test_al_set() { 197 | printf("Test: \"al_set('arraylist *', 'size_t' ,'void *')\" starting ..."); 198 | 199 | int assert_code; 200 | 201 | if ((assert_code = setjmp(break_point))) { 202 | 203 | printf("\x1b[31m failed!\x1b[0m\n"); 204 | switch (assert_code) { 205 | case 2: 206 | printf("\"al_set('arraylist *', 'size_t' ,'void *')\" changes size.\n"); 207 | break; 208 | case 1: 209 | printf("\"al_set('arraylist *', 'size_t' ,'void *')\" does not preserve correct order.\n"); 210 | break; 211 | 212 | } 213 | printf("\n"); 214 | return false; 215 | } else { 216 | arraylist *list = create_arraylist(6); 217 | al_add(list, Integer(3)); 218 | al_add(list, Integer(4)); 219 | al_add(list, Integer(5)); 220 | 221 | al_set(list, 1, Integer(6)); 222 | 223 | int correct_values[] = {3, 6, 5}; 224 | int_assert_equal(list->size, 3, 2); 225 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 1); 226 | 227 | printf("\x1b[32m passed!\x1b[0m\n\n"); 228 | return true; 229 | } 230 | } 231 | 232 | bool test_ensure_capacity() { 233 | printf("Test: \"al_ensure_capacity('arraylist *', 'size_t')\" starting ..."); 234 | 235 | int assert_code; 236 | 237 | if ((assert_code = setjmp(break_point))) { 238 | 239 | printf("\x1b[31m failed!\x1b[0m\n"); 240 | switch (assert_code) { 241 | printf("al_ensure_capacity('arraylist *', 'size_t') "); 242 | case 1: 243 | printf("starting capacity is incorrect.\n"); 244 | break; 245 | case 2: 246 | printf("starting size is incorrect.\n"); 247 | break; 248 | case 3: 249 | printf("should fail when new_capacity < list->size.\n"); 250 | break; 251 | case 4: 252 | printf("should return false when OOM occurs.\n"); 253 | break; 254 | case 5: 255 | printf("should return true when successfully resizes.\n"); 256 | break; 257 | case 6: 258 | printf("should preserve size when resizing.\n"); 259 | break; 260 | 261 | } 262 | printf("\n"); 263 | return false; 264 | } else { 265 | arraylist *list = create_arraylist(6); 266 | 267 | al_add(list, Integer(1)); 268 | al_add(list, Integer(1)); 269 | 270 | int_assert_equal(list->capacity, 6, 1); 271 | int_assert_equal(list->size, 2, 2); 272 | 273 | bool status = al_ensure_capacity(list, 1); 274 | bool_assert_equal(status, false, 3); 275 | 276 | status = al_ensure_capacity(list, ULLONG_MAX); 277 | bool_assert_equal(status, false, 4); 278 | 279 | status = al_ensure_capacity(list, 3); 280 | bool_assert_equal(status, true, 5); 281 | int_assert_equal(list->size, 2, 6); 282 | 283 | printf("\x1b[32m passed!\x1b[0m\n\n"); 284 | return true; 285 | } 286 | } 287 | 288 | bool test_al_get() { 289 | printf("Test: \"al_get('arraylist *', 'size_t')\" starting ..."); 290 | 291 | int assert_code; 292 | 293 | if ((assert_code = setjmp(break_point))) { 294 | 295 | printf("\x1b[31m failed!\x1b[0m\n"); 296 | switch (assert_code) { 297 | case 1: 298 | printf("does not return correct value\n"); 299 | break; 300 | case 2: 301 | printf("index out of bounds should return null\n."); 302 | break; 303 | 304 | } 305 | printf("\n"); 306 | return false; 307 | } else { 308 | arraylist *list = create_arraylist(6); 309 | 310 | al_add(list, Integer(1)); 311 | al_add(list, Integer(2)); 312 | 313 | int *i = (int *) al_get(list, 1); 314 | int_assert_equal(*i, 2, 1); 315 | 316 | i = (int *) al_get(list, 0); 317 | int_assert_equal(*i, 1, 1); 318 | 319 | i = (int *) al_get(list, 2); 320 | int_assert_equal((long) i, 0, 2); 321 | 322 | 323 | printf("\x1b[32m passed!\x1b[0m\n\n"); 324 | return true; 325 | } 326 | } 327 | 328 | bool test_remove() { 329 | printf("Test: \"al_remove('arraylist *', 'size_t')\" starting ..."); 330 | 331 | int assert_code; 332 | 333 | if ((assert_code = setjmp(break_point))) { 334 | 335 | printf("\x1b[31m failed!\x1b[0m\n"); 336 | switch (assert_code) { 337 | case 1: 338 | printf("size should be reduced by 1 when removing.\n"); 339 | break; 340 | case 2: 341 | printf("capacity should not change when removing.\n"); 342 | break; 343 | case 3: 344 | printf("does not retrieve correct value.\n"); 345 | break; 346 | case 4: 347 | printf("does not maintain order of remaining elements.\n"); 348 | break; 349 | 350 | } 351 | printf("\n"); 352 | return false; 353 | } else { 354 | arraylist *list = create_arraylist(6); 355 | al_add(list, Integer(3)); 356 | al_add(list, Integer(4)); 357 | al_add(list, Integer(5)); 358 | int *i = (void *) al_remove(list, 2); 359 | 360 | int_assert_equal(list->size, 2, 1); 361 | int_assert_equal(list->capacity, 6, 2); 362 | int_assert_equal(*i, 5, 3); 363 | 364 | int correct_values[2] = {3, 4}; 365 | 366 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 4); 367 | i = (void *) al_remove(list, 0); 368 | int_assert_equal(*i, 3, 3); 369 | correct_values[0] = 4; 370 | int_array_assert_equal((int **) list->elements, correct_values, list->size, 4); 371 | printf("\x1b[32m passed!\x1b[0m\n\n"); 372 | return true; 373 | } 374 | } 375 | 376 | bool test_sort() { 377 | return false; 378 | } --------------------------------------------------------------------------------