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/etl.jpg b/etl.jpg deleted file mode 100644 index 77556b7f..00000000 Binary files a/etl.jpg and /dev/null differ diff --git a/etl.png b/etl.png new file mode 100644 index 00000000..39882ffb Binary files /dev/null and b/etl.png differ diff --git a/etl.pspimage b/etl.pspimage new file mode 100644 index 00000000..a5329e63 Binary files /dev/null and b/etl.pspimage differ diff --git a/favicon.ico b/favicon.ico index 0b1fcbe3..1a20e372 100644 Binary files a/favicon.ico and b/favicon.ico differ 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) { 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 e3101277..d59d81fe 100644 --- a/intrusive_links.h +++ b/intrusive_links.h @@ -31,7 +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 "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 { @@ -39,84 +58,768 @@ namespace etl { enum { - NO_AUTO_UNLINK = false, - AUTO_UNLINK = true + DEFAULT, + AUTO, + CHECKED }; }; + namespace count_option + { + enum + { + SLOW_COUNT, + FAST_COUNT + }; + } + + //*************************************************************************** + /// Link exception. + //*************************************************************************** + class link_exception : public etl::exception + { + public: + + 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_ - }; - - forward_link* etl_next; }; + //****************************************************************** + // 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() + { + 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() + { + assert(etl_next != nullptr); + } + }; + + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + } + + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link_splice(TLink& lhs, TLink& rhs) + { + rhs.etl_next = lhs.etl_next; + 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; + } + } + + // Pointer, Pointer + template + typename etl::enable_if >::value, void>::type + link_splice(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 + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + } + + // 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; + } + + 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; + } + } + + // 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; + 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; + 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 + 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(); + } + } + } + + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + unlink_after(TLink& before, TLink& last) + { + before.etl_next = last.etl_next; + + if ((TLink::OPTION == etl::link_option::AUTO) || + (TLink::OPTION == etl::link_option::CHECKED)) + { + 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_, - }; - - bidirectional_link* etl_previous; - bidirectional_link* etl_next; + base_unlink(); + } }; + //****************************************************************** // Specialisation for auto unlinked option. // 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_ - }; + 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(); } - bidirectional_link* etl_previous; - bidirectional_link* etl_next; + void unlink() + { + base_unlink(); + clear(); + } }; + //****************************************************************** + // Specialisation for checked unlink option. + // An error will be generated if the links are valid when the object + // is destroyed. + //****************************************************************** + template + struct bidirectional_link + : public __private_intrusive_links__::bidirectional_link_base, ID_, etl::link_option::CHECKED> + { + bidirectional_link() + { + clear(); + } + + ~bidirectional_link() + { + assert(etl_previous == nullptr); + assert(etl_next == nullptr); + } + + void unlink() + { + base_unlink(); + clear(); + } + }; + + // Reference, Reference + template + typename etl::enable_if >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + 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 + link(TLink* lhs, TLink* rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = rhs; + } + + if (rhs != nullptr) + { + rhs->etl_previous = lhs; + } + } + + // 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 + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + + if (rhs != nullptr) + { + rhs->etl_previous = &lhs; + } + } + + // 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 + link(TLink* lhs, TLink& rhs) + { + if (lhs != nullptr) + { + lhs->etl_next = &rhs; + } + + 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) + { + node.unlink(); + } + + // Reference Reference + template + typename etl::enable_if >::value, void>::type + unlink(TLink& first, TLink& last) + { + if (&first == &last) + { + 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; + } + } + } + + namespace __private_intrusive_links__ + { + //*************************************************************************** + /// A tree link base. + //*************************************************************************** + template + struct tree_link_base + { + enum + { + ID = ID_, + OPTION = OPTION_ + }; + + void clear() + { + etl_parent = nullptr; + etl_left = nullptr; + etl_right = nullptr; + } + + bool is_linked() const + { + 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_ - }; - - tree_link* etl_parent; - tree_link* etl_left; - tree_link* etl_right; }; + + //****************************************************************** + // 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() + { + 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() + { + assert(etl_parent != nullptr); + assert(etl_left != nullptr); + assert(etl_right != nullptr); + } + }; + + // 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 +#undef ETL_FILE +#endif \ No newline at end of file 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 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) { //************************************************************************* 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 1b7cc0c9..06ba8868 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,1062 @@ namespace }; //******************************************************* - bool operator ==(const Data& lhs, const Data& rhs) - { - return lhs.value == rhs.value; - } + // Bidirectional + //******************************************************* + 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; - 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; + }; + + struct BDataChecked : public FirstBLinkChecked + { + BDataChecked(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; + typedef etl::tree_link<2> ThirdTLink; + + 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)) + + int value; + }; + + //******************************************************* + // Mixed + //******************************************************* + struct MData : public FirstFLink, public SecondBLink, public ThirdTLink + { + MData(int value) + : value(value) { - 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); + + 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) + { + 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_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) + { + 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_previous == data0); + 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); + + 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->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_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) + { + 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_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) + { + 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); + } + + //************************************************************************* + 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/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); + } + }; +} + 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 +