diff --git a/intrusive_forward_list.h b/intrusive_forward_list.h new file mode 100644 index 00000000..c7f0d6c7 --- /dev/null +++ b/intrusive_forward_list.h @@ -0,0 +1,914 @@ +///\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__ +#define __ETL_INTRUSIVE_FORWARD_LIST__ + +#if WIN32 +#undef min +#endif + +#include +#include +#include +#include + +#include "nullptr.h" +#include "type_traits.h" +#include "array.h" + +namespace etl +{ + //*************************************************************************** + /// Exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_exception : public exception + { + public: + + intrusive_forward_list_exception(const char* what) + : exception(what) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_iterator_exception : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_iterator_exception() + : intrusive_forward_list_exception("intrusive_forward_list: iterator problem") + { + } + }; + + //*************************************************************************** + /// Index exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_index_exception : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_index_exception() + : intrusive_forward_list_exception("intrusive_forward_list: index out of bounds") + { + } + }; + + 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 + //*************************************************************************** + template + class intrusive_forward_list + { + public: + + // Node typedef. + typedef __private_intrusive_forward_list__::intrusive_forward_list_node_base node_t; + + // STL style typedefs. + typedef TValue value_type; + typedef TValue* pointer; + typedef const TValue* const_pointer; + typedef TValue& reference; + typedef const TValue& const_reference; + typedef size_t size_type; + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class intrusive_forward_list; + + iterator() + : p_node(nullptr), + index(0) + { + } + + iterator(node_t& node, size_t index) + : p_node(&node), + index(index) + { + } + + iterator(const iterator& other) + : p_node(other.p_node), + index(other.index) + { + } + + iterator& operator ++() + { + p_node = p_node->get_next(index); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_node = p_node->get_next(index); + return temp; + } + + iterator operator =(const iterator& other) + { + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return static_cast(*p_node); + } + + const_reference operator *() const + { + return static_cast(*p_node); + } + + pointer operator &() + { + return static_cast(p_node); + } + + const_pointer operator &() const + { + return static_cast(p_node); + } + + pointer operator ->() + { + return static_cast(p_node); + } + + const_pointer operator ->() const + { + return static_cast(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); + } + + private: + + node_t* p_node; + size_t index; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class intrusive_forward_list; + + const_iterator() + : p_node(nullptr), + index(0) + { + } + + const_iterator(node_t& node, size_t index) + : p_node(&node), + index(index) + { + } + + const_iterator(const node_t& node, size_t index) + : p_node(&node), + index(index) + { + } + + const_iterator(const typename intrusive_forward_list::iterator& other) + : p_node(other.p_node), + index(other.index) + { + } + + const_iterator(const const_iterator& other) + : p_node(other.p_node), + index(other.index) + { + } + + const_iterator& operator ++() + { + p_node = p_node->get_next(index); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_node = p_node->get_next(index); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return static_cast(*p_node); + } + + const_pointer operator &() const + { + return static_cast(p_node); + } + + const_pointer operator ->() const + { + return static_cast(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); + } + + private: + + const node_t* p_node; + size_t index; + }; + + typedef typename std::iterator_traits::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_forward_list(size_t index) + : index(index) + { + initialise(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template + intrusive_forward_list(size_t index, TIterator first, TIterator last) + : index(index) + { + assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + iterator begin() + { + return iterator(get_head(), index); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(get_head(), index); + } + + //************************************************************************* + /// Gets before the beginning of the intrusive_forward_list. + //************************************************************************* + iterator before_begin() + { + return iterator(start_node, index); + } + + //************************************************************************* + /// Gets before the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator before_begin() const + { + return const_iterator(start_node, index); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(get_head(), index); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + iterator end() + { + return iterator(); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(); + } + + //************************************************************************* + /// Clears the intrusive_forward_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 get_head(); + } + + //************************************************************************* + /// Assigns a range of values to the intrusive_forward_list. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined throws forward_list_iterator if the iterators are reversed. + //************************************************************************* + template + void assign(TIterator first, TIterator last) + { +#ifdef _DEBUG + difference_type count = std::distance(first, last); + + if (count < 0) + { + ETL_ERROR(intrusive_forward_list_iterator_exception()); + } +#endif + + 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; + ++current_size; + } + } + + //************************************************************************* + /// Pushes a value to the front of the intrusive_forward_list. + //************************************************************************* + void push_front(node_t& value) + { + insert_node_after(start_node, value); + } + + //************************************************************************* + /// Removes a value from the front of the intrusive_forward_list. + //************************************************************************* + void pop_front() + { + if (!empty()) + { + remove_node_after(start_node); + } + } + + //************************************************************************* + /// Reverses the intrusive_forward_list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + 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); + + while (p_next != nullptr) + { + p_last = p_current; + p_current = p_next; + p_next = p_current->get_next(index); + + p_current->set_next(index, p_last); + } + + join(&start_node, p_current); + } + + //************************************************************************* + /// Inserts a value to the 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, index); + } + + //************************************************************************* + /// Inserts a range of values to the 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->get_next(index); + + // Join the ends. + join(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->get_next(index); // Remember the next node. + p_first = p_next; // Move to the next node. + } + + if (p_next == nullptr) + { + return end(); + } + else + { + return iterator(*p_last, index); + } + } + + //************************************************************************* + /// Removes all but the one element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template + void unique(TIsEqual isEqual) + { + if (empty()) + { + return; + } + + node_t* last = &get_head(); + node_t* current = last->get_next(index); + + while (current != nullptr) + { + // Is this value the same as the last? + if (isEqual(static_cast(*current), static_cast(*last))) + { + remove_node_after(*last); + } + else + { + // Move on one. + last = current; + } + + current = last->get_next(index); + } + } + + //************************************************************************* + /// 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 = before_begin(); + i_tail = before_begin(); + + 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; + ++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; + ++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; + ++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 == before_begin()) + { + join(i_head.p_node, i_node.p_node); + i_head = i_node; + i_tail = i_node; + } + else + { + join(i_tail.p_node, i_node.p_node); + i_tail = i_node; + } + + i_tail.p_node->set_next(index, nullptr); + } + + // 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(node_t& value) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (static_cast(*i_item) == static_cast(value)) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template + void remove_if(TPredicate predicate) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (predicate(*i_item)) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Returns true if the list has not elements. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + private: + + node_t start_node; ///< The node 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 node that this list operates on. + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(node_t* left, node_t* right) + { + left->set_next(index, right); + } + + //************************************************************************* + /// Is the intrusive_forward_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return current_size <= 1; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + void insert_node_after(node_t& position, node_t& node) + { + // Connect to the intrusive_forward_list. + join(&node, position.get_next(index)); + join(&position, &node); + ++current_size; + } + + //************************************************************************* + /// Remove a node. + //************************************************************************* + void remove_node_after(node_t& node) + { + // The node to erase. + node_t* p_node = node.get_next(index); + + if (p_node != nullptr) + { + // Disconnect the node from the intrusive_forward_list. + join(&node, p_node->get_next(index)); + --current_size; + } + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + node_t& get_head() + { + return *start_node.get_next(index); + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const node_t& get_head() const + { + return *start_node.get_next(index); + } + + //************************************************************************* + /// Initialise the intrusive_forward_list. + //************************************************************************* + void initialise() + { + start_node.set_next(index, nullptr); + current_size = 0; + } + + // Disabled. + intrusive_forward_list(const intrusive_forward_list& other); + intrusive_forward_list& operator = (const intrusive_forward_list& rhs); + }; +} + +#if WIN32 +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp new file mode 100644 index 00000000..c389c660 --- /dev/null +++ b/test/test_intrusive_forward_list.cpp @@ -0,0 +1,715 @@ +/****************************************************************************** +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 "../intrusive_forward_list.h" + +#include +#include +#include +#include +#include +#include + +typedef TestDataDC ItemDC; +typedef TestDataNDC ItemNDC; + +class ItemDCNode : public etl::intrusive_forward_list_node<2> +{ +public: + + ItemDCNode(const std::string& text) + : data(text) + { + } + + ItemDC data; +}; + +const size_t INDEXES = 2; + +class ItemNDCNode : public etl::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::intrusive_forward_list DataDC; + typedef etl::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 data0(0); + DataNDC data1(1); + + CHECK(data0.empty()); + CHECK(data1.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + + CHECK(!data0.empty()); + CHECK_EQUAL(sorted_data.size(), data0.size()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + DataNDC data0(0, 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) + { + DataNDC data0(0, 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) + { + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + data0.clear(); + + CHECK(data0.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + DataNDC data0(0); + + // 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) + { + DataNDC data0(0); + DataNDC data1(1); + + 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) + { + std::list compare0; + std::list compare1; + + DataNDC data0(0); + DataNDC data1(1); + + 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_after_position_value) + { + ItemNDCNode INSERT_VALUE1 = ItemNDCNode("1"); + ItemNDCNode INSERT_VALUE2 = ItemNDCNode("2"); + + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, sorted_data.begin(), sorted_data.end()); + + size_t offset = 2; + + DataNDC::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); + + data0.insert_after(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 + 1); + + std::vector temp(data0.begin(), data0.end()); + + data0.insert_after(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_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()); + + DataNDC data0(0, test1.begin(), test1.end()); + DataNDC data1(1, test1.begin(), test1.end()); + + data0.insert_after(data0.before_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(); + DataNDC::iterator id = data0.begin(); + + std::advance(icd, 4); + std::advance(id, 3); + + compare.insert(icd, test2.begin(), test2.end()); + data0.insert_after(id, test2.begin(), test2.end()); + + std::vector out(data0.begin(), data0.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) + { + std::list compare_data; + DataNDC data0(0); + + 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) + { + DataNDC data0(0); + DataNDC data1(1); + + 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_after_single) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, sorted_data.begin(), sorted_data.end()); + + DataNDC::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); + + i_compare_data = compare_data.erase(i_compare_data); + i_data = data0.erase_after(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() + 1); + 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())); + + 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() + 1; + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data0.begin(); + i_data = data0.erase_after(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_after_range) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data_1 = data0.begin(); + std::advance(i_data_1, 2); + + DataNDC::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); + + DataNDC::iterator i_result = data0.erase_after(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_after_range_end) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, sorted_data.begin(), sorted_data.end()); + + DataNDC::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::vector::iterator i_compare_result = compare_data.erase(i_compare_data, compare_data.end()); + + DataNDC::iterator i_result = data0.erase_after(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_after_all) + { + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + + data0.erase_after(data0.before_begin(), data0.end()); + + CHECK(data0.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_front) + { + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + + CHECK_EQUAL(sorted_data.front(), data0.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_unique) + { + DataNDC data0(0, non_unique_data.begin(), non_unique_data.end()); + DataNDC data1(1, 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) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, 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) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, 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) + { + DataNDC data0(0, sorted_data.begin(), sorted_data.end()); + DataNDC data1(1, 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) + { + DataNDC data0(0, unsorted_data.begin(), unsorted_data.end()); + DataNDC data1(1, 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) + { + DataNDC data0(0, unsorted_data.begin(), unsorted_data.end()); + DataNDC data1(1, 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); + } + }; +} diff --git a/test/vs2015/etl.vcxproj b/test/vs2015/etl.vcxproj index a28d0ca7..04b94e74 100644 --- a/test/vs2015/etl.vcxproj +++ b/test/vs2015/etl.vcxproj @@ -42,6 +42,7 @@ true + true false @@ -290,6 +291,7 @@ + diff --git a/test/vs2015/etl.vcxproj.filters b/test/vs2015/etl.vcxproj.filters index 31541cd0..ae59a793 100644 --- a/test/vs2015/etl.vcxproj.filters +++ b/test/vs2015/etl.vcxproj.filters @@ -689,6 +689,9 @@ Source Files + + Source Files +