commit ef56551877144c333eb315c393d159d2414ae0f3 from: Evan Burkey date: Sat Mar 14 06:10:36 2026 UTC add ll_find, ll_reverse, ll_sort, ll_to_array, LL_ITER_REV and simplify set to use ll_find commit - da735c49230ce27cc18449d4d5d7f3bcfecaa7de commit + ef56551877144c333eb315c393d159d2414ae0f3 blob - e152b15b776fb2c8c69f76664a019ec0248d7a59 blob + 6c63e57c408b7f62baa2bed580e9fa6b81c19e00 --- include/lflinkedlist.h +++ include/lflinkedlist.h @@ -34,7 +34,17 @@ int ll_remove_next(List *list, ListNode *node, void ** int ll_remove_prev(List *list, ListNode *node, void **data); +ListNode *ll_find(List *list, const void *data); + +void ll_reverse(List *list); + +void ll_sort(List *list, int (*cmp)(const void *a, const void *b)); + +void **ll_to_array(List *list); + /* Provides ListNode *node for the iteration loop */ #define LL_ITER(list) for(ListNode *node = (list)->head; node != NULL; node = node->next) +#define LL_ITER_REV(list) for(ListNode *node = (list)->tail; node != NULL; node = node->prev) + #endif blob - 53ec9d9a88a03fb3090e822ddcc9959b4fef0560 blob + 3efce6794774833d7c2752b2fe570b9e354da7dd --- src/linkedlist.c +++ src/linkedlist.c @@ -120,3 +120,110 @@ int ll_remove_prev(List *list, ListNode *node, void ** return ll_remove(list, node->prev, data); } +ListNode *ll_find(List *list, const void *data) { + if (list->match == NULL) { + return NULL; + } + for (ListNode *node = list->head; node != NULL; node = node->next) { + if (list->match(data, node->data)) { + return node; + } + } + return NULL; +} + +void ll_reverse(List *list) { + ListNode *cur = list->head; + ListNode *tmp; + while (cur != NULL) { + tmp = cur->next; + cur->next = cur->prev; + cur->prev = tmp; + cur = tmp; + } + tmp = list->head; + list->head = list->tail; + list->tail = tmp; +} + +static ListNode *ll_merge(ListNode *a, ListNode *b, + int (*cmp)(const void *, const void *)) { + ListNode dummy; + ListNode *tail = &dummy; + dummy.next = NULL; + + while (a != NULL && b != NULL) { + if (cmp(a->data, b->data) <= 0) { + tail->next = a; + a->prev = tail; + a = a->next; + } else { + tail->next = b; + b->prev = tail; + b = b->next; + } + tail = tail->next; + } + + tail->next = (a != NULL) ? a : b; + if (tail->next != NULL) { + tail->next->prev = tail; + } + + dummy.next->prev = NULL; + return dummy.next; +} + +static ListNode *ll_mergesort(ListNode *head, + int (*cmp)(const void *, const void *)) { + if (head == NULL || head->next == NULL) { + return head; + } + + /* split in half with slow/fast pointers */ + ListNode *slow = head; + ListNode *fast = head->next; + while (fast != NULL && fast->next != NULL) { + slow = slow->next; + fast = fast->next->next; + } + ListNode *second = slow->next; + slow->next = NULL; + if (second != NULL) { + second->prev = NULL; + } + + ListNode *a = ll_mergesort(head, cmp); + ListNode *b = ll_mergesort(second, cmp); + return ll_merge(a, b, cmp); +} + +void ll_sort(List *list, int (*cmp)(const void *a, const void *b)) { + if (list->size < 2) { + return; + } + list->head = ll_mergesort(list->head, cmp); + + /* fix tail pointer */ + ListNode *node = list->head; + while (node->next != NULL) { + node = node->next; + } + list->tail = node; +} + +void **ll_to_array(List *list) { + if (list->size == 0) { + return NULL; + } + void **arr = malloc(list->size * sizeof(void *)); + if (arr == NULL) { + return NULL; + } + size_t i = 0; + for (ListNode *node = list->head; node != NULL; node = node->next) { + arr[i++] = node->data; + } + return arr; +} + blob - 9e68fc54b2da44997bbd2dcc4d980f68c25aaef4 blob + e9ea33f070449ed8609fba04178972b065dba6a4 --- src/set.c +++ src/set.c @@ -18,14 +18,7 @@ int set_insert(Set *set, const void *data) { } int set_remove(Set *set, void **data) { - ListNode *node = NULL; - - for (node = set->head; node != NULL; node = node->next) { - if (set->match(*data, node->data)) { - break; - } - } - + ListNode *node = ll_find(set, *data); if (node == NULL) { return -1; } @@ -96,12 +89,7 @@ int set_difference(Set *setd, const Set *a, const Set } int set_is_member(const Set *set, const void *data) { - for (ListNode *node = set->head; node != NULL; node = node->next) { - if (set->match(data, node->data)) { - return 1; - } - } - return 0; + return ll_find((List *)set, data) != NULL; } int set_is_subset(const Set *a, const Set *b) { blob - 02121eab523233f0ce728df2fc6931aba6901619 blob + ff52d5816b27025a8199993784ea05baa32931ad --- tests/test_linkedlist.c +++ tests/test_linkedlist.c @@ -3,7 +3,18 @@ #include "lftest.h" #include "lflinkedlist.h" +static int match_int(const void *a, const void *b) { + return *(const int *)a == *(const int *)b; +} + +static int cmp_int(const void *a, const void *b) { + int x = *(const int *)a; + int y = *(const int *)b; + return (x > y) - (x < y); +} + int main() { + /* basic insert/remove */ List *list = malloc(sizeof(List)); ll_init(list, NULL); @@ -25,5 +36,107 @@ int main() { ll_destroy(list); free(list); + /* ll_find */ + list = malloc(sizeof(List)); + ll_init(list, NULL); + list->match = match_int; + + int a = 10, b = 20, c = 30; + ll_ins_next(list, list->head, &a); + ll_ins_next(list, list->tail, &b); + ll_ins_next(list, list->tail, &c); + + ListNode *found = ll_find(list, &b); + ASSERT_NOT_NULL(found); + ASSERT_EQ(*(int *)found->data, 20); + + int missing = 99; + found = ll_find(list, &missing); + ASSERT_NULL(found); + + /* ll_find with no match callback */ + list->match = NULL; + found = ll_find(list, &a); + ASSERT_NULL(found); + list->match = match_int; + + /* ll_reverse */ + ll_reverse(list); + ASSERT_EQ(*(int *)list->head->data, 30); + ASSERT_EQ(*(int *)list->tail->data, 10); + + int expected_rev[] = {30, 20, 10}; + int idx = 0; + LL_ITER(list) { + ASSERT_EQ(*(int *)node->data, expected_rev[idx++]); + } + + /* LL_ITER_REV */ + int expected_fwd[] = {10, 20, 30}; + idx = 0; + LL_ITER_REV(list) { + ASSERT_EQ(*(int *)node->data, expected_fwd[idx++]); + } + + /* ll_to_array */ + void **arr = ll_to_array(list); + ASSERT_NOT_NULL(arr); + ASSERT_EQ(*(int *)arr[0], 30); + ASSERT_EQ(*(int *)arr[1], 20); + ASSERT_EQ(*(int *)arr[2], 10); + free(arr); + + ll_destroy(list); + free(list); + + /* ll_sort */ + list = malloc(sizeof(List)); + ll_init(list, NULL); + + int s1 = 3, s2 = 1, s3 = 5, s4 = 2, s5 = 4; + ll_ins_next(list, list->head, &s1); + ll_ins_next(list, list->tail, &s2); + ll_ins_next(list, list->tail, &s3); + ll_ins_next(list, list->tail, &s4); + ll_ins_next(list, list->tail, &s5); + + ll_sort(list, cmp_int); + ASSERT_EQ(list->size, 5); + ASSERT_EQ(*(int *)list->head->data, 1); + ASSERT_EQ(*(int *)list->tail->data, 5); + + int expected_sorted[] = {1, 2, 3, 4, 5}; + idx = 0; + LL_ITER(list) { + ASSERT_EQ(*(int *)node->data, expected_sorted[idx++]); + } + + /* verify prev pointers are correct after sort */ + idx = 4; + LL_ITER_REV(list) { + ASSERT_EQ(*(int *)node->data, expected_sorted[idx--]); + } + + /* sort empty and single-element lists */ + ll_destroy(list); + ll_init(list, NULL); + ll_sort(list, cmp_int); + ASSERT_EQ(list->size, 0); + + int solo = 42; + ll_ins_next(list, list->head, &solo); + ll_sort(list, cmp_int); + ASSERT_EQ(list->size, 1); + ASSERT_EQ(*(int *)list->head->data, 42); + + /* ll_to_array on empty list */ + ll_destroy(list); + ll_init(list, NULL); + arr = ll_to_array(list); + ASSERT_NULL(arr); + + ll_destroy(list); + free(list); + TEST_REPORT(); }