diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 729d2ec37..11f446ba2 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -99,7 +99,7 @@ int ql_insert(quicklist ** qlp, int index, void * data) { ql->next = qn; qn->num_elements = QL_LIMIT; ql->num_elements -= QL_LIMIT; - memcpy(qn->elements, ql->elements+ql->num_elements-QL_LIMIT, QL_LIMIT*sizeof(void*)); + memcpy(qn->elements, ql->elements+ql->num_elements, QL_LIMIT*sizeof(void*)); if (index<=ql->num_elements) { return ql_insert(qlp, index, data); } else { @@ -113,3 +113,35 @@ int ql_insert(quicklist ** qlp, int index, void * data) { } return 0; } + +void ql_foreach(struct quicklist * ql, void (*cb)(void *)) +{ + for (;ql;ql=ql->next) { + int i; + for (i=0;i!=ql->num_elements;++i) { + cb(ql->elements[i]); + } + } +} + +int ql_advance(struct quicklist ** iterator, int * index, int stride) +{ + quicklist * ql = *iterator; + int i = *index; + if (!ql || i<0 || stride<0) { + return ERANGE; + } else if (i + stridenum_elements) { + *index = i + stride; + return 0; + } else { + *index = i - ql->num_elements + stride; + *iterator = ql->next; + return ql_advance(iterator, index, 0); + } +} + +void ql_free(struct quicklist * ql) +{ + if (ql->next) ql_free(ql->next); + free(ql); +} diff --git a/src/util/quicklist.h b/src/util/quicklist.h index d77ebcf94..89fc95cf7 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -22,13 +22,15 @@ extern "C" { #endif /* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ -struct quicklist; +typedef struct quicklist quicklist; void * ql_get(struct quicklist * ql, int index); int ql_length(const struct quicklist * ql); void ql_push(struct quicklist ** qlp, void * data); int ql_delete(struct quicklist ** qlp, int index); int ql_insert(struct quicklist ** qlp, int index, void * data); - +void ql_foreach(struct quicklist * ql, void (*cb)(void *)); +int ql_advance(struct quicklist ** iterator, int * index, int stride); +void ql_free(struct quicklist * ql); #ifdef __cplusplus } #endif diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c new file mode 100644 index 000000000..5125a9b37 --- /dev/null +++ b/src/util/quicklist_test.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include "quicklist.h" + +static const char * hello = "Hello World"; + +static void test_insert(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, i, ql_length(ql)); + ql_insert(&ql, 0, (void*)i); + } + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, 31-i, (int)ql_get(ql, i)); + } +} + +static void test_advance(CuTest * tc) { + struct quicklist * ql = NULL, *qli; + int i, n = 31; + for (i=0;i!=32;++i) { + ql_insert(&ql, 0, (void*)i); + } + for (i=0,qli=ql;qli;ql_advance(&qli, &i, 1),n--) { + int g = (int)ql_get(qli, i); + CuAssertIntEquals(tc, n, g); + } +} + +static void test_push(CuTest * tc) { + struct quicklist * ql = NULL; + CuAssertIntEquals(tc, 0, ql_length(ql)); + ql_push(&ql, (void*)hello); + CuAssertIntEquals(tc, 1, ql_length(ql)); + CuAssertStrEquals(tc, "Hello World", (const char *)ql_get(ql, 0)); + ql_delete(&ql, 0); + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_delete_edgecases(CuTest * tc) { + struct quicklist * ql = NULL; + ql_delete(&ql, 0); + CuAssertPtrEquals(tc, 0, ql); + ql_push(&ql, (void*)hello); + ql_delete(&ql, -1); + ql_delete(&ql, 32); + CuAssertIntEquals(tc, 1, ql_length(ql)); +} + +static void test_insert_many(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + ql_push(&ql, (void*)i); + } + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, 32-i, ql_length(ql)); + CuAssertIntEquals(tc, i, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 31, (int)ql_get(ql, ql_length(ql)-1)); + ql_delete(&ql, 0); + } + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_delete_rand(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + ql_push(&ql, (void*)i); + } + CuAssertIntEquals(tc, 32, ql_length(ql)); + ql_delete(&ql, 0); + CuAssertIntEquals(tc, 1, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 31, ql_length(ql)); + ql_delete(&ql, 30); + CuAssertIntEquals(tc, 30, ql_length(ql)); +} + +CuSuite* get_quicklist_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_advance); + SUITE_ADD_TEST(suite, test_push); + SUITE_ADD_TEST(suite, test_insert); + SUITE_ADD_TEST(suite, test_insert_many); + SUITE_ADD_TEST(suite, test_delete_rand); + SUITE_ADD_TEST(suite, test_delete_edgecases); + return suite; +}