From 189cde576fdc667089c8e82601c7af042610ca51 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 24 Jan 2016 17:08:14 +0000 Subject: [PATCH 1/9] More additions to links and tests --- intrusive_links.h | 280 +++++++++++++++++- test/test_intrusive_links.cpp | 524 ++++++++++++++++++++++++++++++---- 2 files changed, 744 insertions(+), 60 deletions(-) diff --git a/intrusive_links.h b/intrusive_links.h index e3101277..6c373eae 100644 --- a/intrusive_links.h +++ b/intrusive_links.h @@ -32,6 +32,7 @@ SOFTWARE. #define __ETL_INTRUSIVE_LINKS__ #include "nullptr.h" +#include "type_traits.h" namespace etl { @@ -55,20 +56,95 @@ namespace etl ID = ID_ }; + void clear() + { + etl_next = nullptr; + } + forward_link* etl_next; }; + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + } + + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link(TLink* lhs, TLink* rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = rhs; + } + } + + // Reference, Pointer + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + } + + // Pointer, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink* lhs, TLink& rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = &rhs; + } + } + + // Reference + template + typename etl::enable_if >::value, void>::type + unlink_after(TLink& node) + { + if (node.etl_next != nullptr) + { + node.etl_next = node.etl_next->etl_next; + } + } + + // Pointer + template + typename etl::enable_if >::value, void>::type + unlink_after(TLink* node) + { + if (node != nullptr) + { + if (node->etl_next != nullptr) + { + node->etl_next = node.etl_next->etl_next; + } + } + } + //*************************************************************************** /// A bidirectional link. //*************************************************************************** - template + template struct bidirectional_link { enum { - ID = ID_, + ID = ID_, + OPTION = OPTION_ }; + void clear() + { + etl_previous = nullptr; + etl_next = nullptr; + } + bidirectional_link* etl_previous; bidirectional_link* etl_next; }; @@ -80,7 +156,8 @@ namespace etl { enum { - ID = ID_ + ID = ID_, + OPTION = etl::link_option::AUTO_UNLINK }; ~bidirectional_link() @@ -98,10 +175,102 @@ namespace etl } } + void clear() + { + etl_previous = nullptr; + etl_next = nullptr; + } + bidirectional_link* etl_previous; bidirectional_link* etl_next; }; + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + rhs.etl_previous = &lhs; + } + + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link(TLink* lhs, TLink* rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = rhs; + } + + if (rhs != nullptr) + { + rhs->etl_previous = lhs; + } + } + + // Reference, Pointer + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + + if (rhs != nullptr) + { + rhs->etl_previous = &lhs; + } + } + + // Pointer, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink* lhs, TLink& rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = &rhs; + } + + rhs.etl_previous = lhs; + } + + // Reference + template + typename etl::enable_if >::value, void>::type + unlink(TLink& node) + { + if (node.etl_next != nullptr) + { + node.etl_next->etl_previous = node.etl_previous; + } + + if (node.etl_previous != nullptr) + { + node.etl_previous->etl_next = node.etl_next; + } + } + + // Pointer + template + typename etl::enable_if >::value, void>::type + unlink(TLink* node) + { + if (node != nullptr) + { + if (node->etl_next != nullptr) + { + node->etl_next->etl_previous = node->etl_previous; + } + + if (node->etl_previous != nullptr) + { + node->etl_previous->etl_next = node->etl_next; + } + } + } + //*************************************************************************** /// A tree link. //*************************************************************************** @@ -113,10 +282,115 @@ namespace etl ID = ID_ }; + void clear() + { + etl_parent = nullptr; + etl_left = nullptr; + etl_right = nullptr; + } + tree_link* etl_parent; tree_link* etl_left; tree_link* etl_right; }; + + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_left(TLink& parent, TLink& leaf) + { + parent.etl_left = &leaf; + leaf.etl_parent = &parent; + } + + template + typename etl::enable_if >::value, void>::type + link_right(TLink& parent, TLink& leaf) + { + parent.etl_right = &leaf; + leaf.etl_parent = &parent; + } + + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link_left(TLink* parent, TLink* leaf) + { + if (parent != nullptr) + { + parent->etl_left = leaf; + } + + if (leaf != nullptr) + { + leaf->etl_parent = parent; + } + } + + template + typename etl::enable_if >::value, void>::type + link_right(TLink* parent, TLink* leaf) + { + if (parent != nullptr) + { + parent->etl_right = leaf; + } + + if (leaf != nullptr) + { + leaf->etl_parent = parent; + } + } + + // Reference, Pointer + template + typename etl::enable_if >::value, void>::type + link_left(TLink& parent, TLink* leaf) + { + parent.etl_left = leaf; + + if (leaf != nullptr) + { + leaf->etl_parent = &parent; + } + } + + template + typename etl::enable_if >::value, void>::type + link_right(TLink& parent, TLink* leaf) + { + parent.etl_right = leaf; + + if (leaf != nullptr) + { + leaf->etl_parent = &parent; + } + } + + // Pointer, Reference + template + typename etl::enable_if >::value, void>::type + link_left(TLink* parent, TLink& leaf) + { + if (parent != nullptr) + { + parent->etl_left = &leaf; + } + + leaf.etl_parent = parent; + } + + template + typename etl::enable_if >::value, void>::type + link_right(TLink* parent, TLink& leaf) + { + if (parent != nullptr) + { + parent->etl_right = &leaf; + } + + leaf.etl_parent = parent; + } } #endif diff --git a/test/test_intrusive_links.cpp b/test/test_intrusive_links.cpp index 1b7cc0c9..2c82bce0 100644 --- a/test/test_intrusive_links.cpp +++ b/test/test_intrusive_links.cpp @@ -36,12 +36,14 @@ SOFTWARE. namespace { //******************************************************* - typedef etl::bidirectional_link<0, etl::link_option::AUTO_UNLINK> FirstLink; - typedef etl::bidirectional_link<1> SecondLink; + //Forward + //******************************************************* + typedef etl::forward_link<0> FirstFLink; + typedef etl::forward_link<1> SecondFLink; - struct Data : public FirstLink, public SecondLink + struct FData : public FirstFLink, public SecondFLink { - Data(int value) + FData(int value) : value(value) { } @@ -50,84 +52,492 @@ namespace }; //******************************************************* - bool operator ==(const Data& lhs, const Data& rhs) - { - return lhs.value == rhs.value; - } + // Bidirectional + //******************************************************* + typedef etl::bidirectional_link<0, etl::link_option::AUTO_UNLINK> FirstBLinkAuto; + typedef etl::bidirectional_link<0> FirstBLink; + typedef etl::bidirectional_link<1> SecondBLink; - bool operator !=(const Data& lhs, const Data& rhs) + struct BData : public FirstBLink, public SecondBLink { - return !(lhs == rhs); - } + BData(int value) + : value(value) + { + } + + int value; + }; + + struct BDataAuto : public FirstBLinkAuto, public SecondBLink + { + BDataAuto(int value) + : value(value) + { + } + + int value; + }; //******************************************************* - template - void join(TLink* lhs, TLink* rhs) + // Tree + //******************************************************* + typedef etl::tree_link<0> FirstTLink; + typedef etl::tree_link<1> SecondTLink; + + struct TData : public FirstTLink, public SecondTLink { - if ((lhs == nullptr) && (rhs != nullptr)) + TData(int value) + : value(value) { - rhs->etl_previous = nullptr; } - else if ((lhs != nullptr) && (rhs == nullptr)) - { - lhs->etl_next = nullptr; - } - else if ((lhs != nullptr) && (rhs != nullptr)) - { - lhs->etl_next = rhs; - rhs->etl_previous = lhs; - } - } + + int value; + }; SUITE(test_forward_list) - { + { //************************************************************************* - TEST(test_bidirectional_link) + TEST(test_link_forward_link) { - // FirstLink is auto-unlink, SecondLink is not. + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); - Data* data0 = new Data(0); - Data* data1 = new Data(1); - Data* data2 = new Data(2); - Data* data3 = new Data(3); + data0.FirstFLink::clear(); + etl::link(data0, data1); + CHECK(data0.FirstFLink::etl_next == &data1); - join(nullptr, data0); - join(data0, data1); - join(data1, data2); - join(data2, data3); - join(data3, nullptr); + data0.FirstFLink::clear(); + etl::link(&data0, data1); + CHECK(data0.FirstFLink::etl_next == &data1); - join(nullptr, data0); - join(data0, data1); - join(data1, data2); - join(data2, data3); - join(data3, nullptr); + data0.FirstFLink::clear(); + etl::link(data0, &data1); + CHECK(data0.FirstFLink::etl_next == &data1); + + data0.FirstFLink::clear(); + etl::link(&data0, &data1); + CHECK(data0.FirstFLink::etl_next == &data1); + + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + CHECK(data1.FirstFLink::etl_next == &data2); + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondFLink::etl_next == &data2); + CHECK(data2.SecondFLink::etl_next == &data1); + CHECK(data1.SecondFLink::etl_next == &data0); + CHECK(data0.SecondFLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_unlink_after_forward_link) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + etl::unlink_after(data1); + data2.FirstFLink::clear(); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data3); + CHECK(data2.FirstFLink::etl_next == nullptr); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondFLink::etl_next == &data2); + CHECK(data2.SecondFLink::etl_next == &data1); + CHECK(data1.SecondFLink::etl_next == &data0); + CHECK(data0.SecondFLink::etl_next == nullptr); + + etl::unlink_after(data2); + data1.SecondFLink::clear(); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondFLink::etl_next == &data2); + CHECK(data2.SecondFLink::etl_next == &data0); + CHECK(data1.SecondFLink::etl_next == nullptr); + CHECK(data0.SecondFLink::etl_next == nullptr); + + etl::unlink_after(data3); + etl::unlink_after(data0); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondFLink::etl_next == &data2); + CHECK(data2.SecondFLink::etl_next == &data0); + CHECK(data0.SecondFLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_self_link_forward_link) + { + FData data0(0); + + etl::link(data0, data0); + + CHECK(data0.FirstFLink::etl_next == &data0); + + etl::unlink_after(data0); + + CHECK(data0.FirstFLink::etl_next == &data0); + } + + //************************************************************************* + TEST(test_link_bidirectional_link) + { + // FirstBLinkAuto is auto-unlink, SecondBLink is not. + + BDataAuto* data0 = new BDataAuto(0); + BDataAuto* data1 = new BDataAuto(1); + BDataAuto* data2 = new BDataAuto(2); + BDataAuto* data3 = new BDataAuto(3); + + etl::link(nullptr, data0); + + data1->FirstBLinkAuto::clear(); + etl::link(*data0, *data1); + CHECK(data0->FirstBLinkAuto::etl_next == data1); + CHECK(data1->FirstBLinkAuto::etl_previous == data0); + + data1->FirstBLinkAuto::clear(); + etl::link(*data0, data1); + CHECK(data0->FirstBLinkAuto::etl_next == data1); + CHECK(data1->FirstBLinkAuto::etl_previous == data0); + + data1->FirstBLinkAuto::clear(); + etl::link(data0, *data1); + CHECK(data0->FirstBLinkAuto::etl_next == data1); + CHECK(data1->FirstBLinkAuto::etl_previous == data0); + + data1->FirstBLinkAuto::clear(); + etl::link(data0, data1); + CHECK(data0->FirstBLinkAuto::etl_next == data1); + CHECK(data1->FirstBLinkAuto::etl_previous == data0); + + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + CHECK(data0->FirstBLinkAuto::etl_previous == nullptr); + CHECK(data1->FirstBLinkAuto::etl_next == data2); + CHECK(data2->FirstBLinkAuto::etl_previous == data1); + CHECK(data2->FirstBLinkAuto::etl_next == data3); + CHECK(data3->FirstBLinkAuto::etl_previous == data2); + CHECK(data3->FirstBLinkAuto::etl_next == nullptr); + + etl::link(nullptr, data3); + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + CHECK(data3->SecondBLink::etl_previous == nullptr); + CHECK(data3->SecondBLink::etl_next == data2); + CHECK(data2->SecondBLink::etl_previous == data3); + CHECK(data2->SecondBLink::etl_next == data1); + CHECK(data1->SecondBLink::etl_previous == data2); + CHECK(data1->SecondBLink::etl_next == data0); + CHECK(data0->SecondBLink::etl_previous == data1); + CHECK(data0->SecondBLink::etl_next == nullptr); delete data1; - CHECK(data0->FirstLink::etl_next == data2); - CHECK(data2->FirstLink::etl_previous == data0); + CHECK(data0->FirstBLinkAuto::etl_next == data2); + CHECK(data2->FirstBLinkAuto::etl_previous == data0); - CHECK(data0->SecondLink::etl_next != data2); - CHECK(data0->SecondLink::etl_next != nullptr); - CHECK(data2->SecondLink::etl_previous != data0); - CHECK(data2->SecondLink::etl_previous != nullptr); + CHECK(data3->SecondBLink::etl_previous == nullptr); + CHECK(data3->SecondBLink::etl_next == data2); + CHECK(data2->SecondBLink::etl_previous == data3); + CHECK(data2->SecondBLink::etl_next != nullptr); + CHECK(data0->SecondBLink::etl_previous != nullptr); + CHECK(data0->SecondBLink::etl_next == nullptr); delete data0; - CHECK(data2->FirstLink::etl_next == data3); - CHECK(data2->FirstLink::etl_previous == nullptr); - CHECK(data3->FirstLink::etl_previous == data2); + CHECK(data2->FirstBLinkAuto::etl_next == data3); + CHECK(data2->FirstBLinkAuto::etl_previous == nullptr); + CHECK(data3->FirstBLinkAuto::etl_previous == data2); - CHECK(data2->SecondLink::etl_next == data3); - CHECK(data3->SecondLink::etl_previous != nullptr); + CHECK(data3->SecondBLink::etl_previous == nullptr); + CHECK(data3->SecondBLink::etl_next == data2); + CHECK(data2->SecondBLink::etl_previous == data3); + CHECK(data2->SecondBLink::etl_next != nullptr); delete data3; - CHECK(data2->FirstLink::etl_next == nullptr); - CHECK(data2->FirstLink::etl_previous == nullptr); + CHECK(data2->FirstBLinkAuto::etl_next == nullptr); + CHECK(data2->FirstBLinkAuto::etl_previous == nullptr); - CHECK(data2->SecondLink::etl_next != nullptr); - CHECK(data2->SecondLink::etl_previous != nullptr); + CHECK(data2->SecondBLink::etl_next != nullptr); + CHECK(data2->SecondBLink::etl_previous != nullptr); delete data2; } + + //************************************************************************* + TEST(test_unlink_bidirectional_link) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + etl::link(nullptr, data0); + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + etl::link(nullptr, data3); + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + etl::unlink(data1); + data1.FirstBLink::clear(); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data2); + CHECK(data1.FirstBLink::etl_previous == nullptr); + CHECK(data1.FirstBLink::etl_next == nullptr); + CHECK(data2.FirstBLink::etl_previous == &data0); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == &data2); + CHECK(data2.SecondBLink::etl_previous == &data3); + CHECK(data2.SecondBLink::etl_next == &data1); + CHECK(data1.SecondBLink::etl_previous == &data2); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + + etl::unlink(data2); + data2.SecondBLink::clear(); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data2); + CHECK(data1.FirstBLink::etl_previous == nullptr); + CHECK(data1.FirstBLink::etl_next == nullptr); + CHECK(data2.FirstBLink::etl_previous == &data0); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == &data1); + CHECK(data2.SecondBLink::etl_previous == nullptr); + CHECK(data2.SecondBLink::etl_next == nullptr); + CHECK(data1.SecondBLink::etl_previous == &data3); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + + etl::unlink(data0); + data0.FirstBLink::clear(); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == nullptr); + CHECK(data1.FirstBLink::etl_previous == nullptr); + CHECK(data1.FirstBLink::etl_next == nullptr); + CHECK(data2.FirstBLink::etl_previous == nullptr); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == &data1); + CHECK(data2.SecondBLink::etl_previous == nullptr); + CHECK(data2.SecondBLink::etl_next == nullptr); + CHECK(data1.SecondBLink::etl_previous == &data3); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + + etl::unlink(data3); + data3.SecondBLink::clear(); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == nullptr); + CHECK(data1.FirstBLink::etl_previous == nullptr); + CHECK(data1.FirstBLink::etl_next == nullptr); + CHECK(data2.FirstBLink::etl_previous == nullptr); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == nullptr); + CHECK(data2.SecondBLink::etl_previous == nullptr); + CHECK(data2.SecondBLink::etl_next == nullptr); + CHECK(data1.SecondBLink::etl_previous == nullptr); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_self_link_bidirectional_link) + { + BData data0(0); + + etl::link(data0, data0); + + CHECK(data0.FirstBLink::etl_previous == &data0); + CHECK(data0.FirstBLink::etl_next == &data0); + + etl::unlink(data0); + + CHECK(data0.FirstBLink::etl_previous == &data0); + CHECK(data0.FirstBLink::etl_next == &data0); + } + + //************************************************************************* + TEST(test_tree_link) + { + TData data0(0); + TData data1(1); + TData data2(2); + TData data3(3); + TData data4(4); + TData data5(5); + TData data6(6); + + // First link + data0.FirstTLink::clear(); + etl::link_left(data0, data1); + etl::link_right(data0, data2); + CHECK(data0.FirstTLink::etl_left == &data1); + CHECK(data0.FirstTLink::etl_right == &data2); + CHECK(data1.FirstTLink::etl_parent == &data0); + CHECK(data2.FirstTLink::etl_parent == &data0); + + data0.FirstTLink::clear(); + etl::link_left(&data0, data1); + etl::link_right(&data0, data2); + CHECK(data0.FirstTLink::etl_left == &data1); + CHECK(data0.FirstTLink::etl_right == &data2); + CHECK(data1.FirstTLink::etl_parent == &data0); + CHECK(data2.FirstTLink::etl_parent == &data0); + + data0.FirstTLink::clear(); + etl::link_left(data0, &data1); + etl::link_right(data0, &data2); + CHECK(data0.FirstTLink::etl_left == &data1); + CHECK(data0.FirstTLink::etl_right == &data2); + CHECK(data1.FirstTLink::etl_parent == &data0); + CHECK(data2.FirstTLink::etl_parent == &data0); + + data0.FirstTLink::clear(); + etl::link_left(&data0, &data1); + etl::link_right(&data0, &data2); + + etl::link_left(data1, data3); + etl::link_right(data1, data4); + etl::link_left(data3, nullptr); + etl::link_right(data3, nullptr); + etl::link_left(data4, nullptr); + etl::link_right(data4, nullptr); + + etl::link_left(data2, data5); + etl::link_right(data2, data6); + etl::link_left(data5, nullptr); + etl::link_right(data5, nullptr); + etl::link_left(data6, nullptr); + etl::link_right(data6, nullptr); + + // Second link + data0.SecondTLink::clear(); + etl::link_left(&data6, &data4); + etl::link_right(&data6, &data5); + + etl::link_left(data4, data0); + etl::link_right(data4, data1); + etl::link_left(data0, nullptr); + etl::link_right(data0, nullptr); + etl::link_left(data1, nullptr); + etl::link_right(data1, nullptr); + + etl::link_left(data5, data2); + etl::link_right(data5, data3); + etl::link_left(data2, nullptr); + etl::link_right(data2, nullptr); + etl::link_left(data3, nullptr); + etl::link_right(data3, nullptr); + + // Check first + CHECK(data0.FirstTLink::etl_left == &data1); + CHECK(data0.FirstTLink::etl_right == &data2); + CHECK(data1.FirstTLink::etl_parent == &data0); + CHECK(data2.FirstTLink::etl_parent == &data0); + + CHECK(data1.FirstTLink::etl_left == &data3); + CHECK(data1.FirstTLink::etl_right == &data4); + CHECK(data3.FirstTLink::etl_parent == &data1); + CHECK(data3.FirstTLink::etl_left == nullptr); + CHECK(data3.FirstTLink::etl_right == nullptr); + CHECK(data4.FirstTLink::etl_parent == &data1); + CHECK(data4.FirstTLink::etl_left == nullptr); + CHECK(data4.FirstTLink::etl_right == nullptr); + + CHECK(data2.FirstTLink::etl_left == &data5); + CHECK(data2.FirstTLink::etl_right == &data6); + CHECK(data5.FirstTLink::etl_parent == &data2); + CHECK(data5.FirstTLink::etl_left == nullptr); + CHECK(data5.FirstTLink::etl_right == nullptr); + CHECK(data6.FirstTLink::etl_parent == &data2); + CHECK(data6.FirstTLink::etl_left == nullptr); + CHECK(data6.FirstTLink::etl_right == nullptr); + + // Check second + CHECK(data6.SecondTLink::etl_left == &data4); + CHECK(data6.SecondTLink::etl_right == &data5); + CHECK(data4.SecondTLink::etl_parent == &data6); + CHECK(data5.SecondTLink::etl_parent == &data6); + + CHECK(data4.SecondTLink::etl_left == &data0); + CHECK(data4.SecondTLink::etl_right == &data1); + CHECK(data0.SecondTLink::etl_parent == &data4); + CHECK(data0.SecondTLink::etl_left == nullptr); + CHECK(data0.SecondTLink::etl_right == nullptr); + CHECK(data1.SecondTLink::etl_parent == &data4); + CHECK(data1.SecondTLink::etl_left == nullptr); + CHECK(data1.SecondTLink::etl_right == nullptr); + + CHECK(data5.SecondTLink::etl_left == &data2); + CHECK(data5.SecondTLink::etl_right == &data3); + CHECK(data2.SecondTLink::etl_parent == &data5); + CHECK(data2.SecondTLink::etl_left == nullptr); + CHECK(data2.SecondTLink::etl_right == nullptr); + CHECK(data3.SecondTLink::etl_parent == &data5); + CHECK(data3.SecondTLink::etl_left == nullptr); + CHECK(data3.SecondTLink::etl_right == nullptr); + } }; } From fa1284d7ed3bb32bc1ab26145f0472897904d4b7 Mon Sep 17 00:00:00 2001 From: jwellbelove Date: Mon, 25 Jan 2016 12:37:41 +0000 Subject: [PATCH 2/9] Partial update. Added link_after to forward_link. Added SAFE option to bidirectional_link --- intrusive_links.h | 111 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/intrusive_links.h b/intrusive_links.h index 6c373eae..e2f380dd 100644 --- a/intrusive_links.h +++ b/intrusive_links.h @@ -33,6 +33,11 @@ SOFTWARE. #include "nullptr.h" #include "type_traits.h" +#include "exception.h" +#include "error_handler.h" + +#undef ETL_FILE +#define ETL_FILE "23" namespace etl { @@ -40,11 +45,26 @@ namespace etl { enum { - NO_AUTO_UNLINK = false, - AUTO_UNLINK = true + DEFAULT = 0, + AUTO = 1, + SAFE = 2 }; }; + //*************************************************************************** + /// Deque full exception. + ///\ingroup deque + //*************************************************************************** + class link_exception : public etl::exception + { + public: + + link_exception(string_type file_name, numeric_type line_number) + : exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number) + { + } + }; + //*************************************************************************** /// A forward link. //*************************************************************************** @@ -72,6 +92,15 @@ namespace etl lhs.etl_next = &rhs; } + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_insert(TLink& lhs, TLink& rhs) + { + rhs.etl_next = lhs.etl_next; + lhs.etl_next = &rhs; + } + // Pointer, Pointer template typename etl::enable_if >::value, void>::type @@ -83,6 +112,22 @@ namespace etl } } + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link_insert(TLink* lhs, TLink* rhs) + { + if (lhs != nullptr) + { + if (rhs != nullptr) + { + rhs->etl_next = lhs->etl_next; + } + + lhs->etl_next = rhs; + } + } + // Reference, Pointer template typename etl::enable_if >::value, void>::type @@ -91,6 +136,19 @@ namespace etl lhs.etl_next = rhs; } + // Reference, Pointer + template + typename etl::enable_if >::value, void>::type + link_insert(TLink& lhs, TLink* rhs) + { + if (rhs != nullptr) + { + rhs->etl_next = lhs.etl_next; + } + + lhs.etl_next = rhs; + } + // Pointer, Reference template typename etl::enable_if >::value, void>::type @@ -102,6 +160,18 @@ namespace etl } } + // Pointer, Reference + template + typename etl::enable_if >::value, void>::type + link_insert(TLink* lhs, TLink& rhs) + { + if (lhs != nullptr) + { + rhs.etl_next = lhs->etl_next; + lhs->etl_next = &rhs; + } + } + // Reference template typename etl::enable_if >::value, void>::type @@ -130,7 +200,7 @@ namespace etl //*************************************************************************** /// A bidirectional link. //*************************************************************************** - template + template struct bidirectional_link { enum @@ -149,10 +219,12 @@ namespace etl bidirectional_link* etl_next; }; + //****************************************************************** // Specialisation for auto unlinked option. // When this link is destroyed it will automatically unlink itself. + //****************************************************************** template - struct bidirectional_link + struct bidirectional_link { enum { @@ -185,6 +257,36 @@ namespace etl bidirectional_link* etl_next; }; + //****************************************************************** + // Specialisation for safe unlinked option. + // An error will be generated if the links are valid when the object + // is destroyed. + //****************************************************************** + template + struct bidirectional_link + { + enum + { + ID = ID_, + OPTION = etl::link_option::AUTO_UNLINK + }; + + ~bidirectional_link() + { + ETL_ASSERT(etl_previous == nullptr, ETL_ERROR(link_exception)); + ETL_ASSERT(etl_next == nullptr, ETL_ERROR(link_exception)); + } + + void clear() + { + etl_previous = nullptr; + etl_next = nullptr; + } + + bidirectional_link* etl_previous; + bidirectional_link* etl_next; + }; + // Reference, Reference template typename etl::enable_if >::value, void>::type @@ -393,4 +495,5 @@ namespace etl } } +#undef ETL_FILE #endif From 348a6333d2399514a775b4468aaf34c07708cb25 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:00:56 +0000 Subject: [PATCH 3/9] Removed file --- etl.jpg | Bin 18660 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 etl.jpg diff --git a/etl.jpg b/etl.jpg deleted file mode 100644 index 77556b7f27f6fd48bb15124c0ef307f1aa896b18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18660 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

lOl&M@s4lRh=;HQCalKM8Q_e`omE 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 Y9(wQtD8K?z5Yj`jVGA!`NI(DpJK^mF*#H0l From 9a35980950aff3566f7ebdc59f472181b733272c Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:03:49 +0000 Subject: [PATCH 4/9] Modified checksum class to be easily customised. Added sum, bsd & xor policies. Deleted bsd_checksum.h --- bsd_checksum.h | 139 ------------------------------ checksum.h | 167 ++++++++++++++++++++++++++++++++----- test/test_xor_checksum.cpp | 149 +++++++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+), 160 deletions(-) delete mode 100644 bsd_checksum.h create mode 100644 test/test_xor_checksum.cpp diff --git a/bsd_checksum.h b/bsd_checksum.h deleted file mode 100644 index 00fb7884..00000000 --- a/bsd_checksum.h +++ /dev/null @@ -1,139 +0,0 @@ -///\file - -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -http://www.etlcpp.com - -Copyright(c) 2014 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#ifndef __ETL_BSDCHECKSUM__ -#define __ETL_BSDCHECKSUM__ - -#include - -#include "static_assert.h" -#include "type_traits.h" -#include "binary.h" -#include "ihash.h" - -///\defgroup bsdchecksum BSD Checksum calculation -///\ingroup maths - -namespace etl -{ - //*************************************************************************** - /// Calculates the checksum. - ///\tparam TSum The type used for the sum. - ///\ingroup checksum - //*************************************************************************** - template - class bsd_checksum - { - public: - - STATIC_ASSERT(is_unsigned::value, "Signed TSum template parameter not supported"); - - typedef TSum value_type; - - //************************************************************************* - /// Default constructor. - //************************************************************************* - bsd_checksum() - { - reset(); - } - - //************************************************************************* - /// Constructor from range. - /// \param begin Start of the range. - /// \param end End of the range. - //************************************************************************* - template - bsd_checksum(TIterator begin, const TIterator end) - { - STATIC_ASSERT(sizeof(typename std::iterator_traits::value_type) == 1, "Only 8 bit types supported"); - reset(); - - while (begin != end) - { - sum = rotate_right(sum) + *begin++; - } - } - - //************************************************************************* - /// Resets the CRC to the initial state. - //************************************************************************* - void reset() - { - sum = 0; - } - - //************************************************************************* - /// Adds a range. - /// \param begin - /// \param end - //************************************************************************* - template - void add(TIterator begin, const TIterator end) - { - STATIC_ASSERT(sizeof(typename std::iterator_traits::value_type) == 1, "Only 8 bit types supported"); - - while (begin != end) - { - sum = rotate_right(sum) + *begin++; - } - } - - //************************************************************************* - /// \param value The uint8_t to add to the checksum. - //************************************************************************* - void add(uint8_t value) - { - sum = rotate_right(sum) + value; - } - - //************************************************************************* - /// Gets the checksum value. - //************************************************************************* - value_type value() - { - return sum; - } - - //************************************************************************* - /// Conversion operator to value_type. - //************************************************************************* - operator value_type () - { - return sum; - } - - private: - - value_type sum; - }; -} - -#endif diff --git a/checksum.h b/checksum.h index 142a00de..44633267 100644 --- a/checksum.h +++ b/checksum.h @@ -1,24 +1,20 @@ + ///\file /****************************************************************************** The MIT License(MIT) - Embedded Template Library. https://github.com/ETLCPP/etl http://www.etlcpp.com - Copyright(c) 2014 jwellbelove - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE @@ -35,7 +31,7 @@ SOFTWARE. #include "static_assert.h" #include "type_traits.h" -#include "ihash.h" +#include "binary.h" ///\defgroup checksum Checksum calculation ///\ingroup maths @@ -43,18 +39,86 @@ SOFTWARE. namespace etl { //*************************************************************************** - /// Calculates the checksum. - ///\tparam TSum The type used for the sum. + /// Standard addition checksum policy. + //*************************************************************************** + template + struct checksum_policy_sum + { + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return sum + value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// BSD checksum policy. + //*************************************************************************** + template + struct checksum_policy_bsd + { + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return etl::rotate_right(sum) + value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// Standard XOR checksum policy. + //*************************************************************************** + template + struct checksum_policy_xor + { + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return sum ^ value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// Calculates a checksum according to the specified policy. + ///\tparam TSum The type used for the sum. + ///\tparam TPolicy The type used to enact the policy. Default = checksum_policy_sum ///\ingroup checksum //*************************************************************************** - template + template > class checksum { public: - STATIC_ASSERT(is_unsigned::value, "Signed TSum template parameter not supported"); + STATIC_ASSERT(etl::is_unsigned::value, "Signed TSum template parameter not supported"); - typedef TSum value_type; + typedef TSum value_type; + typedef TPolicy policy_type; //************************************************************************* /// Default constructor. @@ -75,10 +139,7 @@ namespace etl STATIC_ASSERT(sizeof(typename std::iterator_traits::value_type) == 1, "Type not supported"); reset(); - while (begin != end) - { - sum += *begin++; - } + add(begin, end); } //************************************************************************* @@ -86,7 +147,7 @@ namespace etl //************************************************************************* void reset() { - sum = 0; + sum = policy.initial(); } //************************************************************************* @@ -101,7 +162,7 @@ namespace etl while (begin != end) { - sum += *begin++; + sum = policy.add(sum, *begin++); } } @@ -110,7 +171,7 @@ namespace etl //************************************************************************* void add(uint8_t value) { - sum += value; + sum = policy.add(sum, value); } //************************************************************************* @@ -118,7 +179,7 @@ namespace etl //************************************************************************* value_type value() const { - return sum; + return policy.final(sum); } //************************************************************************* @@ -126,13 +187,77 @@ namespace etl //************************************************************************* operator value_type () const { - return sum; + return policy.final(sum); } private: - value_type sum; + value_type sum; + policy_type policy; }; + + //************************************************************************* + /// BSD Checksum. + //************************************************************************* + template + class bsd_checksum : public etl::checksum > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + bsd_checksum() + { + reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template + bsd_checksum(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits::value_type) == 1, "Type not supported"); + + reset(); + add(begin, end); + } + }; + + //************************************************************************* + /// XOR Checksum. + //************************************************************************* + template + class xor_checksum : public etl::checksum > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + xor_checksum() + { + reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template + xor_checksum(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits::value_type) == 1, "Type not supported"); + + reset(); + add(begin, end); + } + }; + } #endif diff --git a/test/test_xor_checksum.cpp b/test/test_xor_checksum.cpp new file mode 100644 index 00000000..24c28866 --- /dev/null +++ b/test/test_xor_checksum.cpp @@ -0,0 +1,149 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "../checksum.h" + +namespace +{ + template + TSum reference_checksum(TIterator begin, TIterator end) + { + typedef typename std::iterator_traits::value_type value_type; + TSum checksum = 0; + + while (begin != end) + { + value_type value = *begin++; + checksum ^= value; + } + + return checksum; + } + + SUITE(test_checksum) + { + //************************************************************************* + TEST(test_checksum_constructor) + { + std::string data("123456789"); + + uint8_t sum = etl::xor_checksum(data.begin(), data.end()); + uint8_t compare = reference_checksum(data.begin(), data.end()); + + CHECK_EQUAL(int(compare), int(sum)); + } + + //************************************************************************* + TEST(test_checksum_add_values8_add) + { + std::string data("123456789"); + + etl::xor_checksum checksum_calculator; + + for (size_t i = 0; i < data.size(); ++i) + { + checksum_calculator.add(data[i]); + } + + uint8_t sum = checksum_calculator; + uint8_t compare = reference_checksum(data.begin(), data.end()); + + CHECK_EQUAL(int(compare), int(sum)); + } + + //************************************************************************* + TEST(test_checksum_add_values8_operator_plus_equals) + { + std::string data("123456789"); + + etl::xor_checksum checksum_calculator; + + for (size_t i = 0; i < data.size(); ++i) + { + checksum_calculator.add(data[i]); + } + + uint8_t sum = checksum_calculator; + uint8_t compare = reference_checksum(data.begin(), data.end()); + + CHECK_EQUAL(int(compare), int(sum)); + } + + //************************************************************************* + TEST(test_checksum_add_range) + { + std::string data("123456789"); + + etl::xor_checksum checksum_calculator; + + checksum_calculator.add(data.begin(), data.end()); + + uint8_t sum = checksum_calculator.value(); + uint8_t compare = reference_checksum(data.begin(), data.end()); + + CHECK_EQUAL(int(compare), int(sum)); + } + + //************************************************************************* + TEST(test_checksum_add_range_sum32) + { + std::string data("1"); + + etl::xor_checksum checksum_calculator; + + checksum_calculator.add(data.begin(), data.end()); + + uint32_t sum = checksum_calculator.value(); + uint32_t compare = reference_checksum(data.begin(), data.end()); + + CHECK_EQUAL(compare, sum); + } + + //************************************************************************* + TEST(test_checksum_add_range_endian) + { + std::vector data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + std::vector data2 = { 0x04030201, 0x08070605 }; + std::vector data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; + + uint64_t hash1 = etl::xor_checksum(data1.begin(), data1.end()); + uint64_t hash2 = etl::xor_checksum((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t))); + uint64_t hash3 = etl::xor_checksum(data3.rbegin(), data3.rend()); + CHECK_EQUAL(hash1, hash2); + CHECK_EQUAL(hash1, hash3); + } + }; +} + From 65e5dbd7c998762e17a4e7e6ba3657c005c2a252 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:04:06 +0000 Subject: [PATCH 5/9] Modified checksum class to be easily customised. Added sum, bsd & xor policies. Deleted bsd_checksum.h --- test/test_bsd_checksum.cpp | 45 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/test/test_bsd_checksum.cpp b/test/test_bsd_checksum.cpp index 1c0991eb..9c209da1 100644 --- a/test/test_bsd_checksum.cpp +++ b/test/test_bsd_checksum.cpp @@ -33,31 +33,30 @@ SOFTWARE. #include #include -#include "../bsd_checksum.h" -#include "../endian.h" - -template -TSum reference_checksum(TIterator begin, TIterator end) -{ - typedef typename std::iterator_traits::value_type value_type; - TSum checksum = 0; - - while (begin != end) - { - value_type value = *begin++; - - for (int i = 0; i < sizeof(value_type); ++i) - { - uint8_t byte = (value >> (i * 8)) & 0xFF; - checksum = etl::rotate_right(checksum) + byte; - } - } - - return checksum; -} +#include "../checksum.h" namespace -{ +{ + template + TSum reference_checksum(TIterator begin, TIterator end) + { + typedef typename std::iterator_traits::value_type value_type; + TSum checksum = 0; + + while (begin != end) + { + value_type value = *begin++; + + for (int i = 0; i < sizeof(value_type); ++i) + { + uint8_t byte = (value >> (i * 8)) & 0xFF; + checksum = etl::rotate_right(checksum) + byte; + } + } + + return checksum; + } + SUITE(test_checksum) { //************************************************************************* From 8144554320953339dea9236cd6c6de271927e27d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:05:42 +0000 Subject: [PATCH 6/9] Added intrusive_list and updated intrusive_forward list. Added set of intrusive links. --- intrusive_forward_list.h | 442 ++++++++++- intrusive_links.h | 576 +++++++++++--- test/test_intrusive_forward_list.cpp | 394 +++++++-- test/test_intrusive_links.cpp | 580 +++++++++++++- test/test_intrusive_list.cpp | 1098 ++++++++++++++++++++++++++ test/vs2015/etl.sln | 3 + test/vs2015/etl.vcxproj | 4 +- test/vs2015/etl.vcxproj.filters | 12 +- 8 files changed, 2864 insertions(+), 245 deletions(-) create mode 100644 test/test_intrusive_list.cpp diff --git a/intrusive_forward_list.h b/intrusive_forward_list.h index a66a451e..04260181 100644 --- a/intrusive_forward_list.h +++ b/intrusive_forward_list.h @@ -7,7 +7,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl http://www.etlcpp.com -Copyright(c) 2015 jwellbelove +Copyright(c) 2016 jwellbelove Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -45,6 +45,7 @@ SOFTWARE. #include "exception.h" #include "error_handler.h" #include "intrusive_links.h" +#include "algorithm.h" #undef ETL_FILE #define ETL_FILE "20" @@ -107,12 +108,26 @@ namespace etl } }; + //*************************************************************************** + /// Unsorted exception for the intrusive_forward_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_forward_list_unsorted : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_unsorted(string_type file_name, numeric_type line_number) + : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:unsorted", ETL_FILE"D"), file_name, line_number) + { + } + }; + //*************************************************************************** /// An intrusive forward list. ///\ingroup intrusive_forward_list ///\note TLink must be a base of TValue. //*************************************************************************** - template > + template , const size_t COUNT_OPTION = etl::count_option::FAST_COUNT > class intrusive_forward_list { public: @@ -128,7 +143,7 @@ namespace etl typedef const value_type& const_reference; typedef size_t size_type; - public: + typedef intrusive_forward_list list_type; //************************************************************************* /// iterator. @@ -239,7 +254,7 @@ namespace etl { } - const_iterator(const typename intrusive_forward_list::iterator& other) + const_iterator(const typename intrusive_forward_list::iterator& other) : p_value(other.p_value) { } @@ -427,8 +442,7 @@ namespace etl while (first != last) { link_type& link = *first++; - join(p_last_link, &link); - join(&link, nullptr); + etl::link_splice(p_last_link, link); p_last_link = &link; ++current_size; } @@ -475,24 +489,40 @@ namespace etl second = track; // Move second link to next } - join(&start_link, first); + etl::link(start_link, first); } //************************************************************************* /// Inserts a value to the intrusive_forward_list after the specified position. //************************************************************************* - iterator insert_after(iterator position, value_type& value) + template + typename etl::enable_if::type + insert_after(iterator position, value_type& value) { insert_link_after(*position.p_value, value); + return iterator(value); + } + //************************************************************************* + /// Inserts a value to the intrusive_forward_list after the specified position. + /// Checks that the value is unlinked. + //************************************************************************* + template + typename etl::enable_if::type + insert_after(iterator position, value_type& value) + { + ETL_ASSERT(!value.TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception)); + + insert_link_after(*position.p_value, value); return iterator(value); } //************************************************************************* /// Inserts a range of values to the intrusive_forward_list after the specified position. //************************************************************************* - template - void insert_after(iterator position, TIterator first, TIterator last) + template + typename etl::enable_if::type + insert_after(iterator position, TIterator first, TIterator last) { while (first != last) { @@ -502,10 +532,30 @@ namespace etl } } + //************************************************************************* + /// Inserts a range of values to the intrusive_forward_list after the specified position. + /// Checks that the values are unlinked. + //************************************************************************* + template + typename etl::enable_if::type + insert_after(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + ETL_ASSERT(!position.p_value->TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception)); + + // Set up the next free link. + insert_link_after(*position.p_value, *first++); + ++position; + } + } + //************************************************************************* /// Erases the value at the specified position. //************************************************************************* - iterator erase_after(iterator position) + template + typename etl::enable_if::type + erase_after(iterator position) { iterator next(position); ++next; @@ -516,17 +566,37 @@ namespace etl return next; } + //************************************************************************* + /// Erases the value at the specified position. + /// Clears the link after erasing. + //************************************************************************* + template + typename etl::enable_if::type + erase_after(iterator position) + { + iterator next(position); + ++next; + ++next; + + remove_link_after(*position.p_value); + position.p_value->TLink::clear(); + + return next; + } + //************************************************************************* /// Erases a range of elements. //************************************************************************* - iterator erase_after(iterator first, iterator last) + template + typename etl::enable_if::type + erase_after(iterator first, iterator last) { link_type* p_first = first.p_value; link_type* p_last = last.p_value; link_type* p_next = p_first->etl_next; // Join the ends. - join(p_first, p_last); + etl::link(p_first, p_last); p_first = p_next; @@ -550,6 +620,44 @@ namespace etl } } + //************************************************************************* + /// Erases a range of elements. + /// Clears the links after erasing. + //************************************************************************* + template + typename etl::enable_if::type + erase_after(iterator first, iterator last) + { + link_type* p_first = first.p_value; + link_type* p_last = last.p_value; + link_type* p_next = p_first->etl_next; + + // Join the ends. + etl::link(p_first, p_last); + + p_first = p_next; + + // Erase the ones in between. + while (p_first != p_last) + { + // One less. + --current_size; + + p_next = p_first->etl_next; // Remember the next link. + p_first->TLink::clear(); // Clear the link. + p_first = p_next; // Move to the next link. + } + + if (p_next == nullptr) + { + return end(); + } + else + { + return iterator(*static_cast(p_last)); + } + } + //************************************************************************* /// Removes all but the one element from every consecutive group of equal /// elements in the container. @@ -679,14 +787,14 @@ namespace etl // Add the next link to the merged head. if (i_head == before_begin()) { - join(i_head.p_value, i_link.p_value); - i_head = i_link; - i_tail = i_link; + etl::link(i_head.p_value, i_link.p_value); + i_head = i_link; + i_tail = i_link; } else { - join(i_tail.p_value, i_link.p_value); - i_tail = i_link; + etl::link(i_tail.p_value, i_link.p_value); + i_tail = i_link; } i_tail.p_value->link_type::etl_next = nullptr; @@ -737,7 +845,7 @@ namespace etl { iterator i_item = begin(); iterator i_last_item = before_begin(); - + while (i_item != end()) { if (predicate(*i_item)) @@ -753,41 +861,296 @@ namespace etl } //************************************************************************* - /// Returns true if the list has not elements. + /// Returns true if the list has no elements. //************************************************************************* bool empty() const { - return current_size == 0; + return start_link.etl_next == nullptr; } //************************************************************************* /// Returns the number of elements. //************************************************************************* - size_t size() const + template + typename etl::enable_if::type + size() const { - return current_size; + return current_size.count; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + template + typename etl::enable_if::type + size() const + { + return std::distance(cbegin(), cend()); + } + + //************************************************************************* + /// Splice another list into this one. + //************************************************************************* + void splice_after(iterator position, list_type& list) + { + // No point splicing to ourself! + if (&list != this) + { + if (!list.empty()) + { + link_type& first = list.get_head(); + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + current_size += list.size(); + } + } + + link_type& before = *position.p_value; + link_type& after = *position.p_value->link_type::etl_next; + + etl::link(before, first); + + link_type* last = &before; + while (last->link_type::etl_next != nullptr) + { + last = last->link_type::etl_next; + } + + etl::link(last, after); + + list.clear(); + } + } + } + + //************************************************************************* + /// Splice an element from another list into this one. + //************************************************************************* + void splice(iterator position, list_type& list, iterator isource) + { + link_type& before = *position.p_value; + + etl::unlink(*isource.p_value); + etl::link_splice(before, *isource.p_value); + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + ++current_size; + --list.current_size; + } + } + } + + //************************************************************************* + /// Splice a range of elements from another list into this one. + //************************************************************************* + void splice_after(iterator position, list_type& list, iterator begin_, iterator end_) + { + if (!list.empty()) + { + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + size_t n = std::distance(begin_, end_) - 1; + current_size += n; + list.current_size -= n; + } + } + + link_type* first = begin_.p_value; + link_type* last = first; + + while (last->link_type::etl_next != end_.p_value) + { + last = last->link_type::etl_next; + } + + // Unlink from the source list. + link_type* first_next = first->link_type::etl_next; + etl::unlink_after(*first, *last); + + // Fix our links. + link_type* before = position.p_value; + + etl::link_splice(*before, *first_next, *last); + } + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + void merge(list_type& list) + { + merge(list, std::less()); + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + template + void merge(list_type& list, TCompare compare) + { + if (!list.empty()) + { +#if _DEBUG + ETL_ASSERT(etl::is_sorted(list.begin(), list.end(), compare), ETL_ERROR(intrusive_forward_list_unsorted)); + ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_forward_list_unsorted)); +#endif + + value_type* other_begin = static_cast(&list.get_head()); + value_type* other_terminal = nullptr; + + value_type* before = static_cast(&start_link); + value_type* before_next = get_next(before); + value_type* terminal = nullptr; + + while ((before->link_type::etl_next != terminal) && (other_begin != other_terminal)) + { + // Find the place to insert. + while ((before_next != terminal) && !(compare(*other_begin, *before_next))) + { + before = before_next; + before_next = get_next(before_next); + } + + // Insert. + if (before_next != terminal) + { + while ((other_begin != other_terminal) && (compare(*other_begin, *before_next))) + { + value_type* value = other_begin; + other_begin = get_next(other_begin); + etl::link_splice(*before, *value); + before = get_next(before); + } + } + } + + // Any left over? + if (before_next == terminal) + { + while (other_begin != other_terminal) + { + value_type* value = other_begin; + other_begin = get_next(other_begin); + etl::link_splice(*before, *value); + before = get_next(before); + } + } + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + current_size += list.size(); + } + + list.clear(); + } } private: link_type start_link; ///< The link that acts as the intrusive_forward_list start. - size_t current_size; ///< The number of elements in the list. - size_t index; ///< The index level of the link that this list operates on. + + //************************************************************************* + /// Counter type based on count option. + //************************************************************************* + template + class counter_type; //************************************************************************* - /// Join two links. + /// Slow type. //************************************************************************* - void join(link_type* left, link_type* right) + template <> + class counter_type { - left->etl_next = right; - } + public: + counter_type& operator ++() + { + return *this; + } + + counter_type& operator --() + { + return *this; + } + + counter_type& operator =(size_t new_count) + { + return *this; + } + + counter_type& operator +=(size_t diff) + { + return *this; + } + + counter_type& operator -=(size_t diff) + { + return *this; + } + }; + + //************************************************************************* + /// Fast type. + //************************************************************************* + template <> + class counter_type + { + public: + + counter_type() + : count(0) + { + } + + counter_type& operator ++() + { + ++count; + return *this; + } + + counter_type& operator --() + { + --count; + return *this; + } + + counter_type& operator =(size_t new_count) + { + count = new_count; + return *this; + } + + counter_type& operator +=(size_t diff) + { + count += diff; + return *this; + } + + counter_type& operator -=(size_t diff) + { + count -= diff; + return *this; + } + + size_t count; + }; + + counter_type current_size; ///< Counts the number of elements in the list. + //************************************************************************* /// Is the intrusive_forward_list a trivial length? //************************************************************************* bool is_trivial_list() const { - return current_size <= 1; + return (start_link.link_type::etl_next == nullptr) || (start_link.link_type::etl_next->etl_next == nullptr);; } //************************************************************************* @@ -796,8 +1159,7 @@ namespace etl void insert_link_after(link_type& position, link_type& link) { // Connect to the intrusive_forward_list. - join(&link, position.etl_next); - join(&position, &link); + etl::link_splice(position, link); ++current_size; } @@ -806,13 +1168,9 @@ namespace etl //************************************************************************* void remove_link_after(link_type& link) { - // The link to erase. - link_type* p_link = link.etl_next; - - if (p_link != nullptr) + if (link.etl_next != nullptr) { - // Disconnect the link from the intrusive_forward_list. - join(&link, p_link->etl_next); + etl::unlink_after(link); --current_size; } } @@ -833,6 +1191,14 @@ namespace etl return *start_link.etl_next; } + //************************************************************************* + /// Get the next value. + //************************************************************************* + value_type* get_next(link_type* link) const + { + return static_cast(link->etl_next); + } + //************************************************************************* /// Initialise the intrusive_forward_list. //************************************************************************* diff --git a/intrusive_links.h b/intrusive_links.h index e2f380dd..d59d81fe 100644 --- a/intrusive_links.h +++ b/intrusive_links.h @@ -31,13 +31,26 @@ SOFTWARE. #ifndef __ETL_INTRUSIVE_LINKS__ #define __ETL_INTRUSIVE_LINKS__ +#include + #include "nullptr.h" #include "type_traits.h" #include "exception.h" #include "error_handler.h" #undef ETL_FILE -#define ETL_FILE "23" +#define ETL_FILE "21" + +//***************************************************************************** +// Note: +// The link functions work slightly differently to the STL 'insert' convention +// in that the second link parameter will be inserted after the first. +// i.e. +// If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the +// resulting list will contain '1', '2', '5', '3', '4' +// This is to maintain consistency between forward and bidirectional links +// and also is intuitive. +//***************************************************************************** namespace etl { @@ -45,48 +58,120 @@ namespace etl { enum { - DEFAULT = 0, - AUTO = 1, - SAFE = 2 + DEFAULT, + AUTO, + CHECKED }; }; + namespace count_option + { + enum + { + SLOW_COUNT, + FAST_COUNT + }; + } + //*************************************************************************** - /// Deque full exception. - ///\ingroup deque + /// Link exception. //*************************************************************************** class link_exception : public etl::exception { public: - link_exception(string_type file_name, numeric_type line_number) - : exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number) + link_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) { } }; + //*************************************************************************** + /// not unlinked exception. + //*************************************************************************** + class not_unlinked_exception : public etl::link_exception + { + public: + + not_unlinked_exception(string_type file_name, numeric_type line_number) + : link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number) + { + } + }; + + namespace __private_intrusive_links__ + { + //*************************************************************************** + /// A forward link base. + //*************************************************************************** + template + struct forward_link_base + { + enum + { + ID = ID_, + OPTION = OPTION_ + }; + + void clear() + { + etl_next = nullptr; + } + + bool is_linked() const + { + return etl_next != nullptr; + } + + TLink* etl_next; + }; + } + //*************************************************************************** /// A forward link. //*************************************************************************** - template - struct forward_link + template + struct forward_link + : public __private_intrusive_links__::forward_link_base, ID_, OPTION_> { - enum - { - ID = ID_ - }; + }; - void clear() + //****************************************************************** + // There is no valid specialisation for auto link + //****************************************************************** + template + struct forward_link + : public __private_intrusive_links__::forward_link_base, ID_, etl::link_option::AUTO> + { + forward_link() { - etl_next = nullptr; + clear(); + } + }; + + //****************************************************************** + // Specialisation for checked unlink option. + // An error will be generated if the links are valid when the object + // is destroyed. + //****************************************************************** + template + struct forward_link + : public __private_intrusive_links__::forward_link_base, ID_, etl::link_option::CHECKED> + { + forward_link() + { + clear(); } - forward_link* etl_next; + ~forward_link() + { + assert(etl_next != nullptr); + } }; // Reference, Reference template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link(TLink& lhs, TLink& rhs) { lhs.etl_next = &rhs; @@ -94,8 +179,8 @@ namespace etl // Reference, Reference template - typename etl::enable_if >::value, void>::type - link_insert(TLink& lhs, TLink& rhs) + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink& rhs) { rhs.etl_next = lhs.etl_next; lhs.etl_next = &rhs; @@ -103,7 +188,7 @@ namespace etl // Pointer, Pointer template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link(TLink* lhs, TLink* rhs) { if (lhs != nullptr) @@ -114,8 +199,8 @@ namespace etl // Pointer, Pointer template - typename etl::enable_if >::value, void>::type - link_insert(TLink* lhs, TLink* rhs) + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink* rhs) { if (lhs != nullptr) { @@ -130,7 +215,7 @@ namespace etl // Reference, Pointer template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link(TLink& lhs, TLink* rhs) { lhs.etl_next = rhs; @@ -138,8 +223,8 @@ namespace etl // Reference, Pointer template - typename etl::enable_if >::value, void>::type - link_insert(TLink& lhs, TLink* rhs) + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink* rhs) { if (rhs != nullptr) { @@ -151,7 +236,7 @@ namespace etl // Pointer, Reference template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link(TLink* lhs, TLink& rhs) { if (lhs != nullptr) @@ -162,8 +247,8 @@ namespace etl // Pointer, Reference template - typename etl::enable_if >::value, void>::type - link_insert(TLink* lhs, TLink& rhs) + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink& rhs) { if (lhs != nullptr) { @@ -172,51 +257,125 @@ namespace etl } } + // Reference, Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink& first, TLink& last) + { + last.etl_next = lhs.etl_next; + lhs.etl_next = &first; + } + + // Pointer, Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink& first, TLink& last) + { + if (lhs != nullptr) + { + last.etl_next = lhs->etl_next; + lhs->etl_next = &first; + } + else + { + last.etl_next = nullptr; + } + } + // Reference template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type unlink_after(TLink& node) { if (node.etl_next != nullptr) { node.etl_next = node.etl_next->etl_next; + + if ((TLink::OPTION == etl::link_option::AUTO) || + (TLink::OPTION == etl::link_option::CHECKED)) + { + node.clear(); + } } } - // Pointer + // Reference, Reference template - typename etl::enable_if >::value, void>::type - unlink_after(TLink* node) + typename etl::enable_if >::value, void>::type + unlink_after(TLink& before, TLink& last) { - if (node != nullptr) + before.etl_next = last.etl_next; + + if ((TLink::OPTION == etl::link_option::AUTO) || + (TLink::OPTION == etl::link_option::CHECKED)) { - if (node->etl_next != nullptr) - { - node->etl_next = node.etl_next->etl_next; - } + last.clear(); } } + namespace __private_intrusive_links__ + { + //*************************************************************************** + /// A bidirectional link base. + //*************************************************************************** + template + struct bidirectional_link_base + { + enum + { + ID = ID_, + OPTION = OPTION_ + }; + + void clear() + { + etl_previous = nullptr; + etl_next = nullptr; + } + + bool is_linked() const + { + return (etl_previous != nullptr) || (etl_next != nullptr); + } + + void reverse() + { + std::swap(etl_previous, etl_next); + } + + TLink* etl_previous; + TLink* etl_next; + + protected: + + void base_unlink() + { + // Connect the previous link with the next. + if (etl_previous != nullptr) + { + etl_previous->etl_next = etl_next; + } + + // Connect the next link with the previous. + if (etl_next != nullptr) + { + etl_next->etl_previous = etl_previous; + } + } + }; + } + //*************************************************************************** /// A bidirectional link. //*************************************************************************** - template - struct bidirectional_link + template + struct bidirectional_link + : public __private_intrusive_links__::bidirectional_link_base, ID_, OPTION_> { - enum + void unlink() { - ID = ID_, - OPTION = OPTION_ - }; - - void clear() - { - etl_previous = nullptr; - etl_next = nullptr; + base_unlink(); } - - bidirectional_link* etl_previous; - bidirectional_link* etl_next; }; //****************************************************************** @@ -224,67 +383,51 @@ namespace etl // When this link is destroyed it will automatically unlink itself. //****************************************************************** template - struct bidirectional_link + struct bidirectional_link + : public __private_intrusive_links__::bidirectional_link_base, ID_, etl::link_option::AUTO> { - enum + bidirectional_link() { - ID = ID_, - OPTION = etl::link_option::AUTO_UNLINK - }; + clear(); + } ~bidirectional_link() { - // Connect the previous link with the next. - if (etl_previous != nullptr) - { - etl_previous->etl_next = etl_next; - } - - // Connect the next link with the previous. - if (etl_next != nullptr) - { - etl_next->etl_previous = etl_previous; - } + base_unlink(); } - void clear() + void unlink() { - etl_previous = nullptr; - etl_next = nullptr; + base_unlink(); + clear(); } - - bidirectional_link* etl_previous; - bidirectional_link* etl_next; }; //****************************************************************** - // Specialisation for safe unlinked option. + // Specialisation for checked unlink option. // An error will be generated if the links are valid when the object // is destroyed. //****************************************************************** template - struct bidirectional_link + struct bidirectional_link + : public __private_intrusive_links__::bidirectional_link_base, ID_, etl::link_option::CHECKED> { - enum + bidirectional_link() { - ID = ID_, - OPTION = etl::link_option::AUTO_UNLINK - }; + clear(); + } ~bidirectional_link() { - ETL_ASSERT(etl_previous == nullptr, ETL_ERROR(link_exception)); - ETL_ASSERT(etl_next == nullptr, ETL_ERROR(link_exception)); + assert(etl_previous == nullptr); + assert(etl_next == nullptr); } - void clear() + void unlink() { - etl_previous = nullptr; - etl_next = nullptr; + base_unlink(); + clear(); } - - bidirectional_link* etl_previous; - bidirectional_link* etl_next; }; // Reference, Reference @@ -296,6 +439,22 @@ namespace etl rhs.etl_previous = &lhs; } + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink& rhs) + { + rhs.etl_next = lhs.etl_next; + rhs.etl_previous = &lhs; + + if (lhs.etl_next != nullptr) + { + lhs.etl_next->etl_previous = &rhs; + } + + lhs.etl_next = &rhs; + } + // Pointer, Pointer template typename etl::enable_if >::value, void>::type @@ -312,6 +471,32 @@ namespace etl } } + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink* rhs) + { + if (rhs != nullptr) + { + if (lhs != nullptr) + { + rhs->etl_next = lhs->etl_next; + } + + rhs->etl_previous = lhs; + } + + if (lhs != nullptr) + { + if (lhs->etl_next != nullptr) + { + lhs->etl_next->etl_previous = rhs; + } + + lhs->etl_next = rhs; + } + } + // Reference, Pointer template typename etl::enable_if >::value, void>::type @@ -325,6 +510,25 @@ namespace etl } } + // Reference, Pointer + template + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink* rhs) + { + if (rhs != nullptr) + { + rhs->etl_next = lhs.etl_next; + rhs->etl_previous = &lhs; + } + + if (lhs.etl_next != nullptr) + { + lhs.etl_next->etl_previous = rhs; + } + + lhs.etl_next = rhs; + } + // Pointer, Reference template typename etl::enable_if >::value, void>::type @@ -338,67 +542,189 @@ namespace etl rhs.etl_previous = lhs; } + // Pointer, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink& rhs) + { + if (lhs != nullptr) + { + rhs.etl_next = lhs->etl_next; + } + + rhs.etl_previous = lhs; + + if (lhs != nullptr) + { + if (lhs->etl_next != nullptr) + { + lhs->etl_next->etl_previous = &rhs; + } + + lhs->etl_next = &rhs; + } + } + + // Reference, Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink& first, TLink& last) + { + last.etl_next = lhs.etl_next; + first.etl_previous = &lhs; + + if (last.etl_next != nullptr) + { + last.etl_next->etl_previous = &last; + } + + lhs.etl_next = &first; + } + + // Pointer, Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink* lhs, TLink& first, TLink& last) + { + if (lhs != nullptr) + { + last.etl_next = lhs->etl_next; + } + else + { + last.etl_next = nullptr; + } + + first.etl_previous = lhs; + + if (last.etl_next != nullptr) + { + last.etl_next->etl_previous = &last; + } + + if (lhs != nullptr) + { + lhs->etl_next = &first; + } + } + // Reference template typename etl::enable_if >::value, void>::type unlink(TLink& node) { - if (node.etl_next != nullptr) - { - node.etl_next->etl_previous = node.etl_previous; - } + node.unlink(); + } - if (node.etl_previous != nullptr) + // Reference Reference + template + typename etl::enable_if >::value, void>::type + unlink(TLink& first, TLink& last) + { + if (&first == &last) { - node.etl_previous->etl_next = node.etl_next; + first.unlink(); + } + else + { + if (last.etl_next != nullptr) + { + last.etl_next->etl_previous = first.etl_previous; + } + + if (first.etl_previous != nullptr) + { + first.etl_previous->etl_next = last.etl_next; + } + + if ((TLink::OPTION == etl::link_option::AUTO) || + (TLink::OPTION == etl::link_option::CHECKED)) + { + first.etl_previous = nullptr; + last.etl_next = nullptr; + } } } - // Pointer - template - typename etl::enable_if >::value, void>::type - unlink(TLink* node) + namespace __private_intrusive_links__ { - if (node != nullptr) + //*************************************************************************** + /// A tree link base. + //*************************************************************************** + template + struct tree_link_base { - if (node->etl_next != nullptr) + enum { - node->etl_next->etl_previous = node->etl_previous; + ID = ID_, + OPTION = OPTION_ + }; + + void clear() + { + etl_parent = nullptr; + etl_left = nullptr; + etl_right = nullptr; } - if (node->etl_previous != nullptr) + bool is_linked() const { - node->etl_previous->etl_next = node->etl_next; + return (etl_parent != nullptr) || (etl_left != nullptr) || (etl_right != nullptr); } - } + + TLink* etl_parent; + TLink* etl_left; + TLink* etl_right; + }; } //*************************************************************************** /// A tree link. //*************************************************************************** - template + template struct tree_link + : public __private_intrusive_links__::tree_link_base, ID_, OPTION_> { - enum - { - ID = ID_ - }; + }; - void clear() + //****************************************************************** + // There is no valid specialisation for auto link + //****************************************************************** + template + struct tree_link + : public __private_intrusive_links__::tree_link_base, ID_, etl::link_option::AUTO> + { + tree_link() { - etl_parent = nullptr; - etl_left = nullptr; - etl_right = nullptr; + clear(); + } + }; + + //****************************************************************** + // Specialisation for checked unlink option. + // An error will be generated if the links are valid when the object + // is destroyed. + //****************************************************************** + template + struct tree_link + : public __private_intrusive_links__::tree_link_base, ID_, etl::link_option::CHECKED> + { + tree_link() + { + clear(); } - tree_link* etl_parent; - tree_link* etl_left; - tree_link* etl_right; + ~tree_link() + { + assert(etl_parent != nullptr); + assert(etl_left != nullptr); + assert(etl_right != nullptr); + } }; // Reference, Reference template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_left(TLink& parent, TLink& leaf) { parent.etl_left = &leaf; @@ -406,7 +732,7 @@ namespace etl } template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_right(TLink& parent, TLink& leaf) { parent.etl_right = &leaf; @@ -415,7 +741,7 @@ namespace etl // Pointer, Pointer template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_left(TLink* parent, TLink* leaf) { if (parent != nullptr) @@ -430,7 +756,7 @@ namespace etl } template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_right(TLink* parent, TLink* leaf) { if (parent != nullptr) @@ -446,7 +772,7 @@ namespace etl // Reference, Pointer template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_left(TLink& parent, TLink* leaf) { parent.etl_left = leaf; @@ -458,7 +784,7 @@ namespace etl } template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_right(TLink& parent, TLink* leaf) { parent.etl_right = leaf; @@ -471,7 +797,7 @@ namespace etl // Pointer, Reference template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_left(TLink* parent, TLink& leaf) { if (parent != nullptr) @@ -483,7 +809,7 @@ namespace etl } template - typename etl::enable_if >::value, void>::type + typename etl::enable_if >::value, void>::type link_right(TLink* parent, TLink& leaf) { if (parent != nullptr) @@ -496,4 +822,4 @@ namespace etl } #undef ETL_FILE -#endif +#endif \ No newline at end of file diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index 847ac82b..df73665d 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -76,6 +76,11 @@ namespace return data < other.data; } + bool operator >(const ItemNDCNode& other) const + { + return other.data < data; + } + ItemNDC data; }; @@ -130,25 +135,6 @@ namespace typedef etl::intrusive_forward_list DataNDC1; typedef std::vector InitialDataNDC; - - template - bool Equal(TIterator1 begin1, - TIterator1 end1, - TIterator2 begin2) - { - while (begin1 != end1) - { - if (*begin1 != *begin2) - { - return false; - } - - ++begin1; - ++begin2; - } - - return true; - } } namespace @@ -157,9 +143,15 @@ namespace { InitialDataNDC unsorted_data; InitialDataNDC sorted_data; + InitialDataNDC sorted_data2; InitialDataNDC non_unique_data; InitialDataNDC unique_data; InitialDataNDC small_data; + InitialDataNDC merge_data0; + InitialDataNDC merge_data1; + InitialDataNDC merge_data2; + InitialDataNDC merge_data3; + InitialDataNDC merge_data4; bool are_equal; @@ -170,9 +162,16 @@ namespace { unsorted_data = { ItemNDCNode("1"), ItemNDCNode("0"), ItemNDCNode("3"), ItemNDCNode("2"), ItemNDCNode("5"), ItemNDCNode("4"), ItemNDCNode("7"), ItemNDCNode("6"), ItemNDCNode("9"), ItemNDCNode("8") }; sorted_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + sorted_data2 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; non_unique_data = { ItemNDCNode("0"), ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; unique_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; small_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + + merge_data0 = { ItemNDCNode("1"), ItemNDCNode("1"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("5"), ItemNDCNode("7"), ItemNDCNode("8") }; + merge_data1 = { ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("9"), ItemNDCNode("9") }; + merge_data2 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("7") }; + merge_data3 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7") }; + merge_data4 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; } }; @@ -195,6 +194,20 @@ namespace CHECK_EQUAL(sorted_data.size(), data0.size()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty_begin_end) + { + DataNDC0 data0; + + CHECK(data0.begin() == data0.end()); + + DataNDC0::const_iterator begin = data0.begin(); + DataNDC0::const_iterator end = data0.end(); + CHECK(begin == end); + + CHECK(data0.cbegin() == data0.cend()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_iterator) { @@ -317,7 +330,7 @@ namespace ItemNDCNode INSERT_VALUE1 = ItemNDCNode("1"); ItemNDCNode INSERT_VALUE2 = ItemNDCNode("2"); - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); DataNDC1 data1(sorted_data.begin(), sorted_data.end()); @@ -326,16 +339,16 @@ namespace DataNDC0::iterator i_data = data0.begin(); std::advance(i_data, offset); - std::vector::iterator i_compare_data = compare_data.begin(); - std::advance(i_compare_data, offset + 1); + std::forward_list::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, offset); data0.insert_after(i_data, INSERT_VALUE1); - compare_data.insert(i_compare_data, INSERT_VALUE1); + compare_data.insert_after(i_compare_data, INSERT_VALUE1); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -348,19 +361,19 @@ namespace std::advance(i_data, offset); i_compare_data = compare_data.begin(); - std::advance(i_compare_data, offset + 1); + std::advance(i_compare_data, offset); - std::vector temp(data0.begin(), data0.end()); + std::forward_list temp(data0.begin(), data0.end()); data0.insert_after(i_data, INSERT_VALUE2); - compare_data.insert(i_compare_data, INSERT_VALUE2); + compare_data.insert_after(i_compare_data, INSERT_VALUE2); temp.assign(data0.begin(), data0.end()); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -373,8 +386,8 @@ namespace { std::vector test1 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4") }; std::vector test2 = { ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; - std::vector compare(test2); - compare.insert(compare.end(), test1.begin(), test1.end()); + std::forward_list compare(test1.begin(), test1.end()); + compare.insert_after(compare.before_begin(), test2.begin(), test2.end()); DataNDC0 data0(test1.begin(), test1.end()); DataNDC1 data1(test1.begin(), test1.end()); @@ -392,16 +405,16 @@ namespace compare.assign(test1.begin(), test1.end()); data0.assign(test1.begin(), test1.end()); - std::vector::iterator icd = compare.begin(); + std::forward_list::iterator icd = compare.begin(); DataNDC0::iterator id = data0.begin(); - std::advance(icd, 4); + std::advance(icd, 3); std::advance(id, 3); - compare.insert(icd, test2.begin(), test2.end()); + compare.insert_after(icd, test2.begin(), test2.end()); data0.insert_after(id, test2.begin(), test2.end()); - std::vector out(data0.begin(), data0.end()); + std::forward_list out(data0.begin(), data0.end()); are_equal = std::equal(data0.begin(), data0.end(), compare.begin()); CHECK(are_equal); @@ -500,17 +513,17 @@ namespace //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_after_single) { - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); DataNDC1 data1(sorted_data.begin(), sorted_data.end()); DataNDC0::iterator i_data = data0.begin(); std::advance(i_data, 2); - std::vector::iterator i_compare_data = compare_data.begin(); - std::advance(i_compare_data, 3); + std::forward_list::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 2); - i_compare_data = compare_data.erase(i_compare_data); + i_compare_data = compare_data.erase_after(i_compare_data); i_data = data0.erase_after(i_data); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); @@ -518,14 +531,14 @@ namespace CHECK(are_equal); CHECK(*i_compare_data == *i_data); - i_compare_data = compare_data.erase(compare_data.begin() + 1); + i_compare_data = compare_data.erase_after(compare_data.begin()); i_data = data0.erase_after(data0.begin()); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -536,8 +549,8 @@ namespace CHECK(are_equal); // Move to the last value and erase. - i_compare_data = compare_data.begin() + 1; - i_compare_data = compare_data.erase(i_compare_data); + i_compare_data = compare_data.begin(); + i_compare_data = compare_data.erase_after(i_compare_data); i_data = data0.begin(); i_data = data0.erase_after(i_data); @@ -545,8 +558,8 @@ namespace are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -560,23 +573,23 @@ namespace //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_after_range) { - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); - DataNDC1 data1(sorted_data.begin(), sorted_data.end()); + DataNDC1 data1(sorted_data2.begin(), sorted_data2.end()); DataNDC0::iterator i_data_1 = data0.begin(); std::advance(i_data_1, 2); DataNDC0::iterator i_data_2 = data0.begin(); - std::advance(i_data_2, 4); + std::advance(i_data_2, 5); - std::vector::iterator i_compare_data_1 = compare_data.begin(); - std::advance(i_compare_data_1, 3); + std::forward_list::iterator i_compare_data_1 = compare_data.begin(); + std::advance(i_compare_data_1, 2); - std::vector::iterator i_compare_data_2 = compare_data.begin(); - std::advance(i_compare_data_2, 4); + std::forward_list::iterator i_compare_data_2 = compare_data.begin(); + std::advance(i_compare_data_2, 5); - std::vector::iterator i_compare_result = compare_data.erase(i_compare_data_1, i_compare_data_2); + std::forward_list::iterator i_compare_result = compare_data.erase_after(i_compare_data_1, i_compare_data_2); DataNDC0::iterator i_result = data0.erase_after(i_data_1, i_data_2); @@ -584,8 +597,8 @@ namespace are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -596,17 +609,17 @@ namespace //************************************************************************* TEST_FIXTURE(SetupFixture, test_erase_after_range_end) { - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); DataNDC1 data1(sorted_data.begin(), sorted_data.end()); DataNDC0::iterator i_data = data0.begin(); std::advance(i_data, 4); - std::vector::iterator i_compare_data = compare_data.begin(); - std::advance(i_compare_data, 5); + std::forward_list::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 4); - std::vector::iterator i_compare_result = compare_data.erase(i_compare_data, compare_data.end()); + std::forward_list::iterator i_compare_result = compare_data.erase_after(i_compare_data, compare_data.end()); DataNDC0::iterator i_result = data0.erase_after(i_data, data0.end()); @@ -614,8 +627,8 @@ namespace are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -665,19 +678,18 @@ namespace //************************************************************************* TEST_FIXTURE(SetupFixture, test_remove) { - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); DataNDC1 data1(sorted_data.begin(), sorted_data.end()); - std::vector::iterator i_item = std::find(compare_data.begin(), compare_data.end(), ItemNDCNode("7")); - compare_data.erase(i_item); + compare_data.remove(ItemNDCNode("7")); data0.remove(ItemNDCNode("7")); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -688,19 +700,18 @@ namespace //************************************************************************* TEST_FIXTURE(SetupFixture, test_remove_if) { - std::vector compare_data(sorted_data.begin(), sorted_data.end()); + std::forward_list compare_data(sorted_data.begin(), sorted_data.end()); DataNDC0 data0(sorted_data.begin(), sorted_data.end()); DataNDC1 data1(sorted_data.begin(), sorted_data.end()); - std::vector::iterator i_item = std::find(compare_data.begin(), compare_data.end(), ItemNDCNode("7")); - compare_data.erase(i_item); + compare_data.remove_if(std::bind2nd(std::equal_to(), ItemNDCNode("7"))); data0.remove_if(std::bind2nd(std::equal_to(), ItemNDCNode("7"))); are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); CHECK(are_equal); - CHECK_EQUAL(compare_data.size(), data0.size()); - CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), data0.size()); + CHECK_EQUAL(std::distance(compare_data.begin(), compare_data.end()), std::distance(data0.begin(), data0.end())); are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); CHECK(are_equal); @@ -752,5 +763,242 @@ namespace are_equal = std::equal(data1.begin(), data1.end(), unsorted_data.begin()); CHECK(are_equal); } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_list) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC0 data1(sorted_data2.begin(), sorted_data2.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + std::forward_list compare0(data0.begin(), data0.end()); + std::forward_list compare1(data1.begin(), data1.end()); + + std::forward_list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + data0.splice_after(idata_destination, data1); + compare0.splice_after(icompare_destination, compare1); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare1.begin(), compare1.end()), data1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_list_self) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + std::forward_list compare0(data0.begin(), data0.end()); + + std::forward_list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + data0.splice_after(idata_destination, data0); + compare0.splice_after(icompare_destination, compare0); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_range) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC0 data1(sorted_data2.begin(), sorted_data2.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 2); + + DataNDC0::iterator idata_begin = data1.begin(); + std::advance(idata_begin, 4); + + DataNDC0::iterator idata_end = data1.begin(); + std::advance(idata_end, 7); + + std::forward_list compare0(data0.begin(), data0.end()); + std::forward_list compare1(data1.begin(), data1.end()); + + std::forward_list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 2); + + std::forward_list::iterator icompare_begin = compare1.begin(); + std::advance(icompare_begin, 4); + + std::forward_list::iterator icompare_end = compare1.begin(); + std::advance(icompare_end, 7); + + data0.splice_after(idata_destination, data1, idata_begin, idata_end); + compare0.splice_after(icompare_destination, compare1, icompare_begin, icompare_end); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare1.begin(), compare1.end()), data1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_range_self) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 2); + + DataNDC0::iterator idata_begin = data0.begin(); + std::advance(idata_begin, 4); + + DataNDC0::iterator idata_end = data0.begin(); + std::advance(idata_end, 7); + + std::forward_list compare0(data0.begin(), data0.end()); + + std::forward_list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 2); + + std::forward_list::iterator icompare_begin = compare0.begin(); + std::advance(icompare_begin, 4); + + std::forward_list::iterator icompare_end = compare0.begin(); + std::advance(icompare_end, 7); + + data0.splice_after(idata_destination, data0, idata_begin, idata_end); + compare0.splice_after(icompare_destination, compare0, icompare_begin, icompare_end); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_1) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data1(merge_data1.begin(), merge_data1.end()); + + std::forward_list compare0(merge_data0.begin(), merge_data0.end()); + std::forward_list compare1(merge_data1.begin(), merge_data1.end()); + + data0.merge(data1); + compare0.merge(compare1); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare1.begin(), compare1.end()), data1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_2) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data2(merge_data2.begin(), merge_data2.end()); + + std::forward_list compare0(merge_data0.begin(), merge_data0.end()); + std::forward_list compare2(merge_data2.begin(), merge_data2.end()); + + data0.merge(data2); + compare0.merge(compare2); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare2.begin(), compare2.end()), data2.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_3) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data3(merge_data3.begin(), merge_data3.end()); + + std::forward_list compare0(merge_data0.begin(), merge_data0.end()); + std::forward_list compare3(merge_data3.begin(), merge_data3.end()); + + data0.merge(data3); + compare0.merge(compare3); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare3.begin(), compare3.end()), data3.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_4) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data4(merge_data4.begin(), merge_data4.end()); + + std::forward_list compare0(merge_data0.begin(), merge_data0.end()); + std::forward_list compare4(merge_data4.begin(), merge_data4.end()); + + data0.merge(data4); + compare0.merge(compare4); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare4.begin(), compare4.end()), data4.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_1_reverse_order) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data1(merge_data1.begin(), merge_data1.end()); + + data0.reverse(); + data1.reverse(); + + std::forward_list compare0(merge_data0.begin(), merge_data0.end()); + std::forward_list compare1(merge_data1.begin(), merge_data1.end()); + + compare0.reverse(); + compare1.reverse(); + + data0.merge(data1, std::greater()); + compare0.merge(compare1, std::greater()); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(std::distance(compare0.begin(), compare0.end()), data0.size()); + CHECK_EQUAL(std::distance(compare1.begin(), compare1.end()), data1.size()); + } }; } diff --git a/test/test_intrusive_links.cpp b/test/test_intrusive_links.cpp index 2c82bce0..06ba8868 100644 --- a/test/test_intrusive_links.cpp +++ b/test/test_intrusive_links.cpp @@ -36,7 +36,7 @@ SOFTWARE. namespace { //******************************************************* - //Forward + // Forward //******************************************************* typedef etl::forward_link<0> FirstFLink; typedef etl::forward_link<1> SecondFLink; @@ -54,7 +54,8 @@ namespace //******************************************************* // Bidirectional //******************************************************* - typedef etl::bidirectional_link<0, etl::link_option::AUTO_UNLINK> FirstBLinkAuto; + typedef etl::bidirectional_link<0, etl::link_option::AUTO> FirstBLinkAuto; + typedef etl::bidirectional_link<0, etl::link_option::CHECKED> FirstBLinkChecked; typedef etl::bidirectional_link<0> FirstBLink; typedef etl::bidirectional_link<1> SecondBLink; @@ -78,11 +79,22 @@ namespace int value; }; + struct BDataChecked : public FirstBLinkChecked + { + BDataChecked(int value) + : value(value) + { + } + + int value; + }; + //******************************************************* // Tree //******************************************************* typedef etl::tree_link<0> FirstTLink; typedef etl::tree_link<1> SecondTLink; + typedef etl::tree_link<2> ThirdTLink; struct TData : public FirstTLink, public SecondTLink { @@ -94,6 +106,19 @@ namespace int value; }; + //******************************************************* + // Mixed + //******************************************************* + struct MData : public FirstFLink, public SecondBLink, public ThirdTLink + { + MData(int value) + : value(value) + { + } + + int value; + }; + SUITE(test_forward_list) { //************************************************************************* @@ -137,8 +162,138 @@ namespace CHECK(data2.SecondFLink::etl_next == &data1); CHECK(data1.SecondFLink::etl_next == &data0); CHECK(data0.SecondFLink::etl_next == nullptr); + + FData* pdata; + + pdata = static_cast(data0.FirstFLink::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->FirstFLink::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->FirstFLink::etl_next); + CHECK_EQUAL(3, pdata->value); + + pdata = static_cast(data3.SecondFLink::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->SecondFLink::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->SecondFLink::etl_next); + CHECK_EQUAL(0, pdata->value); } + //************************************************************************* + TEST(test_link_splice_forward_link) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + data0.FirstFLink::clear(); + etl::link_splice(data0, data1); + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == nullptr); + + data0.FirstFLink::clear(); + etl::link_splice(data0, &data1); + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == nullptr); + + data0.FirstFLink::clear(); + etl::link_splice(&data0, data1); + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == nullptr); + + data0.FirstFLink::clear(); + etl::link_splice(&data0, &data1); + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == nullptr); + + data0.FirstFLink::clear(); + etl::link_splice(data0, data3); + etl::link_splice(data0, data1); + etl::link_splice(data1, data2); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data2); + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_link_splice_forward_link_range) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + FData data4(4); + FData data5(5); + FData data6(6); + FData data7(7); + + // First range. + data0.FirstFLink::clear(); + etl::link_splice(data0, data1); + etl::link_splice(data1, data6); + etl::link_splice(data6, data7); + + // Second range. + data2.FirstFLink::clear(); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(data1, data2, data5); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data2); + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == &data4); + CHECK(data4.FirstFLink::etl_next == &data5); + CHECK(data5.FirstFLink::etl_next == &data6); + CHECK(data6.FirstFLink::etl_next == &data7); + CHECK(data7.FirstFLink::etl_next == nullptr); + + // Do it again with a pointer. + // First range. + data0.FirstFLink::clear(); + etl::link_splice(data0, data1); + etl::link_splice(data1, data6); + etl::link_splice(data6, data7); + + // Second range. + data2.FirstFLink::clear(); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(&data1, data2, data5); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data2); + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == &data4); + CHECK(data4.FirstFLink::etl_next == &data5); + CHECK(data5.FirstFLink::etl_next == &data6); + CHECK(data6.FirstFLink::etl_next == &data7); + CHECK(data7.FirstFLink::etl_next == nullptr); + + // Do it again with a nullptr pointer. + // Second range. + data2.FirstFLink::clear(); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(nullptr, data2, data5); + + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == &data4); + CHECK(data4.FirstFLink::etl_next == &data5); + CHECK(data5.FirstFLink::etl_next == nullptr); + } + + //************************************************************************* TEST(test_unlink_after_forward_link) { @@ -194,6 +349,39 @@ namespace CHECK(data0.SecondFLink::etl_next == nullptr); } + //************************************************************************* + TEST(test_unlink_after_range_forward_link) + { + FData data0(0); + FData data1(1); + FData data2(2); + FData data3(3); + + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + etl::unlink_after(data0, data2); + data1.FirstFLink::clear(); + data2.FirstFLink::clear(); + + CHECK(data0.FirstFLink::etl_next == &data3); + CHECK(data1.FirstFLink::etl_next == nullptr); + CHECK(data2.FirstFLink::etl_next == nullptr); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondFLink::etl_next == &data2); + CHECK(data2.SecondFLink::etl_next == &data1); + CHECK(data1.SecondFLink::etl_next == &data0); + CHECK(data0.SecondFLink::etl_next == nullptr); + } + //************************************************************************* TEST(test_self_link_forward_link) { @@ -245,11 +433,12 @@ namespace etl::link(data3, nullptr); CHECK(data0->FirstBLinkAuto::etl_previous == nullptr); - CHECK(data1->FirstBLinkAuto::etl_next == data2); + CHECK(data1->FirstBLinkAuto::etl_previous == data0); + CHECK(data1->FirstBLinkAuto::etl_next == data2); CHECK(data2->FirstBLinkAuto::etl_previous == data1); - CHECK(data2->FirstBLinkAuto::etl_next == data3); + CHECK(data2->FirstBLinkAuto::etl_next == data3); CHECK(data3->FirstBLinkAuto::etl_previous == data2); - CHECK(data3->FirstBLinkAuto::etl_next == nullptr); + CHECK(data3->FirstBLinkAuto::etl_next == nullptr); etl::link(nullptr, data3); etl::link(data3, data2); @@ -266,6 +455,37 @@ namespace CHECK(data0->SecondBLink::etl_previous == data1); CHECK(data0->SecondBLink::etl_next == nullptr); + BDataAuto* pdataauto; + BData* pdata; + + pdataauto = static_cast(data0->FirstBLinkAuto::etl_next); + CHECK_EQUAL(1, pdataauto->value); + pdataauto = static_cast(pdataauto->FirstBLinkAuto::etl_next); + CHECK_EQUAL(2, pdataauto->value); + pdataauto = static_cast(pdataauto->FirstBLinkAuto::etl_next); + CHECK_EQUAL(3, pdataauto->value); + + pdataauto = static_cast(data3->FirstBLinkAuto::etl_previous); + CHECK_EQUAL(2, pdataauto->value); + pdataauto = static_cast(pdataauto->FirstBLinkAuto::etl_previous); + CHECK_EQUAL(1, pdataauto->value); + pdataauto = static_cast(pdataauto->FirstBLinkAuto::etl_previous); + CHECK_EQUAL(0, pdataauto->value); + + pdata = static_cast(data3->SecondBLink::etl_next); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->SecondBLink::etl_next); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->SecondBLink::etl_next); + CHECK_EQUAL(0, pdata->value); + + pdata = static_cast(data0->SecondBLink::etl_previous); + CHECK_EQUAL(1, pdata->value); + pdata = static_cast(pdata->SecondBLink::etl_previous); + CHECK_EQUAL(2, pdata->value); + pdata = static_cast(pdata->SecondBLink::etl_previous); + CHECK_EQUAL(3, pdata->value); + delete data1; CHECK(data0->FirstBLinkAuto::etl_next == data2); CHECK(data2->FirstBLinkAuto::etl_previous == data0); @@ -297,6 +517,181 @@ namespace delete data2; } + //************************************************************************* + TEST(test_link_splice_bidirectional_link) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + + etl::link_splice(data0, data1); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == nullptr); + + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + + etl::link_splice(data0, &data1); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == nullptr); + + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + + etl::link_splice(&data0, data1); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == nullptr); + + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + + etl::link_splice(&data0, &data1); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == nullptr); + + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + etl::link_splice(data0, data3); + etl::link_splice(data0, data1); + etl::link_splice(data1, data2); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == &data2); + CHECK(data2.FirstBLink::etl_previous == &data1); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_link_splice_range_bidirectional_link) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + BData data4(4); + BData data5(5); + BData data6(6); + BData data7(7); + + // Build the first range. + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + etl::link_splice(data0, data1); + etl::link_splice(data1, data6); + etl::link_splice(data6, data7); + + // Build the second range. + data2.FirstBLink::clear(); + etl::link_splice(nullptr, data2); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(data1, data2, data5); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == &data2); + CHECK(data2.FirstBLink::etl_previous == &data1); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == &data4); + CHECK(data4.FirstBLink::etl_previous == &data3); + CHECK(data4.FirstBLink::etl_next == &data5); + CHECK(data5.FirstBLink::etl_previous == &data4); + CHECK(data5.FirstBLink::etl_next == &data6); + CHECK(data6.FirstBLink::etl_previous == &data5); + CHECK(data6.FirstBLink::etl_next == &data7); + CHECK(data7.FirstBLink::etl_previous == &data6); + CHECK(data7.FirstBLink::etl_next == nullptr); + + // Do it again with a pointer parameter. + // Build the first range. + data0.FirstBLink::clear(); + etl::link_splice(nullptr, data0); + etl::link_splice(data0, data1); + etl::link_splice(data1, data6); + etl::link_splice(data6, data7); + + // Build the second range. + data2.FirstBLink::clear(); + etl::link_splice(nullptr, data2); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(&data1, data2, data5); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data1); + CHECK(data1.FirstBLink::etl_previous == &data0); + CHECK(data1.FirstBLink::etl_next == &data2); + CHECK(data2.FirstBLink::etl_previous == &data1); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == &data4); + CHECK(data4.FirstBLink::etl_previous == &data3); + CHECK(data4.FirstBLink::etl_next == &data5); + CHECK(data5.FirstBLink::etl_previous == &data4); + CHECK(data5.FirstBLink::etl_next == &data6); + CHECK(data6.FirstBLink::etl_previous == &data5); + CHECK(data6.FirstBLink::etl_next == &data7); + CHECK(data7.FirstBLink::etl_previous == &data6); + CHECK(data7.FirstBLink::etl_next == nullptr); + + // Do it again with a nullptr parameter. + // Build the range. + data2.FirstBLink::clear(); + etl::link_splice(nullptr, data2); + etl::link_splice(data2, data3); + etl::link_splice(data3, data4); + etl::link_splice(data4, data5); + + etl::link_splice(nullptr, data2, data5); + + CHECK(data2.FirstBLink::etl_previous == nullptr); + CHECK(data2.FirstBLink::etl_next == &data3); + CHECK(data3.FirstBLink::etl_previous == &data2); + CHECK(data3.FirstBLink::etl_next == &data4); + CHECK(data4.FirstBLink::etl_previous == &data3); + CHECK(data4.FirstBLink::etl_next == &data5); + CHECK(data5.FirstBLink::etl_previous == &data4); + CHECK(data5.FirstBLink::etl_next == nullptr); + } + + //************************************************************************* + TEST(test_link_bidirectional_link_checked) + { + // FirstBLinkAuto is auto-unlink + + BDataChecked* data0 = new BDataChecked(0); + BDataChecked* data1 = new BDataChecked(1); + BDataChecked* data2 = new BDataChecked(2); + BDataChecked* data3 = new BDataChecked(3); + + etl::link(nullptr, data0); + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + data2->FirstBLinkChecked::clear(); + CHECK_NO_THROW(delete data2); + } + //************************************************************************* TEST(test_unlink_bidirectional_link) { @@ -402,6 +797,49 @@ namespace CHECK(data0.SecondBLink::etl_next == nullptr); } + //************************************************************************* + TEST(test_unlink_range_bidirectional_link) + { + BData data0(0); + BData data1(1); + BData data2(2); + BData data3(3); + + etl::link(nullptr, data0); + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + etl::link(nullptr, data3); + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + etl::unlink(data1, data2); + data1.FirstBLink::clear(); + data2.FirstBLink::clear(); + + CHECK(data0.FirstBLink::etl_previous == nullptr); + CHECK(data0.FirstBLink::etl_next == &data3); + CHECK(data1.FirstBLink::etl_previous == nullptr); + CHECK(data1.FirstBLink::etl_next == nullptr); + CHECK(data2.FirstBLink::etl_previous == nullptr); + CHECK(data2.FirstBLink::etl_next == nullptr); + CHECK(data3.FirstBLink::etl_previous == &data0); + CHECK(data3.FirstBLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == &data2); + CHECK(data2.SecondBLink::etl_previous == &data3); + CHECK(data2.SecondBLink::etl_next == &data1); + CHECK(data1.SecondBLink::etl_previous == &data2); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + } + //************************************************************************* TEST(test_self_link_bidirectional_link) { @@ -539,5 +977,137 @@ namespace CHECK(data3.SecondTLink::etl_left == nullptr); CHECK(data3.SecondTLink::etl_right == nullptr); } + + //************************************************************************* + TEST(test_is_linked) + { + // Forward link + FData fdata(0); + + fdata.FirstFLink::clear(); + fdata.SecondFLink::clear(); + CHECK(!fdata.FirstFLink::is_linked()); + CHECK(!fdata.SecondFLink::is_linked()); + + etl::link(fdata, fdata); + CHECK(fdata.FirstFLink::is_linked()); + CHECK(!fdata.SecondFLink::is_linked()); + + etl::link(fdata, fdata); + CHECK(fdata.FirstFLink::is_linked()); + CHECK(fdata.SecondFLink::is_linked()); + + // Bidirectional link + BData bdata(0); + + bdata.FirstBLink::clear(); + bdata.SecondBLink::clear(); + CHECK(!bdata.FirstBLink::is_linked()); + CHECK(!bdata.SecondBLink::is_linked()); + + etl::link(bdata, bdata); + CHECK(bdata.FirstBLink::is_linked()); + CHECK(!bdata.SecondBLink::is_linked()); + + etl::link(bdata, bdata); + CHECK(bdata.FirstBLink::is_linked()); + CHECK(bdata.SecondBLink::is_linked()); + + // Tree link + TData tdata(0); + + tdata.FirstTLink::clear(); + tdata.SecondTLink::clear(); + CHECK(!tdata.FirstTLink::is_linked()); + CHECK(!tdata.SecondTLink::is_linked()); + + etl::link_left(tdata, tdata); + CHECK(tdata.FirstTLink::is_linked()); + CHECK(!tdata.SecondTLink::is_linked()); + + etl::link_right(tdata, tdata); + CHECK(tdata.FirstTLink::is_linked()); + CHECK(tdata.SecondTLink::is_linked()); + } + + //************************************************************************* + TEST(test_link_mixed_links) + { + MData data0(0); + MData data1(1); + MData data2(2); + MData data3(3); + MData data4(4); + MData data5(5); + MData data6(6); + + // Forward + data0.FirstFLink::clear(); + etl::link(data0, data1); + etl::link(data1, data2); + etl::link(data2, data3); + etl::link(data3, nullptr); + + // Bidirectional + etl::link(nullptr, data3); + etl::link(data3, data2); + etl::link(data2, data1); + etl::link(data1, data0); + etl::link(data0, nullptr); + + // Tree + data0.ThirdTLink::clear(); + etl::link_left(data0, data1); + etl::link_right(data0, data2); + etl::link_left(data1, data3); + etl::link_right(data1, data4); + etl::link_left(data3, nullptr); + etl::link_right(data3, nullptr); + etl::link_left(data4, nullptr); + etl::link_right(data4, nullptr); + etl::link_left(data2, data5); + etl::link_right(data2, data6); + etl::link_left(data5, nullptr); + etl::link_right(data5, nullptr); + etl::link_left(data6, nullptr); + etl::link_right(data6, nullptr); + + CHECK(data0.FirstFLink::etl_next == &data1); + CHECK(data1.FirstFLink::etl_next == &data2); + CHECK(data2.FirstFLink::etl_next == &data3); + CHECK(data3.FirstFLink::etl_next == nullptr); + + CHECK(data3.SecondBLink::etl_previous == nullptr); + CHECK(data3.SecondBLink::etl_next == &data2); + CHECK(data2.SecondBLink::etl_previous == &data3); + CHECK(data2.SecondBLink::etl_next == &data1); + CHECK(data1.SecondBLink::etl_previous == &data2); + CHECK(data1.SecondBLink::etl_next == &data0); + CHECK(data0.SecondBLink::etl_previous == &data1); + CHECK(data0.SecondBLink::etl_next == nullptr); + + CHECK(data0.ThirdTLink::etl_left == &data1); + CHECK(data0.ThirdTLink::etl_right == &data2); + CHECK(data1.ThirdTLink::etl_parent == &data0); + CHECK(data2.ThirdTLink::etl_parent == &data0); + + CHECK(data1.ThirdTLink::etl_left == &data3); + CHECK(data1.ThirdTLink::etl_right == &data4); + CHECK(data3.ThirdTLink::etl_parent == &data1); + CHECK(data3.ThirdTLink::etl_left == nullptr); + CHECK(data3.ThirdTLink::etl_right == nullptr); + CHECK(data4.ThirdTLink::etl_parent == &data1); + CHECK(data4.ThirdTLink::etl_left == nullptr); + CHECK(data4.ThirdTLink::etl_right == nullptr); + + CHECK(data2.ThirdTLink::etl_left == &data5); + CHECK(data2.ThirdTLink::etl_right == &data6); + CHECK(data5.ThirdTLink::etl_parent == &data2); + CHECK(data5.ThirdTLink::etl_left == nullptr); + CHECK(data5.ThirdTLink::etl_right == nullptr); + CHECK(data6.ThirdTLink::etl_parent == &data2); + CHECK(data6.ThirdTLink::etl_left == nullptr); + CHECK(data6.ThirdTLink::etl_right == nullptr); + } }; } diff --git a/test/test_intrusive_list.cpp b/test/test_intrusive_list.cpp new file mode 100644 index 00000000..048a16a3 --- /dev/null +++ b/test/test_intrusive_list.cpp @@ -0,0 +1,1098 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include +#include "ExtraCheckMacros.h" + +#include "data.h" + +#include "../intrusive_list.h" + +#include +#include +#include +#include +#include + +typedef TestDataDC ItemDC; +typedef TestDataNDC ItemNDC; + +namespace +{ + typedef etl::bidirectional_link<0> FirstLink; + typedef etl::bidirectional_link<1> SecondLink; + + //*************************************************************************** + class ItemDCNode : public FirstLink, public SecondLink + { + public: + + ItemDCNode(const std::string& text) + : data(text) + { + } + + ItemDC data; + }; + + //*************************************************************************** + class ItemNDCNode : public FirstLink, public SecondLink + { + public: + + ItemNDCNode(const std::string& text) + : data(text) + { + } + + bool operator <(const ItemNDCNode& other) const + { + return data < other.data; + } + + bool operator >(const ItemNDCNode& other) const + { + return other.data < data; + } + + ItemNDC data; + }; + + //*************************************************************************** + bool operator ==(const ItemDCNode& lhs, const ItemDCNode& rhs) + { + return lhs.data == rhs.data; + } + + bool operator ==(const ItemNDCNode& lhs, const ItemNDCNode& rhs) + { + return lhs.data == rhs.data; + } + + bool operator !=(const ItemDCNode& lhs, const ItemDCNode& rhs) + { + return lhs.data != rhs.data; + } + + bool operator !=(const ItemNDCNode& lhs, const ItemNDCNode& rhs) + { + return lhs.data != rhs.data; + } + + std::ostream& operator << (std::ostream& os, const ItemNDCNode& node) + { + os << node.data; + return os; + } + + //*************************************************************************** + struct CompareItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data < rhs.data; + } + }; + + struct EqualItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data == rhs.data; + } + }; + + //*************************************************************************** + typedef etl::intrusive_list DataDC0; + typedef etl::intrusive_list DataDC1; + typedef etl::intrusive_list DataNDC0; + typedef etl::intrusive_list DataNDC1; + + typedef std::vector InitialDataNDC; +} + +namespace +{ + SUITE(test_intrusive_list) + { + InitialDataNDC unsorted_data; + InitialDataNDC sorted_data; + InitialDataNDC sorted_data2; + InitialDataNDC non_unique_data; + InitialDataNDC unique_data; + InitialDataNDC small_data; + InitialDataNDC merge_data0; + InitialDataNDC merge_data1; + InitialDataNDC merge_data2; + InitialDataNDC merge_data3; + InitialDataNDC merge_data4; + + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + unsorted_data = { ItemNDCNode("1"), ItemNDCNode("0"), ItemNDCNode("3"), ItemNDCNode("2"), ItemNDCNode("5"), ItemNDCNode("4"), ItemNDCNode("7"), ItemNDCNode("6"), ItemNDCNode("9"), ItemNDCNode("8") }; + sorted_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + sorted_data2 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + non_unique_data = { ItemNDCNode("0"), ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + unique_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + small_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + + merge_data0 = { ItemNDCNode("1"), ItemNDCNode("1"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("5"), ItemNDCNode("7"), ItemNDCNode("8") }; + merge_data1 = { ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("9"), ItemNDCNode("9") }; + merge_data2 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("7") }; + merge_data3 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7") }; + merge_data4 = { ItemNDCNode("0"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataNDC0 data0; + DataNDC1 data1; + + CHECK(data0.empty()); + CHECK(data1.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + CHECK(!data0.empty()); + CHECK_EQUAL(sorted_data.size(), data0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty_begin_end) + { + DataNDC0 data0; + + CHECK(data0.begin() == data0.end()); + + DataNDC0::const_iterator begin = data0.begin(); + DataNDC0::const_iterator end = data0.end(); + CHECK(begin == end); + + CHECK(data0.cbegin() == data0.cend()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + are_equal = std::equal(data0.cbegin(), data0.cend(), sorted_data.begin()); + + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + data0.clear(); + + CHECK(data0.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + bool are_equal; + + DataNDC0 data0; + + // Do it twice. We should only get one copy. + data0.assign(sorted_data.begin(), sorted_data.end()); + data0.assign(sorted_data.begin(), sorted_data.end()); + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range_two_lists_same) + { + bool are_equal; + + DataNDC0 data0; + DataNDC1 data1; + + data0.assign(sorted_data.begin(), sorted_data.end()); + data1.assign(sorted_data.begin(), sorted_data.end()); + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + } + + ////************************************************************************* + TEST_FIXTURE(SetupFixture, test_two_lists_different) + { + bool are_equal; + + std::list compare0; + std::list compare1; + + DataNDC0 data0; + DataNDC1 data1; + + ItemNDCNode node0("0"); + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + ItemNDCNode node7("7"); + + compare0.push_front(node0); + compare0.push_front(node1); + compare0.push_front(node2); + compare0.push_front(node4); + compare0.push_front(node6); + compare0.push_front(node7); + + data0.push_front(node0); + data0.push_front(node1); + data0.push_front(node2); + data0.push_front(node4); + data0.push_front(node6); + data0.push_front(node7); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + CHECK_EQUAL(6, data0.size()); + CHECK_EQUAL(6, std::distance(data0.begin(), data0.end())); + + compare1.push_front(node0); + compare1.push_front(node1); + compare1.push_front(node3); + compare1.push_front(node4); + compare1.push_front(node5); + compare1.push_front(node7); + + data1.push_front(node0); + data1.push_front(node1); + data1.push_front(node3); + data1.push_front(node4); + data1.push_front(node5); + data1.push_front(node7); + + are_equal = std::equal(data1.begin(), data1.end(), compare1.begin()); + CHECK(are_equal); + CHECK_EQUAL(6, data1.size()); + CHECK_EQUAL(6, std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value) + { + bool are_equal; + + ItemNDCNode INSERT_VALUE1 = ItemNDCNode("1"); + ItemNDCNode INSERT_VALUE2 = ItemNDCNode("2"); + + 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()); + + size_t offset = 2; + + DataNDC0::iterator i_data = data0.begin(); + std::advance(i_data, offset); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, offset); + + data0.insert(i_data, INSERT_VALUE1); + compare_data.insert(i_compare_data, INSERT_VALUE1); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + + offset = 0; + + i_data = data0.begin(); + std::advance(i_data, offset); + + i_compare_data = compare_data.begin(); + std::advance(i_compare_data, offset); + + std::vector temp(data0.begin(), data0.end()); + + data0.insert(i_data, INSERT_VALUE2); + compare_data.insert(i_compare_data, INSERT_VALUE2); + + temp.assign(data0.begin(), data0.end()); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + bool are_equal; + + std::vector test1 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4") }; + std::vector test2 = { ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + std::vector compare(test2); + compare.insert(compare.end(), test1.begin(), test1.end()); + + DataNDC0 data0(test1.begin(), test1.end()); + DataNDC1 data1(test1.begin(), test1.end()); + + data0.insert(data0.begin(), test2.begin(), test2.end()); + + are_equal = std::equal(data0.begin(), data0.end(), compare.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), test1.begin()); + CHECK(are_equal); + CHECK_EQUAL(test1.size(), data1.size()); + CHECK_EQUAL(test1.size(), std::distance(data1.begin(), data1.end())); + + compare.assign(test1.begin(), test1.end()); + data0.assign(test1.begin(), test1.end()); + + std::vector::iterator icd = compare.begin(); + DataNDC0::iterator id = data0.begin(); + + std::advance(icd, 3); + std::advance(id, 3); + + compare.insert(icd, test2.begin(), test2.end()); + data0.insert(id, test2.begin(), test2.end()); + + std::vector d(data0.begin(), data0.end()); + std::vector c(compare.begin(), compare.end()); + + are_equal = std::equal(data0.begin(), data0.end(), compare.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), test1.begin()); + CHECK(are_equal); + CHECK_EQUAL(test1.size(), data1.size()); + CHECK_EQUAL(test1.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front) + { + bool are_equal; + + std::list compare_data; + DataNDC0 data0; + + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + + compare_data.push_front(node1); + compare_data.push_front(node2); + compare_data.push_front(node3); + compare_data.push_front(node4); + compare_data.push_front(node5); + compare_data.push_front(node6); + + CHECK_NO_THROW(data0.push_front(node1)); + CHECK_NO_THROW(data0.push_front(node2)); + CHECK_NO_THROW(data0.push_front(node3)); + CHECK_NO_THROW(data0.push_front(node4)); + CHECK_NO_THROW(data0.push_front(node5)); + CHECK_NO_THROW(data0.push_front(node6)); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(6, data0.size()); + CHECK_EQUAL(6, std::distance(data0.begin(), data0.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front_pop_front) + { + DataNDC0 data0; + DataNDC1 data1; + + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + + data0.push_front(node1); + data0.push_front(node2); + data0.push_front(node3); + data0.push_front(node4); + data0.push_front(node5); + data0.push_front(node6); + + data1.push_front(node1); + data1.push_front(node2); + data1.push_front(node3); + data1.push_front(node4); + data1.push_front(node5); + data1.push_front(node6); + + CHECK_EQUAL(6, data0.size()); + CHECK_EQUAL(6, std::distance(data0.begin(), data0.end())); + CHECK(!data0.empty()); + + data0.pop_front(); + data0.pop_front(); + data0.pop_front(); + data0.pop_front(); + data0.pop_front(); + + CHECK_EQUAL(1, data0.size()); + CHECK_EQUAL(1, std::distance(data0.begin(), data0.end())); + CHECK(!data0.empty()); + + data0.pop_front(); + + CHECK_EQUAL(0, data0.size()); + CHECK_EQUAL(0, std::distance(data0.begin(), data0.end())); + CHECK(data0.empty()); + + CHECK_EQUAL(6, data1.size()); + CHECK_EQUAL(6, std::distance(data1.begin(), data1.end())); + CHECK(!data1.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + 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()); + + DataNDC0::iterator i_data = data0.begin(); + std::advance(i_data, 3); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 3); + + i_compare_data = compare_data.erase(i_compare_data); + i_data = data0.erase(i_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK(*i_compare_data == *i_data); + + i_compare_data = compare_data.erase(compare_data.begin()); + i_data = data0.erase(data0.begin()); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + + are_equal = *i_data == *i_compare_data; + CHECK(are_equal); + + // Move to the last value and erase. + i_compare_data = compare_data.begin(); + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data0.begin(); + i_data = data0.erase(i_data); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + + are_equal = *i_data == *i_compare_data; + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + 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()); + + DataNDC0::iterator i_data_1 = data0.begin(); + std::advance(i_data_1, 3); + + DataNDC0::iterator i_data_2 = data0.begin(); + std::advance(i_data_2, 4); + + std::vector::iterator i_compare_data_1 = compare_data.begin(); + std::advance(i_compare_data_1, 3); + + std::vector::iterator i_compare_data_2 = compare_data.begin(); + std::advance(i_compare_data_2, 4); + + std::vector::iterator i_compare_result = compare_data.erase(i_compare_data_1, i_compare_data_2); + + DataNDC0::iterator i_result = data0.erase(i_data_1, i_data_2); + + CHECK_EQUAL(*i_compare_result, *i_result); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_end) + { + 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()); + + DataNDC0::iterator i_data = data0.begin(); + std::advance(i_data, 5); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 5); + + std::vector::iterator i_compare_result = compare_data.erase(i_compare_data, compare_data.end()); + + DataNDC0::iterator i_result = data0.erase(i_data, data0.end()); + + CHECK(i_result == data0.end()); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_all) + { + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + data0.erase(data0.begin(), data0.end()); + + CHECK(data0.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_front) + { + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + CHECK_EQUAL(sorted_data.front(), data0.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_unique) + { + bool are_equal; + + DataNDC0 data0(non_unique_data.begin(), non_unique_data.end()); + DataNDC1 data1(non_unique_data.begin(), non_unique_data.end()); + + data0.unique(EqualItemNDCNode()); + + // data0 should have changed. + are_equal = std::equal(data0.begin(), data0.end(), unique_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(unique_data.size(), data0.size()); + CHECK_EQUAL(unique_data.size(), std::distance(data0.begin(), data0.end())); + + // data1 should not have changed. + are_equal = std::equal(data1.begin(), data1.end(), non_unique_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(non_unique_data.size(), data1.size()); + CHECK_EQUAL(non_unique_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_remove) + { + 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()); + + std::vector::iterator i_item = std::find(compare_data.begin(), compare_data.end(), ItemNDCNode("7")); + compare_data.erase(i_item); + data0.remove(ItemNDCNode("7")); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_remove_if) + { + 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()); + + std::vector::iterator i_item = std::find(compare_data.begin(), compare_data.end(), ItemNDCNode("7")); + compare_data.erase(i_item); + data0.remove_if(std::bind2nd(std::equal_to(), ItemNDCNode("7"))); + + are_equal = std::equal(data0.begin(), data0.end(), compare_data.begin()); + + CHECK(are_equal); + CHECK_EQUAL(compare_data.size(), data0.size()); + CHECK_EQUAL(compare_data.size(), std::distance(data0.begin(), data0.end())); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + CHECK_EQUAL(sorted_data.size(), data1.size()); + CHECK_EQUAL(sorted_data.size(), std::distance(data1.begin(), data1.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC1 data1(sorted_data.begin(), sorted_data.end()); + + data0.reverse(); // Just reverse one of them. + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.rbegin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), sorted_data.begin()); + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_sort) + { + bool are_equal; + + DataNDC0 data0(unsorted_data.begin(), unsorted_data.end()); + DataNDC1 data1(unsorted_data.begin(), unsorted_data.end()); + + data0.sort(); // Just sort one of them. + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), unsorted_data.begin()); + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_sort_compare) + { + bool are_equal; + + DataNDC0 data0(unsorted_data.begin(), unsorted_data.end()); + DataNDC1 data1(unsorted_data.begin(), unsorted_data.end()); + + data0.sort(CompareItemNDCNode()); // Just sort one of them. + + are_equal = std::equal(data0.begin(), data0.end(), sorted_data.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), unsorted_data.begin()); + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_iterator) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC0 data1(unsorted_data.begin(), unsorted_data.end()); + + DataNDC0::iterator idata_source = data1.begin(); + std::advance(idata_source, 2); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + std::list compare0(data0.begin(), data0.end()); + std::list compare1(data1.begin(), data1.end()); + + std::list::iterator icompare_source = compare1.begin(); + std::advance(icompare_source, 2); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + data0.splice(idata_destination, data1, idata_source); + compare0.splice(icompare_destination, compare1, icompare_source); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + are_equal = std::equal(data1.begin(), data1.end(), compare1.begin()); + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_iterator_same_list) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + DataNDC0::iterator idata_source = data0.begin(); + std::advance(idata_source, 2); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 5); + + std::list compare0(data0.begin(), data0.end()); + + std::list::iterator icompare_source = compare0.begin(); + std::advance(icompare_source, 2); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 5); + + data0.splice(idata_destination, data0, idata_source); + compare0.splice(icompare_destination, compare0, icompare_source); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_list) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin() , sorted_data.end()); + DataNDC0 data1(sorted_data2.begin(), sorted_data2.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + std::list compare0(data0.begin(), data0.end()); + std::list compare1(data1.begin(), data1.end()); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + data0.splice(idata_destination, data1); + compare0.splice(icompare_destination, compare1); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data1.size(), compare1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_list_self) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + std::list compare0(data0.begin(), data0.end()); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + data0.splice(idata_destination, data0); + compare0.splice(icompare_destination, compare0); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_range) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + DataNDC0 data1(sorted_data2.begin(), sorted_data2.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 3); + + DataNDC0::iterator idata_begin = data1.begin(); + std::advance(idata_begin, 2); + + DataNDC0::iterator idata_end = data1.begin(); + std::advance(idata_end, 7); + + std::list compare0(data0.begin(), data0.end()); + std::list compare1(data1.begin(), data1.end()); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 3); + + std::list::iterator icompare_begin = compare1.begin(); + std::advance(icompare_begin, 2); + + std::list::iterator icompare_end = compare1.begin(); + std::advance(icompare_end, 7); + + data0.splice(idata_destination, data1, idata_begin, idata_end); + compare0.splice(icompare_destination, compare1, icompare_begin, icompare_end); + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data1.size(), compare1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_splice_range_self) + { + bool are_equal; + + DataNDC0 data0(sorted_data.begin(), sorted_data.end()); + + DataNDC0::iterator idata_destination = data0.begin(); + std::advance(idata_destination, 2); + + DataNDC0::iterator idata_begin = data0.begin(); + std::advance(idata_begin, 4); + + DataNDC0::iterator idata_end = data0.begin(); + std::advance(idata_end, 7); + + std::list compare0(data0.begin(), data0.end()); + + std::list::iterator icompare_destination = compare0.begin(); + std::advance(icompare_destination, 2); + + std::list::iterator icompare_begin = compare0.begin(); + std::advance(icompare_begin, 4); + + std::list::iterator icompare_end = compare0.begin(); + std::advance(icompare_end, 7); + + data0.splice(idata_destination, data0, idata_begin, idata_end); + compare0.splice(icompare_destination, compare0, icompare_begin, icompare_end); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_1) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data1(merge_data1.begin(), merge_data1.end()); + + std::list compare0(merge_data0.begin(), merge_data0.end()); + std::list compare1(merge_data1.begin(), merge_data1.end()); + + data0.merge(data1); + compare0.merge(compare1); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data1.size(), compare1.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_2) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data2(merge_data2.begin(), merge_data2.end()); + + std::list compare0(merge_data0.begin(), merge_data0.end()); + std::list compare2(merge_data2.begin(), merge_data2.end()); + + data0.merge(data2); + compare0.merge(compare2); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data2.size(), compare2.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_3) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data3(merge_data3.begin(), merge_data3.end()); + + std::list compare0(merge_data0.begin(), merge_data0.end()); + std::list compare3(merge_data3.begin(), merge_data3.end()); + + data0.merge(data3); + compare0.merge(compare3); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data3.size(), compare3.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_4) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data4(merge_data4.begin(), merge_data4.end()); + + std::list compare0(merge_data0.begin(), merge_data0.end()); + std::list compare4(merge_data4.begin(), merge_data4.end()); + + data0.merge(data4); + compare0.merge(compare4); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data4.size(), compare4.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_merge_0_1_reverse_order) + { + bool are_equal; + + DataNDC0 data0(merge_data0.begin(), merge_data0.end()); + DataNDC0 data1(merge_data1.begin(), merge_data1.end()); + + data0.reverse(); + data1.reverse(); + + std::list compare0(merge_data0.begin(), merge_data0.end()); + std::list compare1(merge_data1.begin(), merge_data1.end()); + + compare0.reverse(); + compare1.reverse(); + + data0.merge(data1, std::greater()); + compare0.merge(compare1, std::greater()); + + are_equal = std::equal(data0.begin(), data0.end(), compare0.begin()); + CHECK(are_equal); + + CHECK_EQUAL(data0.size(), compare0.size()); + CHECK_EQUAL(data1.size(), compare1.size()); + } + }; +} diff --git a/test/vs2015/etl.sln b/test/vs2015/etl.sln index 476a5ddc..153caf7a 100644 --- a/test/vs2015/etl.sln +++ b/test/vs2015/etl.sln @@ -7,10 +7,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "etl", "etl.vcxproj", "{C21D EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug No Unit Tests|Win32 = Debug No Unit Tests|Win32 Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C21DF78C-D8E0-46AB-9D6F-D38A3C1CB0FB}.Debug No Unit Tests|Win32.ActiveCfg = Debug No Unit Tests|Win32 + {C21DF78C-D8E0-46AB-9D6F-D38A3C1CB0FB}.Debug No Unit Tests|Win32.Build.0 = Debug No Unit Tests|Win32 {C21DF78C-D8E0-46AB-9D6F-D38A3C1CB0FB}.Debug|Win32.ActiveCfg = Debug|Win32 {C21DF78C-D8E0-46AB-9D6F-D38A3C1CB0FB}.Debug|Win32.Build.0 = Debug|Win32 {C21DF78C-D8E0-46AB-9D6F-D38A3C1CB0FB}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/test/vs2015/etl.vcxproj b/test/vs2015/etl.vcxproj index 20ca6e02..0292881a 100644 --- a/test/vs2015/etl.vcxproj +++ b/test/vs2015/etl.vcxproj @@ -160,7 +160,6 @@ - @@ -206,6 +205,7 @@ + @@ -338,6 +338,7 @@ + @@ -369,6 +370,7 @@ + diff --git a/test/vs2015/etl.vcxproj.filters b/test/vs2015/etl.vcxproj.filters index 072f9405..3bd86a0f 100644 --- a/test/vs2015/etl.vcxproj.filters +++ b/test/vs2015/etl.vcxproj.filters @@ -372,9 +372,6 @@ ETL\Maths - - ETL\Maths - ETL\Containers @@ -465,6 +462,9 @@ ETL\Containers + + ETL\Containers + @@ -713,6 +713,12 @@ Source Files + + Source Files + + + Source Files + From b1862b0e399f55f90370b1eae2a9425e1aef7c08 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:06:02 +0000 Subject: [PATCH 7/9] Added intrusive_list and updated intrusive_forward list. Added set of intrusive links. --- intrusive_list.h | 1244 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1244 insertions(+) create mode 100644 intrusive_list.h diff --git a/intrusive_list.h b/intrusive_list.h new file mode 100644 index 00000000..1fcb7954 --- /dev/null +++ b/intrusive_list.h @@ -0,0 +1,1244 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_LIST__ +#define __ETL_INTRUSIVE_LIST__ + +#if WIN32 +#undef min +#endif + +#include +#include +#include +#include + +#include "nullptr.h" +#include "type_traits.h" +#include "exception.h" +#include "error_handler.h" +#include "intrusive_links.h" +#include "static_assert.h" +#include "algorithm.h" + +#undef ETL_FILE +#define ETL_FILE "21" + +namespace etl +{ + //*************************************************************************** + /// Exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_exception : public exception + { + public: + + intrusive_list_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Empty exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_empty : public intrusive_list_exception + { + public: + + intrusive_list_empty(string_type file_name, numeric_type line_number) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:empty", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_iterator_exception : public intrusive_list_exception + { + public: + + intrusive_list_iterator_exception(string_type file_name, numeric_type line_number) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:iterator", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Unsorted exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_unsorted : public intrusive_list_exception + { + public: + + intrusive_list_unsorted(string_type file_name, numeric_type line_number) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:unsorted", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// An intrusive list. + ///\ingroup intrusive_list + ///\note TLink must be a base of TValue. + //*************************************************************************** + template , const size_t COUNT_OPTION = etl::count_option::FAST_COUNT> + class intrusive_list + { + public: + + // Ensure that the link option is compatible with the count option. + STATIC_ASSERT(!((COUNT_OPTION == etl::count_option::FAST_COUNT) && (TLink::OPTION == etl::link_option::AUTO)), "Auto link not compatible with fast count option"); + STATIC_ASSERT(!((COUNT_OPTION == etl::count_option::FAST_COUNT) && (TLink::OPTION == etl::link_option::CHECKED)), "Checked link not compatible with fast count option"); + + typedef intrusive_list list_type; + + // Node typedef. + typedef TLink link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class intrusive_list; + + iterator() + : p_value(nullptr) + { + } + + iterator(value_type& value) + : p_value(&value) + { + } + + iterator(const iterator& other) + : p_value(other.p_value) + { + } + + iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast(p_value->link_type::etl_next); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast(p_value->link_type::etl_next); + return temp; + } + + iterator& operator --() + { + // Read the appropriate 'etl_previous'. + p_value = static_cast(p_value->link_type::etl_previous); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + // Read the appropriate 'etl_previous'. + p_value = static_cast(p_value->link_type::etl_previous); + return temp; + } + + iterator operator =(const iterator& other) + { + p_value = other.p_value; + return *this; + } + + reference operator *() + { + return *p_value; + } + + const_reference operator *() const + { + return *p_value; + } + + pointer operator &() + { + return p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + pointer operator ->() + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + value_type* p_value; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class intrusive_list; + + const_iterator() + : p_value(nullptr) + { + } + + const_iterator(const value_type& value) + : p_value(&value) + { + } + + const_iterator(const typename intrusive_list::iterator& other) + : p_value(other.p_value) + { + } + + const_iterator(const const_iterator& other) + : p_value(other.p_value) + { + } + + const_iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast(p_value->link_type::etl_next); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast(p_value->link_type::etl_next); + return temp; + } + + const_iterator& operator --() + { + // Read the appropriate 'etl_previous'. + p_value = static_cast(p_value->link_type::etl_previous); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + // Read the appropriate 'etl_previous'. + p_value = static_cast(p_value->link_type::etl_previous); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_value = other.p_value; + return *this; + } + + const_reference operator *() const + { + return *p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + const value_type* p_value; + }; + + typedef typename std::iterator_traits::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_list() + { + initialise(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template + intrusive_list(TIterator first, TIterator last) + { + assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + iterator begin() + { + return iterator(static_cast(*get_head())); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(static_cast(*get_head())); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(static_cast(*get_head())); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + iterator end() + { + return iterator(static_cast(terminal_link)); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(static_cast(terminal_link)); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(static_cast(terminal_link)); + } + + //************************************************************************* + /// Clears the intrusive_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + reference front() + { + return *static_cast(get_head()); + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *static_cast(get_head());; + } + + //************************************************************************* + /// Gets a reference to the last element. + //************************************************************************* + reference back() + { + return *static_cast(get_tail()); + } + + //************************************************************************* + /// Gets a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *static_cast(get_tail());; + } + + //************************************************************************* + /// Assigns a range of values to the intrusive_list. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined emits a + /// intrusive_list_iterator_exception if the iterators are reversed. + //************************************************************************* + template + void assign(TIterator first, TIterator last) + { +#ifdef _DEBUG + difference_type count = std::distance(first, last); + ETL_ASSERT(count >= 0, ETL_ERROR(intrusive_list_iterator_exception)); +#endif + + initialise(); + + link_type* p_last_link = &terminal_link; + + // Add all of the elements. + while (first != last) + { + link_type& link = *first++; + etl::link_splice(p_last_link, link); + p_last_link = &link; + ++current_size; + } + } + + //************************************************************************* + /// Pushes a value to the front of the intrusive_list. + //************************************************************************* + void push_front(value_type& value) + { + insert_link(terminal_link, value); + } + + //************************************************************************* + /// Removes a value from the front of the intrusive_list. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); +#endif + remove_link(get_head()); + } + + //************************************************************************* + /// Pushes a value to the back of the intrusive_list. + //************************************************************************* + void push_back(value_type& value) + { + insert_link(terminal_link.link_type::etl_previous, value); + } + + //************************************************************************* + /// Removes a value from the back of the intrusive_list. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); +#endif + remove_link(get_tail()); + } + + //************************************************************************* + /// Reverses the list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + link_type* pnode = terminal_link.etl_next; + + while (pnode != &terminal_link) + { + pnode->reverse(); + pnode = pnode->etl_previous; // Now we've reversed it, we must go to the previous node. + } + + // Terminal node. + pnode->reverse(); + } + + //************************************************************************* + /// Inserts a value to the intrusive_list before the specified position. + //************************************************************************* + template + typename etl::enable_if<(T::OPTION == etl::link_option::DEFAULT) || (T::OPTION == etl::link_option::AUTO), iterator>::type + insert(iterator position, value_type& value) + { + insert_link(position.p_value->link_type::etl_previous, value); + return iterator(value); + } + + //************************************************************************* + /// Inserts a value to the intrusive_list before the specified position. + /// Checks that the value is unlinked. + //************************************************************************* + template + typename etl::enable_if::type + insert(iterator position, value_type& value) + { + ETL_ASSERT(!value.TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception)); + + insert_link(position.p_value->etl_previous, value); + return iterator(value); + } + + //************************************************************************* + /// Inserts a range of values to the intrusive_list before the specified position. + //************************************************************************* + template + typename etl::enable_if<(T::OPTION == etl::link_option::DEFAULT) || (T::OPTION == etl::link_option::AUTO), void>::type + insert(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + // Set up the next free link. + insert_link(*position.p_value->link_type::etl_previous, *first++); + } + } + + //************************************************************************* + /// Inserts a range of values to the intrusive_list after the specified position. + /// Checks that the values are unlinked. + //************************************************************************* + template + typename etl::enable_if::type + insert(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + ETL_ASSERT(!position.p_value->TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception)); + + // Set up the next free link. + insert_link(*position.p_value->link_type::etl_previous, *first++); + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(iterator position) + { + iterator next(position); + ++next; + + remove_link(*position.p_value); + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + template + typename etl::enable_if::type + erase(iterator first, iterator last) + { + link_type* p_first = first.p_value; + link_type* p_last = last.p_value; + + // Join the ends. + etl::link(p_first->etl_previous, p_last); + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + current_size -= std::distance(first, last); + } + + if (p_last == &terminal_link) + { + return end(); + } + else + { + return iterator(*static_cast(p_last)); + } + } + + //************************************************************************* + /// Erases a range of elements. + /// Clears the links after erasing. + //************************************************************************* + template + typename etl::enable_if<(T::OPTION == etl::link_option::AUTO) || (T::OPTION == etl::link_option::CHECKED), iterator>::type + erase(iterator first, iterator last) + { + link_type* p_first = first.p_value; + link_type* p_last = last.p_value; + + // Join the ends. + etl::link(p_first->etl_previous, p_last); + + // Clear the ones in between. + link_type* p_next; + + while (p_first != p_last) + { + // One less. + --current_size; + + p_next = p_first->etl_next; // Remember the next link. + p_first->TLink::clear(); // Clear the link. + p_first = p_next; // Move to the next link. + } + + if (p_last == &terminal_link) + { + return end(); + } + else + { + return iterator(*static_cast(p_last)); + } + } + + //************************************************************************* + /// Removes all but the one element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template + void unique(TIsEqual isEqual) + { + if (empty()) + { + return; + } + + iterator i_item = begin(); + ++i_item; + iterator i_previous = begin(); + + while (i_item != end()) + { + if (isEqual(*i_previous, *i_item)) + { + i_item = erase(i_item); + } + else + { + i_previous = i_item; + ++i_item; + } + } + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + //************************************************************************* + void sort() + { + sort(std::less()); + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses a supplied predicate function or functor. + /// This is not my algorithm. I got it off the web somewhere. + //************************************************************************* + template + void sort(TCompare compare) + { + iterator i_left; + iterator i_right; + iterator i_node; + iterator i_head; + iterator i_tail; + int list_size = 1; + int number_of_merges; + int left_size; + int right_size; + + if (is_trivial_list()) + { + return; + } + + while (true) + { + i_left = begin(); + i_head = end(); + i_tail = end(); + + number_of_merges = 0; // Count the number of merges we do in this pass. + + while (i_left != end()) + { + ++number_of_merges; // There exists a merge to be done. + i_right = i_left; + left_size = 0; + + // Step 'list_size' places along from left + for (int i = 0; i < list_size; ++i) + { + ++left_size; + ++i_right; + + if (i_right == end()) + { + break; + } + } + + // If right hasn't fallen off end, we have two lists to merge. + right_size = list_size; + + // Now we have two lists. Merge them. + while (left_size > 0 || (right_size > 0 && i_right != end())) + { + // Decide whether the next node of merge comes from left or right. + if (left_size == 0) + { + // Left is empty. The node must come from right. + i_node = i_right++; + --right_size; + } + else if (right_size == 0 || i_right == end()) + { + // Right is empty. The node must come from left. + i_node = i_left++; + --left_size; + } + else if (compare(*i_left, *i_right)) + { + // First node of left is lower or same. The node must come from left. + i_node = i_left++; + --left_size; + } + else + { + // First node of right is lower. The node must come from right. + i_node = i_right; + ++i_right; + --right_size; + } + + // Add the next node to the merged head. + if (i_head == end()) + { + etl::link(i_head.p_value, i_node.p_value); + i_head = i_node; + i_tail = i_node; + } + else + { + etl::link(i_tail.p_value, i_node.p_value); + i_tail = i_node; + } + + etl::link(i_tail.p_value, terminal_link); + } + + // Now left has stepped `list_size' places along, and right has too. + i_left = i_right; + } + + // If we have done only one merge, we're finished. + if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case + { + return; + } + + // Otherwise repeat, merging lists twice the size + list_size *= 2; + } + } + + //************************************************************************* + // Removes the values specified. + //************************************************************************* + void remove(const_reference value) + { + iterator i_item = begin(); + + while (i_item != end()) + { + if (*i_item == value) + { + i_item = erase(i_item); + } + else + { + ++i_item; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template + void remove_if(TPredicate predicate) + { + iterator i_item = begin(); + + while (i_item != end()) + { + if (predicate(*i_item)) + { + i_item = erase(i_item); + } + else + { + ++i_item; + } + } + } + + //************************************************************************* + /// Returns true if the list has no elements. + //************************************************************************* + bool empty() const + { + return (terminal_link.link_type::etl_next == &terminal_link); + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + template + typename etl::enable_if::type + size() const + { + return current_size.count; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + template + typename etl::enable_if::type + size() const + { + return std::distance(cbegin(), cend()); + } + + //************************************************************************* + /// Splice another list into this one. + //************************************************************************* + void splice(iterator position, list_type& list) + { + // No point splicing to ourself! + if (&list != this) + { + if (!list.empty()) + { + link_type& first = *list.get_head(); + link_type& last = *list.get_tail(); + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + current_size += list.size(); + } + } + + link_type& after = *position.p_value; + link_type& before = *after.etl_previous; + + etl::link(before, first); + etl::link(last, after); + + list.clear(); + } + } + } + + //************************************************************************* + /// Splice an element from another list into this one. + //************************************************************************* + void splice(iterator position, list_type& list, iterator isource) + { + link_type& before = *position.p_value->link_type::etl_previous; + + etl::unlink(*isource.p_value); + etl::link_splice(before, *isource.p_value); + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + ++current_size; + --list.current_size; + } + } + } + + //************************************************************************* + /// Splice a range of elements from another list into this one. + //************************************************************************* + void splice(iterator position, list_type& list, iterator begin_, iterator end_) + { + if (!list.empty()) + { + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + if (&list != this) + { + size_t n = std::distance(begin_, end_); + current_size += n; + list.current_size -= n; + } + } + + link_type& first = *begin_.p_value; + link_type& last = *end_.p_value->link_type::etl_previous; + + // Unlink from the source list. + etl::unlink(first, last); + + // Fix our links. + link_type& before = *position.p_value->link_type::etl_previous; + + etl::link_splice(before, first, last); + } + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + void merge(list_type& list) + { + merge(list, std::less()); + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + template + void merge(list_type& list, TCompare compare) + { + if (!list.empty()) + { +#if _DEBUG + ETL_ASSERT(etl::is_sorted(list.begin(), list.end(), compare), ETL_ERROR(intrusive_list_unsorted)); + ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_list_unsorted)); +#endif + + value_type* other_begin = static_cast(list.get_head()); + value_type* other_end = static_cast(&list.terminal_link); + + value_type* begin = static_cast(get_head()); + value_type* end = static_cast(&terminal_link); + + while ((begin != end) && (other_begin != other_end)) + { + // Find the place to insert. + while ((begin != end) && !(compare(*other_begin, *begin))) + { + begin = static_cast(begin->link_type::etl_next); + } + + // Insert. + if (begin != end) + { + while ((other_begin != other_end) && (compare(*other_begin, *begin))) + { + value_type* value = other_begin; + other_begin = static_cast(other_begin->link_type::etl_next); + etl::link_splice(*begin->link_type::etl_previous, *value); + } + } + } + + // Any left over? + if ((begin == end) && (other_begin != other_end)) + { + etl::link_splice(*get_tail(), *other_begin, *other_end->link_type::etl_previous); + } + + + if (COUNT_OPTION == etl::count_option::FAST_COUNT) + { + current_size += list.size(); + } + + list.clear(); + } + } + + private: + + /// The link that acts as the intrusive_list start & end. + link_type terminal_link; + + //************************************************************************* + /// Counter type based on count option. + //************************************************************************* + template + class counter_type; + + //************************************************************************* + /// Slow type. + //************************************************************************* + template <> + class counter_type + { + public: + + counter_type& operator ++() + { + return *this; + } + + counter_type& operator --() + { + return *this; + } + + counter_type& operator =(size_t new_count) + { + return *this; + } + + counter_type& operator +=(size_t diff) + { + return *this; + } + + counter_type& operator -=(size_t diff) + { + return *this; + } + }; + + //************************************************************************* + /// Fast type. + //************************************************************************* + template <> + class counter_type + { + public: + + counter_type() + : count(0) + { + } + + counter_type& operator ++() + { + ++count; + return *this; + } + + counter_type& operator --() + { + --count; + return *this; + } + + counter_type& operator =(size_t new_count) + { + count = new_count; + return *this; + } + + counter_type& operator +=(size_t diff) + { + count += diff; + return *this; + } + + counter_type& operator -=(size_t diff) + { + count -= diff; + return *this; + } + + size_t count; + }; + + counter_type current_size; ///< Counts the number of elements in the list. + + //************************************************************************* + /// Is the intrusive_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link); + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type& previous, link_type& new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type& new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type& previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type& link) + { + etl::unlink(link); + --current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type* link) + { + etl::unlink(*link); + --current_size; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + link_type* get_head() + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + const link_type* get_head() const + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + link_type* get_tail() + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + const link_type* get_tail() const + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Initialise the intrusive_list. + //************************************************************************* + void initialise() + { + etl::link(terminal_link, terminal_link); + current_size = 0; + } + + // Disabled. + intrusive_list(const intrusive_list& other); + intrusive_list& operator = (const intrusive_list& rhs); + }; +} + +#if WIN32 +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif From 8d9509d3a708a56645f8d61fd00ee246250af6d0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:06:53 +0000 Subject: [PATCH 8/9] Created new project icon --- etl.png | Bin 0 -> 555 bytes etl.pspimage | Bin 0 -> 11544 bytes favicon.ico | Bin 5686 -> 3262 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 etl.png create mode 100644 etl.pspimage diff --git a/etl.png b/etl.png new file mode 100644 index 0000000000000000000000000000000000000000..39882ffb7e354614867757fbcb947e78dc408f01 GIT binary patch literal 555 zcmV+`0@VG9P)00007bV*G`2jBt+ z4HO-C_wpnF000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP0005HNklab+NYGl&7nvTy)lPy%u_nE+OU46x_^1g%<- z#GnBjiDQ89M{5NLvz`FfaKhjPoKl7W@GEp0T!1(q2k;npKr$H(pbaD-m&pU*3=E)< z#t9${WFfr~{HKOgBK)PyytY z$ew_*VGcmSU;rS0>|AkRlm;Lvg^uz9gr(3?JV0Iw9mN0|l|o0^08LAwqy7mn{UvmT zoA?UL=oS9RuJ9<~S(j8z0N~c80f5!Lci9xMnqDb6LpwmSRPReY*TUk$&t)(5tqn;4 zm`=R0r2^oI#9NCJfGLG|bJq{BPA=YF=L`rS7b`yC;0#qjAy$0E#2Lzfa;*4}&;Pt+ zokV=hN*K1x@i-VRKIpa@_A$BVoPGe#a16*j=X3>F4XOn|2`H518QB$(tBf8t0FW$> t8#4?L*GCM{04C};V08Zh%-g01d;z_Ad46@rc@+Qv002ovPDHLkV1f+6+ob>i literal 0 HcmV?d00001 diff --git a/etl.pspimage b/etl.pspimage new file mode 100644 index 0000000000000000000000000000000000000000..a5329e63b7d3ef3fa5a4a7f010343d07226fd1e3 GIT binary patch literal 11544 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 AH~;_u literal 0 HcmV?d00001 diff --git a/favicon.ico b/favicon.ico index 0b1fcbe38d7b7161068e9d7b8af134ca255a380b..1a20e372e2e939404971ad3e3f4918e697113826 100644 GIT binary patch literal 3262 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 J4e&pk{scq|3grL* From fd8815bb45362dd9ed877755e6b8bf342b3ca3ce Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 10 Feb 2016 19:07:31 +0000 Subject: [PATCH 9/9] Added missing reference return to = operator. --- ideque.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ideque.h b/ideque.h index ce29cf59..935bb4ef 100644 --- a/ideque.h +++ b/ideque.h @@ -116,7 +116,7 @@ namespace etl } //*************************************************** - iterator operator +=(difference_type offset) + iterator& operator +=(difference_type offset) { if (offset > 0) { @@ -132,7 +132,7 @@ namespace etl } //*************************************************** - iterator operator -=(difference_type offset) + iterator& operator -=(difference_type offset) { if (offset > 0) { @@ -310,7 +310,7 @@ namespace etl } //*************************************************** - const_iterator operator +=(difference_type offset) + const_iterator& operator +=(difference_type offset) { if (offset > 0) { @@ -326,7 +326,7 @@ namespace etl } //*************************************************** - const_iterator operator -=(difference_type offset) + const_iterator& operator -=(difference_type offset) { if (offset > 0) {