Skip to content

Commit

Permalink
c-list: add c_list_split()
Browse files Browse the repository at this point in the history
Add a new function c_list_split(), splitting an existing list in two.
It reverse c_list_splice().

Original-by: Michele Dionisio
(rework to allow empty lists to be split and simplify the tests)
Signed-off-by: David Rheinsberg <[email protected]>
  • Loading branch information
mdionisio authored and dvdhrm committed May 3, 2022
1 parent 76900e4 commit b86ba65
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ AUTHORS: (ordered alphabetically)
Danilo Horta <[email protected]>
David Rheinsberg <[email protected]>
Lucas De Marchi <[email protected]>
Michele Dionisio
Thomas Haller <[email protected]>
Tom Gundersen <[email protected]>
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions src/c-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions src/test-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -68,14 +69,18 @@ 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));

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)
Expand Down
92 changes: 92 additions & 0 deletions src/test-basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
#include <string.h>
#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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -220,6 +311,7 @@ int main(void) {
test_iterators();
test_swap();
test_splice();
test_split();
test_flush();
test_macros();
test_gnu();
Expand Down

0 comments on commit b86ba65

Please sign in to comment.