c-list: add c_list_split()

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 <david.rheinsberg@gmail.com>
main
Michele Dionisio 2022-01-26 09:34:40 +01:00 committed by David Rheinsberg
parent 76900e4e36
commit b86ba656ac
5 changed files with 128 additions and 2 deletions

View File

@ -36,5 +36,6 @@ AUTHORS: (ordered alphabetically)
Danilo Horta <danilo.horta@pm.me>
David Rheinsberg <david.rheinsberg@gmail.com>
Lucas De Marchi <lucas.de.marchi@gmail.com>
Michele Dionisio
Thomas Haller <thaller@redhat.com>
Tom Gundersen <teg@jklm.no>

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
@ -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();