From a28cbddd4bafe232778f92890ac8df00ed814edb Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 27 Feb 2025 10:02:56 +0000 Subject: [PATCH 1/8] 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) { From 260a3f4a48c39504f21a96879ad59871e7af7e84 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 1 Mar 2025 13:39:51 +0000 Subject: [PATCH 2/8] Added variadic constructors --- include/etl/intrusive_forward_list.h | 49 +++++++++++++++++++++++++ include/etl/intrusive_list.h | 54 ++++++++++++++++++++++++++++ test/test_intrusive_forward_list.cpp | 23 ++++++++++++ test/test_intrusive_list.cpp | 23 ++++++++++++ 4 files changed, 149 insertions(+) diff --git a/include/etl/intrusive_forward_list.h b/include/etl/intrusive_forward_list.h index 84d0aa94..a466337f 100644 --- a/include/etl/intrusive_forward_list.h +++ b/include/etl/intrusive_forward_list.h @@ -629,6 +629,20 @@ namespace etl this->assign(first, last); } +#if ETL_USING_CPP11 + //************************************************************************* + /// Constructor from variadic list of nodes. + //************************************************************************* + template + intrusive_forward_list(link_type& first, TLinks&... links) + { + current_size = 0; + this->start.etl_next = &first; + link_type* last = make_linked_list(current_size, first, static_cast(links)...); + last->etl_next = &this->terminator; + } +#endif + //************************************************************************* /// Gets the beginning of the intrusive_forward_list. //************************************************************************* @@ -1169,6 +1183,41 @@ namespace etl private: +#if ETL_USING_CPP17 + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + TLink* make_linked_list(size_t& count, TLink& first, TLinks&... links) + { + TLink* current = &first; + ++count; + ((current->etl_next = &links, current = &links, ++count), ...); + + return current; + } +#elif ETL_USING_CPP11 + //*************************************************************************** + /// Create a counted linked list from a number of forward_link nodes. + //*************************************************************************** + link_type* make_linked_list(size_t& count, link_type& first) + { + ++count; + return &first; + } + + //*************************************************************************** + /// Create a counted linked list from a number of forward_link nodes. + //*************************************************************************** + template + link_type* make_linked_list(size_t& count, link_type& first, link_type& next, TLinks&... links) + { + ++count; + first.etl_next = &next; + return make_linked_list(count, next, static_cast(links)...); + } +#endif + //************************************************************************* /// Get the next value. //************************************************************************* diff --git a/include/etl/intrusive_list.h b/include/etl/intrusive_list.h index 6bbd906f..a8da751e 100644 --- a/include/etl/intrusive_list.h +++ b/include/etl/intrusive_list.h @@ -685,6 +685,22 @@ namespace etl this->assign(first, last); } +#if ETL_USING_CPP11 + //************************************************************************* + /// Constructor from variadic list of nodes. + //************************************************************************* + template + intrusive_list(link_type& first, TLinks&... links) + { + current_size = 0; + this->terminal_link.etl_next = &first; + link_type* last = make_linked_list(current_size, first, static_cast(links)...); + first.etl_previous = &this->terminal_link; + last->etl_next = &this->terminal_link; + this->terminal_link.etl_previous = last; + } +#endif + //************************************************************************* /// Gets the beginning of the intrusive_list. //************************************************************************* @@ -1194,6 +1210,44 @@ namespace etl private: +#if ETL_USING_CPP17 + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + link_type* make_linked_list(size_t& count, link_type& first, TLinks&... links) + { + TLink* current = &first; + ++count; + ((current->etl_next = &links, static_cast(links).etl_previous = current, current = &links, ++count), ...); + + return current; + } +#elif ETL_USING_CPP11 + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + link_type* make_linked_list(size_t& count, link_type& first) + { + ++count; + + return &first; + } + + //*************************************************************************** + /// Create a linked list from a number of bidirectional_link nodes. + //*************************************************************************** + template + link_type* make_linked_list(size_t& count, link_type& first, link_type& next, TLinks&... links) + { + ++count; + first.etl_next = &next; + next.etl_previous = &first; + + return make_linked_list(count, next, static_cast(links)...); + } +#endif + // Disabled. intrusive_list(const intrusive_list& other); intrusive_list& operator = (const intrusive_list& rhs); diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index 20c8d830..50ac4883 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -183,6 +183,29 @@ namespace CHECK_EQUAL(sorted_data.size(), data0.size()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_variadic_list_single) + { + DataNDC0 data0(sorted_data[0]); + + CHECK(!data0.empty()); + CHECK_EQUAL(1, data0.size()); + CHECK_EQUAL(sorted_data[0], data0.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_variadic_list_multiple) + { + DataNDC0 data0(sorted_data[0], sorted_data[1], sorted_data[2], sorted_data[3], sorted_data[4], + sorted_data[5], sorted_data[6], sorted_data[7], sorted_data[8], sorted_data[9]); + + CHECK(!data0.empty()); + CHECK_EQUAL(10, data0.size()); + + bool are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + CHECK(are_equal); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_empty_begin_end) { diff --git a/test/test_intrusive_list.cpp b/test/test_intrusive_list.cpp index 33aa4467..48081e35 100644 --- a/test/test_intrusive_list.cpp +++ b/test/test_intrusive_list.cpp @@ -196,6 +196,29 @@ namespace CHECK_EQUAL(sorted_data.size(), data0.size()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_variadic_list_single) + { + DataNDC0 data0(sorted_data[0]); + + CHECK(!data0.empty()); + CHECK_EQUAL(1, data0.size()); + CHECK_EQUAL(sorted_data[0], data0.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_variadic_list_multiple) + { + DataNDC0 data0(sorted_data[0], sorted_data[1], sorted_data[2], sorted_data[3], sorted_data[4], + sorted_data[5], sorted_data[6], sorted_data[7], sorted_data[8], sorted_data[9]); + + CHECK(!data0.empty()); + CHECK_EQUAL(10, data0.size()); + + bool are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + CHECK(are_equal); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_empty_begin_end) { From acc0b4bb89f294fc71ca50b3980857a2845b7369 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 1 Mar 2025 13:40:49 +0000 Subject: [PATCH 3/8] Modified create_linked_list functions to not null terminal link pointers --- include/etl/intrusive_links.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/etl/intrusive_links.h b/include/etl/intrusive_links.h index 1ca2479e..9c0e471c 100644 --- a/include/etl/intrusive_links.h +++ b/include/etl/intrusive_links.h @@ -945,8 +945,7 @@ namespace etl { TLink* current = &first; ((current->etl_next = &links, static_cast(links).etl_previous = current, current = &links), ...); - current->etl_next = ETL_NULLPTR; - + return current; } @@ -959,12 +958,10 @@ namespace etl { 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. //*************************************************************************** From 4e4f7ddbb1a23399a3b06b7b745a1261862ee5f5 Mon Sep 17 00:00:00 2001 From: rolandreichweinbmw Date: Sat, 1 Mar 2025 18:57:27 +0100 Subject: [PATCH 4/8] Cleanup (#1039) --- include/etl/bit_stream.h | 6 +++--- include/etl/intrusive_forward_list.h | 6 +----- include/etl/private/delegate_cpp03.h | 10 +++++----- include/etl/vector.h | 1 - 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/include/etl/bit_stream.h b/include/etl/bit_stream.h index 7c5b557e..b58c5882 100644 --- a/include/etl/bit_stream.h +++ b/include/etl/bit_stream.h @@ -236,8 +236,8 @@ namespace etl while (nbits != 0) { unsigned char mask_width = static_cast(etl::min(nbits, bits_available_in_char)); - - typedef typename etl::make_unsigned::type chunk_t; + + typedef typename etl::make_unsigned::type chunk_t; chunk_t chunk = get_chunk(mask_width); nbits -= mask_width; @@ -529,7 +529,7 @@ namespace etl typedef char value_type; typedef value_type* iterator; - typedef const value_type* const_iterator; + typedef const value_type* const_iterator; typedef etl::span callback_parameter_type; typedef etl::delegate callback_type; diff --git a/include/etl/intrusive_forward_list.h b/include/etl/intrusive_forward_list.h index a466337f..929a69d0 100644 --- a/include/etl/intrusive_forward_list.h +++ b/include/etl/intrusive_forward_list.h @@ -351,11 +351,7 @@ namespace etl } p_previous = p_link; - - if (p_link != ETL_NULLPTR) - { - p_link = p_link->link_type::etl_next; - } + p_link = p_link->link_type::etl_next; } return ETL_NULLPTR; diff --git a/include/etl/private/delegate_cpp03.h b/include/etl/private/delegate_cpp03.h index 250fff6f..382e6504 100644 --- a/include/etl/private/delegate_cpp03.h +++ b/include/etl/private/delegate_cpp03.h @@ -66,11 +66,11 @@ namespace etl //*********************************** template struct call_if_impl - { + { etl::optional call_if(TParam param) { - TDelegate& d = static_cast(*this); - + TDelegate& d = static_cast(*this); + etl::optional result; if (d.is_valid()) @@ -88,8 +88,8 @@ namespace etl { bool call_if() { - TDelegate& d = static_cast(*this); - + TDelegate& d = static_cast(*this); + if (d.is_valid()) { d(); diff --git a/include/etl/vector.h b/include/etl/vector.h index 80994bd5..f2c1b646 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -47,7 +47,6 @@ SOFTWARE. #include "functional.h" #include "static_assert.h" #include "placement_new.h" -#include "algorithm.h" #include "initializer_list.h" #include From 2746cf4060d5821feded821fcfc335ff978e9042 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 2 Mar 2025 08:30:54 +0000 Subject: [PATCH 5/8] Added variadic contruction Added erase from pointer to node --- include/etl/intrusive_forward_list.h | 75 +++++++++++++++++++++---- test/test_intrusive_forward_list.cpp | 84 ++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 11 deletions(-) diff --git a/include/etl/intrusive_forward_list.h b/include/etl/intrusive_forward_list.h index 84d0aa94..566c0e41 100644 --- a/include/etl/intrusive_forward_list.h +++ b/include/etl/intrusive_forward_list.h @@ -338,24 +338,20 @@ namespace etl /// Tests if the link is in this list. /// Returns the previous link to it, if found, otherwise ETL_NULLPTR. //************************************************************************* - link_type* is_link_in_list(link_type& search_link) + link_type* is_link_in_list(const link_type* search_link) { link_type* p_link = start.etl_next; link_type* p_previous = &start; while (p_link != ETL_NULLPTR) { - if (&search_link == p_link) + if (search_link == p_link) { return p_previous; } p_previous = p_link; - - if (p_link != ETL_NULLPTR) - { - p_link = p_link->link_type::etl_next; - } + p_link = p_link->link_type::etl_next; } return ETL_NULLPTR; @@ -366,7 +362,7 @@ namespace etl /// Returns ETL_NULLPTR if the link was not in this list. /// Returns the next //************************************************************************* - link_type* remove_link(link_type& link) + link_type* remove_link(link_type* link) { link_type* result = ETL_NULLPTR; @@ -374,7 +370,7 @@ namespace etl if (p_previous != ETL_NULLPTR) { - link_type* p_next = link.etl_next; + link_type* p_next = link->etl_next; disconnect_link_after(*p_previous); @@ -629,6 +625,20 @@ namespace etl this->assign(first, last); } +#if ETL_USING_CPP11 + //************************************************************************* + /// Constructor from variadic list of nodes. + //************************************************************************* + template + intrusive_forward_list(link_type& first, TLinks&... links) + { + this->current_size = 0; + this->start.etl_next = &first; + link_type* last = make_linked_list(this->current_size, first, static_cast(links)...); + last->etl_next = &this->terminator; + } +#endif + //************************************************************************* /// Gets the beginning of the intrusive_forward_list. //************************************************************************* @@ -787,9 +797,17 @@ namespace etl //************************************************************************* /// Erases the specified node. //************************************************************************* - node_type* erase(node_type& node) + node_type* erase(const node_type& node) { - return static_cast(this->remove_link(node)); + return static_cast(this->remove_link(const_cast(&node))); + } + + //************************************************************************* + /// Erases the specified node. + //************************************************************************* + node_type* erase(const node_type* p_node) + { + return static_cast(this->remove_link(const_cast(p_node))); } //************************************************************************* @@ -1169,6 +1187,41 @@ namespace etl private: +#if ETL_USING_CPP17 + //*************************************************************************** + /// Create a linked list from a number of forward_link nodes. + //*************************************************************************** + template + link_type* make_linked_list(size_t& count, link_type& first, TLinks&... links) + { + link_type* current = &first; + ++count; + ((current->etl_next = &links, current = &links, ++count), ...); + + return current; + } +#elif ETL_USING_CPP11 + //*************************************************************************** + /// Create a counted linked list from a number of forward_link nodes. + //*************************************************************************** + link_type* make_linked_list(size_t& count, link_type& first) + { + ++count; + return &first; + } + + //*************************************************************************** + /// Create a counted linked list from a number of forward_link nodes. + //*************************************************************************** + template + link_type* make_linked_list(size_t& count, link_type& first, link_type& next, TLinks&... links) + { + ++count; + first.etl_next = &next; + return make_linked_list(count, next, static_cast(links)...); + } +#endif + //************************************************************************* /// Get the next value. //************************************************************************* diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index 20c8d830..ca1ce413 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -699,6 +699,90 @@ namespace CHECK(ETL_NULLPTR == p_next5); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_by_node_pointer) + { + bool are_equal; + + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC1 data1(sorted_data.begin(), sorted_data.end()); + + // Move to the third value and erase. + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 3); + + DataNDC0::iterator i_data = data0.begin(); + std::advance(i_data, 3); + + ItemNDCNode& node1 = *i_data; + ItemNDCNode* p_next1 = static_cast(node1.FirstLink::get_next()); + ItemNDCNode* p_node1 = data0.erase(&node1); + i_compare_data = compare_data.erase(i_compare_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(p_next1, p_node1); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Move to the first value and erase. + i_compare_data = compare_data.begin(); + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data0.begin(); + + ItemNDCNode& node2 = *i_data; + ItemNDCNode* p_next2 = static_cast(node2.FirstLink::get_next()); + ItemNDCNode* p_node2 = data0.erase(&node2); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(p_next2, p_node2); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Move to the last value and erase. + i_compare_data = compare_data.begin(); + std::advance(i_compare_data, compare_data.size() - 1); + + i_data = data0.begin(); + std::advance(i_data, data0.size() - 1); + + ItemNDCNode& node3 = *i_data; + ItemNDCNode* p_next3 = static_cast(node3.FirstLink::get_next()); + ItemNDCNode* p_node3 = data0.erase(&node3); + i_compare_data = compare_data.erase(i_compare_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_NOT_EQUAL(p_next3, p_node3); + CHECK(ETL_NULLPTR == p_node3); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Try removing a node that isn't in the list. + auto node_not_in_list = ItemNDCNode("9"); + + ItemNDCNode* p_node4 = data0.erase(&node_not_in_list); + CHECK(p_node4 == ETL_NULLPTR); + + // Try removing the only node in the list. + while (data0.size() > 1) + { + data0.pop_front(); + } + + ItemNDCNode* p_node5 = &data0.front(); + + ItemNDCNode* p_next5 = static_cast(p_node5->FirstLink::get_next()); + p_next5 = data0.erase(p_node5); + CHECK(ETL_NULLPTR == p_next5); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_after_range) { From 68dac39104dab737fec1ba7850455163bfca215d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 2 Mar 2025 08:31:14 +0000 Subject: [PATCH 6/8] Added erase from pointer to node --- include/etl/intrusive_list.h | 20 ++++++--- test/test_intrusive_list.cpp | 84 ++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/include/etl/intrusive_list.h b/include/etl/intrusive_list.h index 6bbd906f..84453b2e 100644 --- a/include/etl/intrusive_list.h +++ b/include/etl/intrusive_list.h @@ -379,13 +379,13 @@ namespace etl //************************************************************************* /// Tests if the link is in this list. //************************************************************************* - bool is_link_in_list(link_type& search_link) const + bool is_link_in_list(const link_type* search_link) const { link_type* p_link = terminal_link.link_type::etl_next; while (p_link != &terminal_link) { - if (&search_link == p_link) + if (search_link == p_link) { return true; } @@ -400,13 +400,13 @@ namespace etl /// Remove the specified node from the list. /// Returns ETL_NULLPTR if the link was not in this list or was the last in the list. //************************************************************************* - link_type* remove_link(link_type& link) + link_type* remove_link(link_type* link) { link_type* result = ETL_NULLPTR; if (is_link_in_list(link)) { - link_type* p_next = link.etl_next; + link_type* p_next = link->etl_next; disconnect_link(link); @@ -843,9 +843,17 @@ namespace etl //************************************************************************* /// Erases the specified node. //************************************************************************* - node_type* erase(node_type& node) + node_type* erase(const node_type& node) { - return static_cast(this->remove_link(node)); + return static_cast(this->remove_link(const_cast(&node))); + } + + //************************************************************************* + /// Erases the specified node. + //************************************************************************* + node_type* erase(const node_type* p_node) + { + return static_cast(this->remove_link(const_cast(p_node))); } //************************************************************************* diff --git a/test/test_intrusive_list.cpp b/test/test_intrusive_list.cpp index 33aa4467..ab13d2be 100644 --- a/test/test_intrusive_list.cpp +++ b/test/test_intrusive_list.cpp @@ -840,6 +840,90 @@ namespace CHECK(ETL_NULLPTR == p_next5); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single_by_node_pointer) + { + bool are_equal; + + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC1 data1(sorted_data.begin(), sorted_data.end()); + + // Move to the third value and erase. + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 3); + + DataNDC0::iterator i_data = data0.begin(); + std::advance(i_data, 3); + + ItemNDCNode& node1 = *i_data; + ItemNDCNode* p_next1 = static_cast(node1.FirstLink::get_next()); + ItemNDCNode* p_node1 = data0.erase(&node1); + i_compare_data = compare_data.erase(i_compare_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(p_next1, p_node1); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Move to the first value and erase. + i_compare_data = compare_data.begin(); + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data0.begin(); + + ItemNDCNode& node2 = *i_data; + ItemNDCNode* p_next2 = static_cast(node2.FirstLink::get_next()); + ItemNDCNode* p_node2 = data0.erase(&node2); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(p_next2, p_node2); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Move to the last value and erase. + i_compare_data = compare_data.begin(); + std::advance(i_compare_data, compare_data.size() - 1); + + i_data = data0.begin(); + std::advance(i_data, data0.size() - 1); + + ItemNDCNode& node3 = *i_data; + ItemNDCNode* p_next3 = static_cast(node3.FirstLink::get_next()); + ItemNDCNode* p_node3 = data0.erase(&node3); + i_compare_data = compare_data.erase(i_compare_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_NOT_EQUAL(p_next3, p_node3); + CHECK(ETL_NULLPTR == p_node3); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), size_t(std::distance(data0.begin(), data0.end()))); + + // Try removing a node that isn't in the list. + auto node_not_in_list = ItemNDCNode("9"); + + ItemNDCNode* p_node4 = data0.erase(&node_not_in_list); + CHECK(p_node4 == ETL_NULLPTR); + + // Try removing the only node in the list. + while (data0.size() > 1) + { + data0.pop_back(); + } + + ItemNDCNode* p_node5 = &data0.front(); + + ItemNDCNode* p_next5 = static_cast(p_node5->FirstLink::get_next()); + p_next5 = data0.erase(p_node5); + CHECK(ETL_NULLPTR == p_next5); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_range) { From 6459ce7b5f3ba998165fa5ae1a3f7fa7635dcb17 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 2 Mar 2025 09:43:31 +0000 Subject: [PATCH 7/8] Improved implementation of etl::is_base_of_all --- .../etl/generators/type_traits_generator.h | 16 ++++++++-------- include/etl/type_traits.h | 19 ++++++++++--------- test/test_type_traits.cpp | 2 ++ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index e55d1221..bc5edbea 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -1405,19 +1405,19 @@ typedef integral_constant true_type; //*************************************************************************** /// Template to determine if a type is a base of all types in a specified list. ///\ingroup types - template - struct is_base_of_all + template + struct is_base_of_all; + + template + struct is_base_of_all : etl::true_type { - static const bool value = etl::is_base_of::value && - etl::is_base_of_all::value; }; - template - struct is_base_of_all + template + struct is_base_of_all : etl::integral_constant::value && + etl::is_base_of_all::value> { - static const bool value = etl::is_base_of::value; }; -#endif #if ETL_USING_CPP17 template diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 327f164b..b75118ed 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -1398,23 +1398,24 @@ typedef integral_constant true_type; //*************************************************************************** /// Template to determine if a type is a base of all types in a specified list. ///\ingroup types - template - struct is_base_of_all + template + struct is_base_of_all; + + template + struct is_base_of_all : etl::true_type { - static const bool value = etl::is_base_of::value && - etl::is_base_of_all::value; }; - template - struct is_base_of_all + template + struct is_base_of_all : etl::integral_constant::value && + etl::is_base_of_all::value> { - static const bool value = etl::is_base_of::value; }; #endif #if ETL_USING_CPP17 - template - inline constexpr bool is_base_of_all_v = etl::is_base_of_all::value; + template + inline constexpr bool is_base_of_all_v = etl::is_base_of_all::value; #endif #if ETL_USING_CPP11 diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index 4316a697..37d620cd 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -1320,9 +1320,11 @@ namespace struct D4 {}; #if ETL_USING_CPP17 + CHECK_TRUE(bool(etl::is_base_of_all_v)); CHECK_TRUE(bool(etl::is_base_of_all_v)); CHECK_FALSE(bool(etl::is_base_of_all_v)); #else + CHECK_TRUE(bool(etl::is_base_of_all::value)); CHECK_TRUE(bool(etl::is_base_of_all::value)); CHECK_FALSE(bool(etl::is_base_of_all::value)); #endif From abe765a9cfcca5b037e1a87842b45fcd75e7bc44 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 2 Mar 2025 10:20:44 +0000 Subject: [PATCH 8/8] Added static assert for variadic constructor Fixed missing this-> prefix for current_size --- include/etl/intrusive_forward_list.h | 2 ++ include/etl/intrusive_list.h | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/etl/intrusive_forward_list.h b/include/etl/intrusive_forward_list.h index 566c0e41..12e3c3d3 100644 --- a/include/etl/intrusive_forward_list.h +++ b/include/etl/intrusive_forward_list.h @@ -632,6 +632,8 @@ namespace etl template intrusive_forward_list(link_type& first, TLinks&... links) { + ETL_STATIC_ASSERT((etl::is_base_of_all::value), "Mixed link types"); + this->current_size = 0; this->start.etl_next = &first; link_type* last = make_linked_list(this->current_size, first, static_cast(links)...); diff --git a/include/etl/intrusive_list.h b/include/etl/intrusive_list.h index 30cf7d50..49bfea05 100644 --- a/include/etl/intrusive_list.h +++ b/include/etl/intrusive_list.h @@ -692,9 +692,11 @@ namespace etl template intrusive_list(link_type& first, TLinks&... links) { - current_size = 0; + ETL_STATIC_ASSERT((etl::is_base_of_all::value), "Mixed link types"); + + this->current_size = 0; this->terminal_link.etl_next = &first; - link_type* last = make_linked_list(current_size, first, static_cast(links)...); + link_type* last = make_linked_list(this->current_size, first, static_cast(links)...); first.etl_previous = &this->terminal_link; last->etl_next = &this->terminal_link; this->terminal_link.etl_previous = last;