From 44a0d7c3c521875756d187e17d25d8294f84be1b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 27 Feb 2025 10:02:56 +0000 Subject: [PATCH] Added etl::create_linked_list and etl::detach_linked_list to the intrusive link utilities --- include/etl/intrusive_links.h | 196 ++++++++++++++++++++ test/test_intrusive_links.cpp | 337 ++++++++++++++++++++++++++++++++++ 2 files changed, 533 insertions(+) diff --git a/include/etl/intrusive_links.h b/include/etl/intrusive_links.h index 577f5010..1ca2479e 100644 --- a/include/etl/intrusive_links.h +++ b/include/etl/intrusive_links.h @@ -404,6 +404,112 @@ namespace etl } } +#if ETL_USING_CPP17 + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first, TLinks&... links) + { + TLink* current = &first; + ((current->etl_next = &links, current = &links), ...); + + return current; + } + + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink* first, TLinks*... links) + { + if (first != ETL_NULLPTR) + { + return create_linked_list(*first, (*links)...); + } + else + { + return nullptr; + } + } +#elif ETL_USING_CPP11 + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first) + { + return &first; + } + + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first, TLink& next, TLinks&... links) + { + first.etl_next = &next; + return create_linked_list(next, static_cast(links)...); + } + + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink* first) + { + if (first != ETL_NULLPTR) + { + return create_linked_list(*first); + } + else + { + return ETL_NULLPTR; + } + } + + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink* first, TLink* next, TLinks*... links) + { + if (first != ETL_NULLPTR) + { + return create_linked_list(*first, *next, static_cast(*links)...); + } + else + { + return ETL_NULLPTR; + } + } +#endif + + //*************************************************************************** + template + typename etl::enable_if::value, void>::type + detach_linked_list(TLink& first) + { + link_clear_range(first); + } + + //*************************************************************************** + template + typename etl::enable_if::value, void>::type + detach_linked_list(TLink* first) + { + if (first != ETL_NULLPTR) + { + detach_linked_list(*first); + } + } + //*************************************************************************** /// A bidirectional link. //*************************************************************************** @@ -829,6 +935,96 @@ namespace etl etl::link_clear_range(*start); } +#if ETL_USING_CPP17 + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first, TLinks&... links) + { + TLink* current = &first; + ((current->etl_next = &links, static_cast(links).etl_previous = current, current = &links), ...); + current->etl_next = ETL_NULLPTR; + + return current; + } + + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink* first, TLinks*... links) + { + TLink* current = first; + ((current->etl_next = links, static_cast(links)->etl_previous = current, current = links), ...); + current->etl_next = ETL_NULLPTR; + + return current; + } +#elif ETL_USING_CPP11 + + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first) + { + return &first; + } + + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink& first, TLink& next, TLinks&... links) + { + first.etl_next = &next; + next.etl_previous = &first; + + return create_linked_list(next, static_cast(links)...); + } + + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + typename etl::enable_if::value, TLink*>::type + create_linked_list(TLink* first, TLink* next, TLinks*... links) + { + if (first != ETL_NULLPTR) + { + return create_linked_list(*first, *next, static_cast(*links)...); + } + else + { + return ETL_NULLPTR; + } + } +#endif + + //*************************************************************************** + template + typename etl::enable_if::value, void>::type + detach_linked_list(TLink& first) + { + link_clear_range(first); + } + + //*************************************************************************** + template + typename etl::enable_if::value, void>::type + detach_linked_list(TLink* first) + { + if (first != ETL_NULLPTR) + { + detach_linked_list(*first); + } + } + //*************************************************************************** /// A binary tree link. //*************************************************************************** diff --git a/test/test_intrusive_links.cpp b/test/test_intrusive_links.cpp index 13a09c5b..cdfa1d8c 100644 --- a/test/test_intrusive_links.cpp +++ b/test/test_intrusive_links.cpp @@ -32,6 +32,8 @@ SOFTWARE. #include "etl/intrusive_links.h" +#include + namespace { //******************************************************* @@ -157,6 +159,166 @@ namespace CHECK_EQUAL(0, pdata->value); } + //************************************************************************* + TEST(test_create_linked_list_multiple_forward_links_as_references) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + FLink0* last0 = etl::create_linked_list(data0, data1, data2, data3); + CHECK(last0 == &data3); + CHECK(data0.FLink0::etl_next == &data1); + CHECK(data1.FLink0::etl_next == &data2); + CHECK(data2.FLink0::etl_next == &data3); + CHECK(data3.FLink0::etl_next == ETL_NULLPTR); + + FLink1* last1 = etl::create_linked_list(data3, data2, data1, data0); + CHECK(last1 == &data0); + CHECK(data3.FLink1::etl_next == &data2); + CHECK(data2.FLink1::etl_next == &data1); + CHECK(data1.FLink1::etl_next == &data0); + CHECK(data0.FLink1::etl_next == ETL_NULLPTR); + + FData* pdata; + + pdata = static_cast(data0.FLink0::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->FLink0::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->FLink0::etl_next); + CHECK_EQUAL(3, pdata->value); + + pdata = static_cast(data3.FLink1::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->FLink1::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->FLink1::etl_next); + CHECK_EQUAL(0, pdata->value); + + FData data4(4); + FData data5(5); + FData data6(6); + FData data7(7); + + auto last2 = etl::create_linked_list(*last0, data4, data5, data6, data7); + CHECK(last2 == &data7); + CHECK(data0.FLink0::etl_next == &data1); + CHECK(data1.FLink0::etl_next == &data2); + CHECK(data2.FLink0::etl_next == &data3); + CHECK(data3.FLink0::etl_next == &data4); + CHECK(data4.FLink0::etl_next == &data5); + CHECK(data5.FLink0::etl_next == &data6); + CHECK(data6.FLink0::etl_next == &data7); + CHECK(data7.FLink0::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_create_linked_list_multiple_forward_links_as_pointers) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + FLink0* last0 = etl::create_linked_list(&data0, &data1, &data2, &data3); + CHECK(last0 == &data3); + CHECK(data0.FLink0::etl_next == &data1); + CHECK(data1.FLink0::etl_next == &data2); + CHECK(data2.FLink0::etl_next == &data3); + CHECK(data3.FLink0::etl_next == ETL_NULLPTR); + + FLink1* last1 = etl::create_linked_list(&data3, &data2, &data1, &data0); + CHECK(last1 == &data0); + CHECK(data3.FLink1::etl_next == &data2); + CHECK(data2.FLink1::etl_next == &data1); + CHECK(data1.FLink1::etl_next == &data0); + CHECK(data0.FLink1::etl_next == ETL_NULLPTR); + + FData* pdata; + + pdata = static_cast(data0.FLink0::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->FLink0::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->FLink0::etl_next); + CHECK_EQUAL(3, pdata->value); + + pdata = static_cast(data3.FLink1::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->FLink1::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->FLink1::etl_next); + CHECK_EQUAL(0, pdata->value); + + FData data4(4); + FData data5(5); + FData data6(6); + FData data7(7); + + auto last2 = etl::create_linked_list(last0, &data4, &data5, &data6, &data7); + CHECK(last2 == &data7); + CHECK(data0.FLink0::etl_next == &data1); + CHECK(data1.FLink0::etl_next == &data2); + CHECK(data2.FLink0::etl_next == &data3); + CHECK(data3.FLink0::etl_next == &data4); + CHECK(data4.FLink0::etl_next == &data5); + CHECK(data5.FLink0::etl_next == &data6); + CHECK(data6.FLink0::etl_next == &data7); + CHECK(data7.FLink0::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_detach_linked_list_multiple_forward_links_as_references) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + etl::create_linked_list(data0, data1, data2, data3); + etl::create_linked_list(data3, data2, data1, data0); + + etl::detach_linked_list(data0); + etl::detach_linked_list(data3); + + CHECK(data0.FLink0::etl_next == ETL_NULLPTR); + CHECK(data1.FLink0::etl_next == ETL_NULLPTR); + CHECK(data2.FLink0::etl_next == ETL_NULLPTR); + CHECK(data3.FLink0::etl_next == ETL_NULLPTR); + + CHECK(data0.FLink1::etl_next == ETL_NULLPTR); + CHECK(data1.FLink1::etl_next == ETL_NULLPTR); + CHECK(data2.FLink1::etl_next == ETL_NULLPTR); + CHECK(data3.FLink1::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_detach_linked_list_multiple_forward_links_as_pointers) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + etl::create_linked_list(data0, data1, data2, data3); + etl::create_linked_list(data3, data2, data1, data0); + + etl::detach_linked_list(&data0); + etl::detach_linked_list(&data3); + + CHECK(data0.FLink0::etl_next == ETL_NULLPTR); + CHECK(data1.FLink0::etl_next == ETL_NULLPTR); + CHECK(data2.FLink0::etl_next == ETL_NULLPTR); + CHECK(data3.FLink0::etl_next == ETL_NULLPTR); + + CHECK(data0.FLink1::etl_next == ETL_NULLPTR); + CHECK(data1.FLink1::etl_next == ETL_NULLPTR); + CHECK(data2.FLink1::etl_next == ETL_NULLPTR); + CHECK(data3.FLink1::etl_next == ETL_NULLPTR); + } + //************************************************************************* TEST(test_link_forward_link_get_set) { @@ -537,6 +699,181 @@ namespace data2.BLink0::unlink(); } + //************************************************************************* + TEST(test_create_linked_list_multiple_bidirectional_links_as_references) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + BLink0* last0 = etl::create_linked_list(data0, data1, data2, data3); + CHECK(last0 == &data3); + CHECK(data0.BLink0::etl_previous == ETL_NULLPTR); + CHECK(data0.BLink0::etl_next == &data1); + CHECK(data1.BLink0::etl_previous == &data0); + CHECK(data1.BLink0::etl_next == &data2); + CHECK(data2.BLink0::etl_previous == &data1); + CHECK(data2.BLink0::etl_next == &data3); + CHECK(data3.BLink0::etl_previous == &data2); + CHECK(data3.BLink0::etl_next == ETL_NULLPTR); + + BLink1* last1 = etl::create_linked_list(data3, data2, data1, data0); + CHECK(last1 == &data0); + CHECK(data3.BLink1::etl_previous == ETL_NULLPTR); + CHECK(data3.BLink1::etl_next == &data2); + CHECK(data2.BLink1::etl_previous == &data3); + CHECK(data2.BLink1::etl_next == &data1); + CHECK(data1.BLink1::etl_previous == &data2); + CHECK(data1.BLink1::etl_next == &data0); + CHECK(data0.BLink1::etl_previous == &data1); + CHECK(data0.BLink1::etl_next == ETL_NULLPTR); + + BData* pdata; + + pdata = static_cast(data0.BLink0::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->BLink0::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->BLink0::etl_next); + CHECK_EQUAL(3, pdata->value); + + pdata = static_cast(data3.BLink1::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->BLink1::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->BLink1::etl_next); + CHECK_EQUAL(0, pdata->value); + + BData data4(4); + BData data5(5); + BData data6(6); + BData data7(7); + + auto last2 = etl::create_linked_list(*last0, data4, data5, data6, data7); + CHECK(last2 == &data7); + CHECK(data0.BLink0::etl_previous == ETL_NULLPTR); + CHECK(data0.BLink0::etl_next == &data1); + CHECK(data1.BLink0::etl_previous == &data0); + CHECK(data1.BLink0::etl_next == &data2); + CHECK(data2.BLink0::etl_previous == &data1); + CHECK(data2.BLink0::etl_next == &data3); + CHECK(data3.BLink0::etl_previous == &data2); + CHECK(data3.BLink0::etl_next == &data4); + CHECK(data4.BLink0::etl_previous == &data3); + CHECK(data4.BLink0::etl_next == &data5); + CHECK(data5.BLink0::etl_previous == &data4); + CHECK(data5.BLink0::etl_next == &data6); + CHECK(data6.BLink0::etl_previous == &data5); + CHECK(data6.BLink0::etl_next == &data7); + CHECK(data7.BLink0::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_create_linked_list_multiple_bidirectional_links_as_pointers) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + BLink0* last0 = etl::create_linked_list(&data0, &data1, &data2, &data3); + CHECK(last0 == &data3); + CHECK(data0.BLink0::etl_next == &data1); + CHECK(data1.BLink0::etl_next == &data2); + CHECK(data2.BLink0::etl_next == &data3); + CHECK(data3.BLink0::etl_next == ETL_NULLPTR); + + BLink1* last1 = etl::create_linked_list(&data3, &data2, &data1, &data0); + CHECK(last1 == &data0); + CHECK(data3.BLink1::etl_next == &data2); + CHECK(data2.BLink1::etl_next == &data1); + CHECK(data1.BLink1::etl_next == &data0); + CHECK(data0.BLink1::etl_next == ETL_NULLPTR); + + BData* pdata; + + pdata = static_cast(data0.BLink0::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->BLink0::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->BLink0::etl_next); + CHECK_EQUAL(3, pdata->value); + + pdata = static_cast(data3.BLink1::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->BLink1::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->BLink1::etl_next); + CHECK_EQUAL(0, pdata->value); + + BData data4(4); + BData data5(5); + BData data6(6); + BData data7(7); + + auto last2 = etl::create_linked_list(last0, &data4, &data5, &data6, &data7); + CHECK(last2 == &data7); + CHECK(data0.BLink0::etl_next == &data1); + CHECK(data1.BLink0::etl_next == &data2); + CHECK(data2.BLink0::etl_next == &data3); + CHECK(data3.BLink0::etl_next == &data4); + CHECK(data4.BLink0::etl_next == &data5); + CHECK(data5.BLink0::etl_next == &data6); + CHECK(data6.BLink0::etl_next == &data7); + CHECK(data7.BLink0::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_detach_linked_list_multiple_bidirectional_links_as_references) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + etl::create_linked_list(data0, data1, data2, data3); + etl::create_linked_list(data3, data2, data1, data0); + + etl::detach_linked_list(data0); + etl::detach_linked_list(data3); + + CHECK(data0.BLink0::etl_next == ETL_NULLPTR); + CHECK(data1.BLink0::etl_next == ETL_NULLPTR); + CHECK(data2.BLink0::etl_next == ETL_NULLPTR); + CHECK(data3.BLink0::etl_next == ETL_NULLPTR); + + CHECK(data0.BLink1::etl_next == ETL_NULLPTR); + CHECK(data1.BLink1::etl_next == ETL_NULLPTR); + CHECK(data2.BLink1::etl_next == ETL_NULLPTR); + CHECK(data3.BLink1::etl_next == ETL_NULLPTR); + } + + //************************************************************************* + TEST(test_detach_linked_list_multiple_bidirectional_links_as_pointers) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + etl::create_linked_list(data0, data1, data2, data3); + etl::create_linked_list(data3, data2, data1, data0); + + etl::detach_linked_list(&data0); + etl::detach_linked_list(&data3); + + CHECK(data0.BLink0::etl_next == ETL_NULLPTR); + CHECK(data1.BLink0::etl_next == ETL_NULLPTR); + CHECK(data2.BLink0::etl_next == ETL_NULLPTR); + CHECK(data3.BLink0::etl_next == ETL_NULLPTR); + + CHECK(data0.BLink1::etl_next == ETL_NULLPTR); + CHECK(data1.BLink1::etl_next == ETL_NULLPTR); + CHECK(data2.BLink1::etl_next == ETL_NULLPTR); + CHECK(data3.BLink1::etl_next == ETL_NULLPTR); + } + //************************************************************************* TEST(test_link_bidirectional_link_get_set) {