diff --git a/basic_intrusive_forward_list.h b/basic_intrusive_forward_list.h new file mode 100644 index 00000000..66bce0a6 --- /dev/null +++ b/basic_intrusive_forward_list.h @@ -0,0 +1,577 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +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. +******************************************************************************/ + +//***************************************************************************** +// This forward list is intended for internal library use. +// It may be used as a very low cost intrusive forward list. +// Elements in the list are accessed as basic_intrusive_forward_list_node. +// Code using this list will be required to cast to the real data type. +// etl::basic_intrusive_forward_list will throw no exceptions or errors. +//***************************************************************************** + +#ifndef __ETL_BASIC_INTRUSIVE_FORWARD_LIST__ +#define __ETL_BASIC_INTRUSIVE_FORWARD_LIST__ + +#include +#include + +#include "nullptr.h" +#include "type_traits.h" +#include "basic_intrusive_forward_list_node.h" + +namespace etl +{ + //*************************************************************************** + /// An intrusive forward list. + ///\ingroup basic_intrusive_forward_list + //*************************************************************************** + class basic_intrusive_forward_list + { + public: + + // Node typedef. + typedef basic_intrusive_forward_list_node node_t; + + // STL style typedefs. + typedef node_t value_type; + typedef node_t* pointer; + typedef const node_t* const_pointer; + typedef node_t& reference; + typedef const node_t& const_reference; + typedef size_t size_type; + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class basic_intrusive_forward_list; + + iterator() + : p_node(nullptr) + { + } + + iterator(node_t& node) + : p_node(&node) + { + } + + iterator(const iterator& other) + : p_node(other.p_node) + { + } + + iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_node = p_node->next; + return temp; + } + + iterator operator =(const iterator& other) + { + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return *p_node; + } + + const_reference operator *() const + { + return *p_node; + } + + pointer operator &() + { + return p_node; + } + + const_pointer operator &() const + { + return p_node; + } + + pointer operator ->() + { + return p_node; + } + + const_pointer operator ->() const + { + return p_node; + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + template + T& ref_cast() + { + return static_cast(*p_node); + } + + template + const T& ref_cast() const + { + return static_cast(*p_node); + } + + private: + + node_t* p_node; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class basic_intrusive_forward_list; + + const_iterator() + : p_node(nullptr) + { + } + + const_iterator(node_t& node) + : p_node(&node) + { + } + + const_iterator(const node_t& node) + : p_node(&node) + { + } + + const_iterator(const basic_intrusive_forward_list::iterator& other) + : p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_node(other.p_node) + { + } + + const_iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_node = p_node->next; + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return *p_node; + } + + const_pointer operator &() const + { + return p_node; + } + + const_pointer operator ->() const + { + return p_node; + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + template + const T& ref_cast() const + { + return static_cast(*p_node); + } + + private: + + const node_t* p_node; + }; + + typedef std::iterator_traits::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + basic_intrusive_forward_list() + { + initialise(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template + basic_intrusive_forward_list(TIterator first, TIterator last) + { + assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + iterator begin() + { + return iterator(get_head()); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets before the beginning of the basic_intrusive_forward_list. + //************************************************************************* + iterator before_begin() + { + return iterator(start_node); + } + + //************************************************************************* + /// Gets before the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator before_begin() const + { + return const_iterator(start_node); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + iterator end() + { + return iterator(); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(); + } + + //************************************************************************* + /// Clears the basic_intrusive_forward_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + template + T& front() + { + return static_cast(get_head()); + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + template + const_reference front() const + { + return static_cast(get_head()); + } + + //************************************************************************* + /// Assigns a range of values to the basic_intrusive_forward_list. + //************************************************************************* + template + void assign(TIterator first, TIterator last) + { + initialise(); + + node_t* p_last_node = &start_node; + + // Add all of the elements. + while (first != last) + { + node_t& node = *first++; + join(p_last_node, &node); + join(&node, nullptr); + p_last_node = &node; + } + } + + //************************************************************************* + /// Pushes a value to the front of the basic_intrusive_forward_list. + //************************************************************************* + void push_front(node_t& value) + { + insert_node_after(start_node, value); + } + + //************************************************************************* + /// Removes a value from the front of the basic_intrusive_forward_list. + //************************************************************************* + void pop_front() + { + if (!empty()) + { + remove_node_after(start_node); + } + } + + //************************************************************************* + /// Reverses the basic_intrusive_forward_list. + //************************************************************************* + void reverse() + { + if ((start_node.next == nullptr) || (start_node.next->next == nullptr)) + { + return; + } + + node_t* first = nullptr; // To keep first node + node_t* second = start_node.next; // To keep second node + node_t* track = start_node.next; // Track the list + + while (track != NULL) + { + track = track->next; // Track point to next node; + second->next = first; // Second node point to first + first = second; // Move first node to next + second = track; // Move second node to next + } + + join(&start_node, first); + } + + //************************************************************************* + /// Inserts a value to the basic_intrusive_forward_list after the specified position. + //************************************************************************* + iterator insert_after(iterator position, node_t& value) + { + insert_node_after(*position.p_node, value); + + return iterator(value); + } + + //************************************************************************* + /// Inserts a range of values to the basic_intrusive_forward_list after the specified position. + //************************************************************************* + template + void insert_after(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + // Set up the next free node. + insert_node_after(*position.p_node, *first++); + ++position; + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase_after(iterator position) + { + iterator next(position); + ++next; + ++next; + + remove_node_after(*position.p_node); + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase_after(iterator first, iterator last) + { + node_t* p_first = first.p_node; + node_t* p_last = last.p_node; + node_t* p_next = p_first->next; + + // Join the ends. + join(p_first, p_last); + + p_first = p_next; + + // Erase the ones in between. + while (p_first != p_last) + { + p_next = p_first->next; // Remember the next node. + p_first = p_next; // Move to the next node. + } + + if (p_next == nullptr) + { + return end(); + } + else + { + return iterator(*p_last); + } + } + + //************************************************************************* + /// Returns true if the list has no elements. + //************************************************************************* + bool empty() const + { + return start_node.next == nullptr; + } + + private: + + node_t start_node; ///< The node that acts as the basic_intrusive_forward_list start. + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(node_t* left, node_t* right) + { + left->next = right; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + void insert_node_after(node_t& position, node_t& node) + { + // Connect to the basic_intrusive_forward_list. + join(&node, position.next); + join(&position, &node); + } + + //************************************************************************* + /// Remove a node. + //************************************************************************* + void remove_node_after(node_t& node) + { + // The node to erase. + node_t* p_node = node.next; + + if (p_node != nullptr) + { + // Disconnect the node from the basic_intrusive_forward_list. + join(&node, p_node->next); + } + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + node_t& get_head() + { + return *start_node.next; + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const node_t& get_head() const + { + return *start_node.next; + } + + //************************************************************************* + /// Initialise the basic_intrusive_forward_list. + //************************************************************************* + void initialise() + { + start_node.next = nullptr; + } + + // Disabled. + basic_intrusive_forward_list(const basic_intrusive_forward_list& other); + basic_intrusive_forward_list& operator = (const basic_intrusive_forward_list& rhs); + }; +} + +#endif diff --git a/basic_intrusive_forward_list_node.h b/basic_intrusive_forward_list_node.h new file mode 100644 index 00000000..2de530cd --- /dev/null +++ b/basic_intrusive_forward_list_node.h @@ -0,0 +1,45 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +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. +******************************************************************************/ + +#ifndef __ETL_BASIC_INTRUSIVE_FORWARD_LIST_NODE__ +#define __ETL_BASIC_INTRUSIVE_FORWARD_LIST_NODE__ + +namespace etl +{ + //*************************************************************************** + /// The node element in the basic_intrusive_forward_list. + /// Derive intrusive node data elements from this. + //*************************************************************************** + struct basic_intrusive_forward_list_node + { + basic_intrusive_forward_list_node* next; + }; +} + +#endif diff --git a/intrusive_forward_list.h b/intrusive_forward_list.h index c7f0d6c7..f6875116 100644 --- a/intrusive_forward_list.h +++ b/intrusive_forward_list.h @@ -41,7 +41,7 @@ SOFTWARE. #include "nullptr.h" #include "type_traits.h" -#include "array.h" +#include "intrusive_forward_list_node.h" namespace etl { @@ -87,66 +87,6 @@ namespace etl } }; - namespace __private_intrusive_forward_list__ - { - //*************************************************************************** - /// The node element in the intrusive_forward_list. - //*************************************************************************** - class intrusive_forward_list_node_base - { - public: - - virtual intrusive_forward_list_node_base* get_next(size_t index) const - { - return base_next; - } - - virtual void set_next(size_t index, intrusive_forward_list_node_base* pnext) - { - base_next = pnext; - } - - private: - - intrusive_forward_list_node_base* base_next; - }; - } - - //*************************************************************************** - /// The node element in the intrusive_forward_list. - //*************************************************************************** - template - struct intrusive_forward_list_node : public __private_intrusive_forward_list__::intrusive_forward_list_node_base - { - public: - - __private_intrusive_forward_list__::intrusive_forward_list_node_base* get_next(size_t index) const - { -#ifdef _DEBUG - if (index >= SIZE) - { - ETL_ERROR(intrusive_forward_list_index_exception()); - } -#endif - return next[index]; - } - - void set_next(size_t index, __private_intrusive_forward_list__::intrusive_forward_list_node_base* pnext) - { -#ifdef _DEBUG - if (index >= SIZE) - { - ETL_ERROR(intrusive_forward_list_index_exception()); - } -#endif - next[index] = pnext; - } - - private: - - etl::array<__private_intrusive_forward_list__::intrusive_forward_list_node_base*, SIZE> next; - }; - //*************************************************************************** /// An intrusive forward list. ///\ingroup intrusive_forward_list @@ -518,23 +458,20 @@ namespace etl { return; } - - node_t* p_last = &start_node; - node_t* p_current = p_last->get_next(index); - node_t* p_next = p_current->get_next(index); - p_current->set_next(index, nullptr); + node_t* first = nullptr; // To keep first node + node_t* second = start_node.get_next(index); // To keep second node + node_t* track = start_node.get_next(index); // Track the list - while (p_next != nullptr) + while (track != NULL) { - p_last = p_current; - p_current = p_next; - p_next = p_current->get_next(index); - - p_current->set_next(index, p_last); + track = track->get_next(index); // Track point to next node; + second->set_next(index, first); // Second node point to first + first = second; // Move first node to next + second = track; // Move second node to next } - join(&start_node, p_current); + join(&start_node, first); } //************************************************************************* diff --git a/intrusive_forward_list_node.h b/intrusive_forward_list_node.h new file mode 100644 index 00000000..052f83a2 --- /dev/null +++ b/intrusive_forward_list_node.h @@ -0,0 +1,99 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +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. +******************************************************************************/ + +#ifndef __ETL_INTRUSIVE_FORWARD_LIST_NODE__ +#define __ETL_INTRUSIVE_FORWARD_LIST_NODE__ + +#include "error_handler.h" +#include "array.h" + +namespace etl +{ + namespace __private_intrusive_forward_list__ + { + //*************************************************************************** + /// The node element in the intrusive_forward_list. + //*************************************************************************** + class intrusive_forward_list_node_base + { + public: + + virtual intrusive_forward_list_node_base* get_next(size_t index) const + { + return base_next; + } + + virtual void set_next(size_t index, intrusive_forward_list_node_base* pnext) + { + base_next = pnext; + } + + private: + + intrusive_forward_list_node_base* base_next; + }; + } + + //*************************************************************************** + /// The node element in the intrusive_forward_list. + //*************************************************************************** + template + struct intrusive_forward_list_node : public __private_intrusive_forward_list__::intrusive_forward_list_node_base + { + public: + + __private_intrusive_forward_list__::intrusive_forward_list_node_base* get_next(size_t index) const + { +#ifdef _DEBUG + if (index >= SIZE) + { + ETL_ERROR(intrusive_forward_list_index_exception()); + } +#endif + return next[index]; + } + + void set_next(size_t index, __private_intrusive_forward_list__::intrusive_forward_list_node_base* pnext) + { +#ifdef _DEBUG + if (index >= SIZE) + { + ETL_ERROR(intrusive_forward_list_index_exception()); + } +#endif + next[index] = pnext; + } + + private: + + etl::array<__private_intrusive_forward_list__::intrusive_forward_list_node_base*, SIZE> next; + }; +} + +#endif diff --git a/test/test_basic_intrusive_forward_list.cpp b/test/test_basic_intrusive_forward_list.cpp new file mode 100644 index 00000000..30ee12d1 --- /dev/null +++ b/test/test_basic_intrusive_forward_list.cpp @@ -0,0 +1,582 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +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 "../basic_intrusive_forward_list.h" + +#include +#include +#include +#include +#include +#include + +typedef TestDataDC ItemDC; +typedef TestDataNDC ItemNDC; + +namespace +{ + class ItemDCNode : public etl::basic_intrusive_forward_list_node + { + public: + + ItemDCNode(const std::string& text) + : data(text) + { + } + + ItemDC data; + }; + + class ItemNDCNode : public etl::basic_intrusive_forward_list_node + { + public: + + ItemNDCNode(const std::string& text) + : data(text) + { + } + + bool operator <(const ItemNDCNode& other) const + { + return data < other.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; + } + + 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; + } + }; +} + +namespace +{ + SUITE(test_forward_list) + { + typedef etl::basic_intrusive_forward_list DataDC; + typedef etl::basic_intrusive_forward_list DataNDC; + + typedef std::vector InitialDataNDC; + + InitialDataNDC unsorted_data; + InitialDataNDC sorted_data; + InitialDataNDC non_unique_data; + InitialDataNDC unique_data; + InitialDataNDC small_data; + + bool are_equal; + + //************************************************************************* + 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") }; + 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") }; + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataNDC data; + DataNDC data1; + + CHECK(data.empty()); + CHECK(data1.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + CHECK(!data.empty()); + } + + ////************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::iterator isorted = sorted_data.begin(); + DataNDC::iterator idata = data.begin(); + + while (isorted != sorted_data.end()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + ////************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::const_iterator isorted = sorted_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + data.clear(); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + DataNDC data; + + // Do it twice. We should only get one copy. + data.assign(sorted_data.begin(), sorted_data.end()); + data.assign(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::const_iterator isorted = sorted_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_after_position_value) + { + ItemNDCNode INSERT_VALUE1 = ItemNDCNode("1"); + ItemNDCNode INSERT_VALUE2 = ItemNDCNode("2"); + + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + size_t offset = 2; + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, offset); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, offset + 1); + + data.insert_after(i_data, INSERT_VALUE1); + compare_data.insert(i_compare_data, INSERT_VALUE1); + + InitialDataNDC::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_after_range) + { + 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()); + + size_t final_size = test1.size() + test2.size(); + + DataNDC data(test1.begin(), test1.end()); + + data.insert_after(data.before_begin(), test2.begin(), test2.end()); + + InitialDataNDC::const_iterator icompare = compare.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(final_size, std::distance(data.begin(), data.end())); + + compare.assign(test1.begin(), test1.end()); + data.assign(test1.begin(), test1.end()); + + std::vector::iterator icd = compare.begin(); + DataNDC::iterator id = data.begin(); + + std::advance(icd, 4); + std::advance(id, 3); + + compare.insert(icd, test2.begin(), test2.end()); + data.insert_after(id, test2.begin(), test2.end()); + + icompare = compare.cbegin(); + idata = data.cbegin(); + + while (icompare != compare.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(final_size, std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front) + { + std::list compare_data; + DataNDC data; + + 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); + + data.push_front(node1); + data.push_front(node2); + data.push_front(node3); + data.push_front(node4); + data.push_front(node5); + data.push_front(node6); + + std::list::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + CHECK_EQUAL(6, std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front_pop_front) + { + DataNDC data; + + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + + data.push_front(node1); + data.push_front(node2); + data.push_front(node3); + data.push_front(node4); + data.push_front(node5); + data.push_front(node6); + + CHECK_EQUAL(6, std::distance(data.begin(), data.end())); + CHECK(!data.empty()); + + data.pop_front(); + data.pop_front(); + data.pop_front(); + data.pop_front(); + data.pop_front(); + + CHECK_EQUAL(1, std::distance(data.begin(), data.end())); + CHECK(!data.empty()); + + data.pop_front(); + + CHECK_EQUAL(0, std::distance(data.begin(), data.end())); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_single) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, 2); + + 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 = data.erase_after(i_data); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK(*i_compare_data == i_data.ref_cast()); + + i_compare_data = compare_data.erase(compare_data.begin() + 1); + i_data = data.erase_after(data.begin()); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + + // Move to the last value and erase. + i_compare_data = compare_data.begin() + 1; + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data.begin(); + i_data = data.erase_after(i_data); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_range) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data_1 = data.begin(); + std::advance(i_data_1, 2); + + DataNDC::iterator i_data_2 = data.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); + + DataNDC::iterator i_result = data.erase_after(i_data_1, i_data_2); + + CHECK_EQUAL(*i_compare_result, i_result.ref_cast()); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_range_end) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, 4); + + 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()); + + DataNDC::iterator i_result = data.erase_after(i_data, data.end()); + + CHECK(i_result == data.end()); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_all) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + data.erase_after(data.before_begin(), data.end()); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_front) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + CHECK_EQUAL(sorted_data.front(), data.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + data.reverse(); + + InitialDataNDC::const_reverse_iterator isorted = sorted_data.crbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.crend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + }; +} diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index c389c660..a8472c16 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -41,69 +41,71 @@ SOFTWARE. typedef TestDataDC ItemDC; typedef TestDataNDC ItemNDC; - -class ItemDCNode : public etl::intrusive_forward_list_node<2> +namespace { -public: - - ItemDCNode(const std::string& text) - : data(text) + class ItemDCNode : public etl::intrusive_forward_list_node<2> { - } + public: - ItemDC data; -}; + ItemDCNode(const std::string& text) + : data(text) + { + } -const size_t INDEXES = 2; + ItemDC data; + }; -class ItemNDCNode : public etl::intrusive_forward_list_node -{ -public: + const size_t INDEXES = 2; - ItemNDCNode(const std::string& text) - : data(text) + class ItemNDCNode : public etl::intrusive_forward_list_node { - } + public: - bool operator <(const ItemNDCNode& other) const - { - return data < other.data; - } + ItemNDCNode(const std::string& text) + : data(text) + { + } - ItemNDC data; -}; + bool operator <(const ItemNDCNode& other) const + { + return data < other.data; + } -bool operator ==(const ItemDCNode& lhs, const ItemDCNode& rhs) -{ - return lhs.data == rhs.data; -} + ItemNDC 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 + 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; + } + }; +} namespace {