commit - da735c49230ce27cc18449d4d5d7f3bcfecaa7de
commit + ef56551877144c333eb315c393d159d2414ae0f3
blob - e152b15b776fb2c8c69f76664a019ec0248d7a59
blob + 6c63e57c408b7f62baa2bed580e9fa6b81c19e00
--- include/lflinkedlist.h
+++ include/lflinkedlist.h
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
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
}
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;
}
}
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
#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);
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();
}