Added etl::create_linked_list and etl::detach_linked_list to the intrusive link utilities

This commit is contained in:
John Wellbelove 2025-02-27 10:02:56 +00:00
parent a75d1d2a30
commit 44a0d7c3c5
2 changed files with 533 additions and 0 deletions

View File

@ -404,6 +404,112 @@ namespace etl
}
}
#if ETL_USING_CPP17
//***************************************************************************
/// Create a linked list from a number of forward_link nodes.
//***************************************************************************
template <typename TLink, typename... TLinks>
typename etl::enable_if<etl::is_forward_link<TLink>::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 TLink, typename... TLinks>
typename etl::enable_if<etl::is_forward_link<TLink>::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 TLink>
typename etl::enable_if<etl::is_forward_link<TLink>::value, TLink*>::type
create_linked_list(TLink& first)
{
return &first;
}
//***************************************************************************
/// Create a linked list from a number of forward_link nodes.
//***************************************************************************
template <typename TLink, typename... TLinks>
typename etl::enable_if<etl::is_forward_link<TLink>::value, TLink*>::type
create_linked_list(TLink& first, TLink& next, TLinks&... links)
{
first.etl_next = &next;
return create_linked_list(next, static_cast<TLink&>(links)...);
}
//***************************************************************************
/// Create a linked list from a number of forward_link nodes.
//***************************************************************************
template <typename TLink>
typename etl::enable_if<etl::is_forward_link<TLink>::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 TLink, typename... TLinks>
typename etl::enable_if<etl::is_forward_link<TLink>::value, TLink*>::type
create_linked_list(TLink* first, TLink* next, TLinks*... links)
{
if (first != ETL_NULLPTR)
{
return create_linked_list(*first, *next, static_cast<TLink&>(*links)...);
}
else
{
return ETL_NULLPTR;
}
}
#endif
//***************************************************************************
template <typename TLink>
typename etl::enable_if<etl::is_forward_link<TLink>::value, void>::type
detach_linked_list(TLink& first)
{
link_clear_range(first);
}
//***************************************************************************
template <typename TLink>
typename etl::enable_if<etl::is_forward_link<TLink>::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 TLink, typename... TLinks>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, TLink*>::type
create_linked_list(TLink& first, TLinks&... links)
{
TLink* current = &first;
((current->etl_next = &links, static_cast<TLink&>(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 TLink, typename... TLinks>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, TLink*>::type
create_linked_list(TLink* first, TLinks*... links)
{
TLink* current = first;
((current->etl_next = links, static_cast<TLink*>(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 TLink>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, TLink*>::type
create_linked_list(TLink& first)
{
return &first;
}
//***************************************************************************
/// Create a linked list from a number of bidirectional_link nodes.
//***************************************************************************
template <typename TLink, typename... TLinks>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::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<TLink&>(links)...);
}
//***************************************************************************
/// Create a linked list from a number of bidirectional_link nodes.
//***************************************************************************
template <typename TLink, typename... TLinks>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, TLink*>::type
create_linked_list(TLink* first, TLink* next, TLinks*... links)
{
if (first != ETL_NULLPTR)
{
return create_linked_list(*first, *next, static_cast<TLink&>(*links)...);
}
else
{
return ETL_NULLPTR;
}
}
#endif
//***************************************************************************
template <typename TLink>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, void>::type
detach_linked_list(TLink& first)
{
link_clear_range(first);
}
//***************************************************************************
template <typename TLink>
typename etl::enable_if<etl::is_bidirectional_link<TLink>::value, void>::type
detach_linked_list(TLink* first)
{
if (first != ETL_NULLPTR)
{
detach_linked_list(*first);
}
}
//***************************************************************************
/// A binary tree link.
//***************************************************************************

View File

@ -32,6 +32,8 @@ SOFTWARE.
#include "etl/intrusive_links.h"
#include <vector>
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<FLink0>(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<FLink1>(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<FData*>(data0.FLink0::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(pdata->FLink0::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->FLink0::etl_next);
CHECK_EQUAL(3, pdata->value);
pdata = static_cast<FData*>(data3.FLink1::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->FLink1::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(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<FLink0>(*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<FLink0>(&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<FLink1>(&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<FData*>(data0.FLink0::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(pdata->FLink0::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->FLink0::etl_next);
CHECK_EQUAL(3, pdata->value);
pdata = static_cast<FData*>(data3.FLink1::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->FLink1::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(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<FLink0>(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<FLink0>(data0, data1, data2, data3);
etl::create_linked_list<FLink1>(data3, data2, data1, data0);
etl::detach_linked_list<FLink0>(data0);
etl::detach_linked_list<FLink1>(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<FLink0>(data0, data1, data2, data3);
etl::create_linked_list<FLink1>(data3, data2, data1, data0);
etl::detach_linked_list<FLink0>(&data0);
etl::detach_linked_list<FLink1>(&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<BLink0>(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<BLink1>(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<BData*>(data0.BLink0::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(pdata->BLink0::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->BLink0::etl_next);
CHECK_EQUAL(3, pdata->value);
pdata = static_cast<BData*>(data3.BLink1::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->BLink1::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(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<BLink0>(*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<BLink0>(&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<BLink1>(&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<BData*>(data0.BLink0::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(pdata->BLink0::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->BLink0::etl_next);
CHECK_EQUAL(3, pdata->value);
pdata = static_cast<BData*>(data3.BLink1::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->BLink1::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(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<BLink0>(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<BLink0>(data0, data1, data2, data3);
etl::create_linked_list<BLink1>(data3, data2, data1, data0);
etl::detach_linked_list<BLink0>(data0);
etl::detach_linked_list<BLink1>(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<BLink0>(data0, data1, data2, data3);
etl::create_linked_list<BLink1>(data3, data2, data1, data0);
etl::detach_linked_list<BLink0>(&data0);
etl::detach_linked_list<BLink1>(&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)
{