diff --git a/AUTHORS b/AUTHORS index ddc4797..76dea87 100644 --- a/AUTHORS +++ b/AUTHORS @@ -36,5 +36,6 @@ AUTHORS: (ordered alphabetically) Danilo Horta David Rheinsberg Lucas De Marchi + Michele Dionisio Thomas Haller Tom Gundersen diff --git a/NEWS.md b/NEWS.md index 945e7f5..02d2c9a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,9 @@ * The minimum required meson version is now 0.60.0. + * New function c_list_split() is added. It reverses c_list_splice() + and thus allows to split a list in half. + * TBD Contributions from: David Rheinsberg diff --git a/src/c-list.h b/src/c-list.h index 69de0b3..711b54d 100644 --- a/src/c-list.h +++ b/src/c-list.h @@ -259,6 +259,31 @@ static inline void c_list_splice(CList *target, CList *source) { } } +/** + * c_list_split() - split one list in two + * @source: the list to split + * @where: new starting element of newlist + * @target: new list + * + * This splits @source in two. All elements following @where (including @where) + * are moved to @target, replacing any old list. If @where points to @source + * (i.e., the end of the list), @target will be empty. + */ +static inline void c_list_split(CList *source, CList *where, CList *target) { + if (where == source) { + *target = (CList)C_LIST_INIT(*target); + } else { + target->next = where; + target->prev = source->prev; + + where->prev->next = source; + source->prev = where->prev; + + where->prev = target; + target->prev->next = target; + } +} + /** * c_list_first() - return pointer to first element, or NULL if empty * @list: list to operate on, or NULL diff --git a/src/test-api.c b/src/test-api.c index bf760cf..864d198 100644 --- a/src/test-api.c +++ b/src/test-api.c @@ -17,7 +17,8 @@ typedef struct { } Node; static void test_api(void) { - CList *list_iter, *list_safe, list = C_LIST_INIT(list); + CList *list_iter, *list_safe; + CList list = C_LIST_INIT(list), list2 = C_LIST_INIT(list2); Node node = { .id = 0, .link = C_LIST_INIT(node.link) }; assert(c_list_init(&list) == &list); @@ -68,7 +69,7 @@ static void test_api(void) { c_list_unlink(&node.link); assert(!c_list_is_linked(&node.link)); - /* swap / splice list operators */ + /* swap / splice / split list operators */ c_list_swap(&list, &list); assert(c_list_is_empty(&list)); @@ -76,6 +77,10 @@ static void test_api(void) { c_list_splice(&list, &list); assert(c_list_is_empty(&list)); + c_list_split(&list, &list, &list2); + assert(c_list_is_empty(&list)); + assert(c_list_is_empty(&list2)); + /* direct/raw iterators */ c_list_for_each(list_iter, &list) diff --git a/src/test-basic.c b/src/test-basic.c index 06cccd8..58ed863 100644 --- a/src/test-basic.c +++ b/src/test-basic.c @@ -11,6 +11,18 @@ #include #include "c-list.h" +static void assert_list_integrity(CList *list) { + CList *iter; + + iter = list; + do { + assert(iter->next->prev == iter); + assert(iter->prev->next == iter); + + iter = iter->next; + } while (iter != list); +} + static void test_iterators(void) { CList *iter, *safe, a, b, list = C_LIST_INIT(list); unsigned int i; @@ -158,6 +170,85 @@ static void test_splice(void) { assert(c_list_last(&target) == &e2); } +static void test_split(void) { + CList e1, e2; + + /* split empty list */ + { + CList source = C_LIST_INIT(source), target; + + c_list_split(&source, &source, &target); + assert(c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 1-element list excluding the element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_split(&source, &source, &target); + assert(!c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 1-element list including the element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_split(&source, &e1, &target); + assert(c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list excluding the elements */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &source, &target); + assert(!c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list including one element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &e2, &target); + assert(!c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list including both elements */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &e1, &target); + assert(c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } +} + + static void test_flush(void) { CList e1 = C_LIST_INIT(e1), e2 = C_LIST_INIT(e2); CList list1 = C_LIST_INIT(list1), list2 = C_LIST_INIT(list2); @@ -220,6 +311,7 @@ int main(void) { test_iterators(); test_swap(); test_splice(); + test_split(); test_flush(); test_macros(); test_gnu();