Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LIST_SPLICE_TAIL/LIST_SPLICE_HEAD #265

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions lib/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,37 @@ __END_EXTERN_C
list_head_init((struct list_head *)(HEAD)); \
CHECK_TYPE(&(HEAD)->first, (HEAD)->tailnextp)

/*
* LIST_SPLICE_TAIL/LIST_SPLICE_HEAD
*
* move all items on the SRC list to the TAIL/HEAD of the DST list.
* O(1) regardless of the number of items to move.
* this leaves the SRC list in an inconsistent state. it's up to
* the user to do LIST_HEAD_INIT(SRC) if necessary.
*/

#define LIST_SPLICE_TAIL(DST, SRC, NAME) \
do { \
if (!LIST_EMPTY(SRC)) { \
(SRC)->first->NAME.prevnextp = (DST)->tailnextp; \
*(DST)->tailnextp = (SRC)->first; \
(DST)->tailnextp = (SRC)->tailnextp; \
} \
} while (0)

#define LIST_SPLICE_HEAD(DST, SRC, NAME) \
do { \
if (!LIST_EMPTY(SRC)) { \
if (LIST_EMPTY(DST)) { \
(DST)->tailnextp = (SRC)->tailnextp; \
} else { \
(DST)->first->NAME.prevnextp = \
(SRC)->tailnextp; \
*(SRC)->tailnextp = (DST)->first; \
} \
(DST)->first = (SRC)->first; \
(DST)->first->NAME.prevnextp = &(DST)->first; \
} \
} while (0)

#endif /* !defined(_TOYWASM_LIST_H) */
99 changes: 99 additions & 0 deletions test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,104 @@ test_list(void **state)
assert_null(LIST_LAST(&h, struct item, entry));
}

void
test_list2(void **state)
{
struct item {
void *dummy1;
LIST_ENTRY(struct item) entry;
int dummy2;
};

LIST_HEAD(struct item) h0;
LIST_HEAD(struct item) h1;
LIST_HEAD(struct item) h2;
LIST_HEAD(struct item) hempty;

struct item i1;
struct item i2;
struct item i3;
struct item i4;
struct item i5;
struct item i6;

/* test LIST_SPLICE_TAIL */

LIST_HEAD_INIT(&h0);

LIST_HEAD_INIT(&h1);
LIST_INSERT_TAIL(&h1, &i1, entry);
LIST_INSERT_TAIL(&h1, &i2, entry);
LIST_INSERT_TAIL(&h1, &i3, entry);

LIST_HEAD_INIT(&h2);
LIST_INSERT_HEAD(&h2, &i6, entry);
LIST_INSERT_HEAD(&h2, &i5, entry);
LIST_INSERT_HEAD(&h2, &i4, entry);

LIST_HEAD_INIT(&hempty);
LIST_SPLICE_TAIL(&h0, &hempty, entry);
LIST_SPLICE_TAIL(&h0, &h1, entry);
LIST_HEAD_INIT(&hempty);
LIST_SPLICE_TAIL(&h0, &hempty, entry);
LIST_SPLICE_TAIL(&h0, &h2, entry);
LIST_HEAD_INIT(&hempty);
LIST_SPLICE_TAIL(&h0, &hempty, entry);

assert_ptr_equal(LIST_FIRST(&h0), &i1);
assert_ptr_equal(LIST_NEXT(&i1, entry), &i2);
assert_ptr_equal(LIST_NEXT(&i2, entry), &i3);
assert_ptr_equal(LIST_NEXT(&i3, entry), &i4);
assert_ptr_equal(LIST_NEXT(&i4, entry), &i5);
assert_ptr_equal(LIST_NEXT(&i5, entry), &i6);
assert_null(LIST_NEXT(&i6, entry));
assert_ptr_equal(LIST_LAST(&h0, struct item, entry), &i6);
assert_ptr_equal(LIST_PREV(&i6, &h0, struct item, entry), &i5);
assert_ptr_equal(LIST_PREV(&i5, &h0, struct item, entry), &i4);
assert_ptr_equal(LIST_PREV(&i4, &h0, struct item, entry), &i3);
assert_ptr_equal(LIST_PREV(&i3, &h0, struct item, entry), &i2);
assert_ptr_equal(LIST_PREV(&i2, &h0, struct item, entry), &i1);
assert_null(LIST_PREV(&i1, &h0, struct item, entry));

/* test LIST_SPLICE_HEAD */

LIST_HEAD_INIT(&h0);

LIST_HEAD_INIT(&h1);
LIST_INSERT_TAIL(&h1, &i1, entry);
LIST_INSERT_TAIL(&h1, &i2, entry);
LIST_INSERT_TAIL(&h1, &i3, entry);

LIST_HEAD_INIT(&h2);
LIST_INSERT_HEAD(&h2, &i6, entry);
LIST_INSERT_HEAD(&h2, &i5, entry);
LIST_INSERT_HEAD(&h2, &i4, entry);

LIST_HEAD_INIT(&hempty);
LIST_SPLICE_HEAD(&h0, &hempty, entry);
LIST_SPLICE_HEAD(&h0, &h1, entry);
LIST_HEAD_INIT(&hempty);
LIST_SPLICE_HEAD(&h0, &hempty, entry);
LIST_SPLICE_HEAD(&h0, &h2, entry);
LIST_HEAD_INIT(&hempty);
LIST_SPLICE_HEAD(&h0, &hempty, entry);

assert_ptr_equal(LIST_FIRST(&h0), &i4);
assert_ptr_equal(LIST_NEXT(&i4, entry), &i5);
assert_ptr_equal(LIST_NEXT(&i5, entry), &i6);
assert_ptr_equal(LIST_NEXT(&i6, entry), &i1);
assert_ptr_equal(LIST_NEXT(&i1, entry), &i2);
assert_ptr_equal(LIST_NEXT(&i2, entry), &i3);
assert_null(LIST_NEXT(&i3, entry));
assert_ptr_equal(LIST_LAST(&h0, struct item, entry), &i3);
assert_ptr_equal(LIST_PREV(&i3, &h0, struct item, entry), &i2);
assert_ptr_equal(LIST_PREV(&i2, &h0, struct item, entry), &i1);
assert_ptr_equal(LIST_PREV(&i1, &h0, struct item, entry), &i6);
assert_ptr_equal(LIST_PREV(&i6, &h0, struct item, entry), &i5);
assert_ptr_equal(LIST_PREV(&i5, &h0, struct item, entry), &i4);
assert_null(LIST_PREV(&i4, &h0, struct item, entry));
}

void
test_xstrnstr(void **state)
{
Expand Down Expand Up @@ -824,6 +922,7 @@ main(int argc, char **argv)
cmocka_unit_test(test_timeutil),
cmocka_unit_test(test_timeutil_int64),
cmocka_unit_test(test_list),
cmocka_unit_test(test_list2),
cmocka_unit_test(test_xstrnstr),
};
return cmocka_run_group_tests(tests, NULL, NULL);
Expand Down
Loading