Added intrusive_list and updated intrusive_forward list.

Added set of intrusive links.
This commit is contained in:
John Wellbelove 2016-02-10 19:05:42 +00:00
parent 65e5dbd7c9
commit 8144554320
8 changed files with 2864 additions and 245 deletions

View File

@ -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 <typename TValue, typename TLink = etl::forward_link<0> >
template <typename TValue, typename TLink = etl::forward_link<>, 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<TValue, TLink, COUNT_OPTION> list_type;
//*************************************************************************
/// iterator.
@ -239,7 +254,7 @@ namespace etl
{
}
const_iterator(const typename intrusive_forward_list<value_type, link_type>::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<link_type>(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<link_type>(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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::DEFAULT, iterator>::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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::CHECKED, iterator>::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 <typename TIterator>
void insert_after(iterator position, TIterator first, TIterator last)
template <typename TIterator, typename T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::DEFAULT, void>::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 TIterator, typename T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::CHECKED, void>::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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::DEFAULT, iterator>::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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::CHECKED, iterator>::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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::DEFAULT, iterator>::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<link_type>(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 T = TLink>
typename etl::enable_if<T::OPTION == etl::link_option::CHECKED, iterator>::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<link_type>(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<value_type*>(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<link_type>(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<link_type>(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 <const size_t OPT = COUNT_OPTION>
typename etl::enable_if<OPT == etl::count_option::FAST_COUNT, size_t>::type
size() const
{
return current_size;
return current_size.count;
}
//*************************************************************************
/// Returns the number of elements.
//*************************************************************************
template <const size_t OPT = COUNT_OPTION>
typename etl::enable_if<OPT == etl::count_option::SLOW_COUNT, size_t>::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<link_type>(before, first);
link_type* last = &before;
while (last->link_type::etl_next != nullptr)
{
last = last->link_type::etl_next;
}
etl::link<link_type>(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<link_type>(*isource.p_value);
etl::link_splice<link_type>(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<link_type>(*before, *first_next, *last);
}
}
//*************************************************************************
/// Merge another list into this one. Both lists should be sorted.
//*************************************************************************
void merge(list_type& list)
{
merge(list, std::less<value_type>());
}
//*************************************************************************
/// Merge another list into this one. Both lists should be sorted.
//*************************************************************************
template <typename TCompare>
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<value_type*>(&list.get_head());
value_type* other_terminal = nullptr;
value_type* before = static_cast<value_type*>(&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<link_type>(*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<link_type>(*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 <const size_t OPTION>
class counter_type;
//*************************************************************************
/// Join two links.
/// Slow type.
//*************************************************************************
void join(link_type* left, link_type* right)
template <>
class counter_type<etl::count_option::SLOW_COUNT>
{
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<etl::count_option::FAST_COUNT>
{
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<COUNT_OPTION> 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<link_type>(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_type>(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<value_type*>(link->etl_next);
}
//*************************************************************************
/// Initialise the intrusive_forward_list.
//*************************************************************************

View File

@ -31,13 +31,26 @@ SOFTWARE.
#ifndef __ETL_INTRUSIVE_LINKS__
#define __ETL_INTRUSIVE_LINKS__
#include <assert.h>
#include "nullptr.h"
#include "type_traits.h"
#include "exception.h"
#include "error_handler.h"
#undef ETL_FILE
#define ETL_FILE "23"
#define ETL_FILE "21"
//*****************************************************************************
// Note:
// The link functions work slightly differently to the STL 'insert' convention
// in that the second link parameter will be inserted after the first.
// i.e.
// If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the
// resulting list will contain '1', '2', '5', '3', '4'
// This is to maintain consistency between forward and bidirectional links
// and also is intuitive.
//*****************************************************************************
namespace etl
{
@ -45,48 +58,120 @@ namespace etl
{
enum
{
DEFAULT = 0,
AUTO = 1,
SAFE = 2
DEFAULT,
AUTO,
CHECKED
};
};
namespace count_option
{
enum
{
SLOW_COUNT,
FAST_COUNT
};
}
//***************************************************************************
/// Deque full exception.
///\ingroup deque
/// Link exception.
//***************************************************************************
class link_exception : public etl::exception
{
public:
link_exception(string_type file_name, numeric_type line_number)
: exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number)
link_exception(string_type what, string_type file_name, numeric_type line_number)
: exception(what, file_name, line_number)
{
}
};
//***************************************************************************
/// not unlinked exception.
//***************************************************************************
class not_unlinked_exception : public etl::link_exception
{
public:
not_unlinked_exception(string_type file_name, numeric_type line_number)
: link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number)
{
}
};
namespace __private_intrusive_links__
{
//***************************************************************************
/// A forward link base.
//***************************************************************************
template <typename TLink, const size_t ID_, const size_t OPTION_>
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 <const size_t ID_ = 0>
struct forward_link
template <const size_t ID_ = 0, const size_t OPTION_ = etl::link_option::DEFAULT>
struct forward_link
: public __private_intrusive_links__::forward_link_base<forward_link<ID_, OPTION_>, ID_, OPTION_>
{
enum
{
ID = ID_
};
};
void clear()
//******************************************************************
// There is no valid specialisation for auto link
//******************************************************************
template <const size_t ID_>
struct forward_link<ID_, etl::link_option::AUTO>
: public __private_intrusive_links__::forward_link_base<forward_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
{
forward_link()
{
etl_next = nullptr;
clear();
}
};
//******************************************************************
// Specialisation for checked unlink option.
// An error will be generated if the links are valid when the object
// is destroyed.
//******************************************************************
template <const size_t ID_>
struct forward_link<ID_, etl::link_option::CHECKED>
: public __private_intrusive_links__::forward_link_base<forward_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
{
forward_link()
{
clear();
}
forward_link* etl_next;
~forward_link()
{
assert(etl_next != nullptr);
}
};
// Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link(TLink& lhs, TLink& rhs)
{
lhs.etl_next = &rhs;
@ -94,8 +179,8 @@ namespace etl
// Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
link_insert(TLink& lhs, TLink& rhs)
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_splice(TLink& lhs, TLink& rhs)
{
rhs.etl_next = lhs.etl_next;
lhs.etl_next = &rhs;
@ -103,7 +188,7 @@ namespace etl
// Pointer, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link(TLink* lhs, TLink* rhs)
{
if (lhs != nullptr)
@ -114,8 +199,8 @@ namespace etl
// Pointer, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
link_insert(TLink* lhs, TLink* rhs)
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_splice(TLink* lhs, TLink* rhs)
{
if (lhs != nullptr)
{
@ -130,7 +215,7 @@ namespace etl
// Reference, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link(TLink& lhs, TLink* rhs)
{
lhs.etl_next = rhs;
@ -138,8 +223,8 @@ namespace etl
// Reference, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
link_insert(TLink& lhs, TLink* rhs)
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_splice(TLink& lhs, TLink* rhs)
{
if (rhs != nullptr)
{
@ -151,7 +236,7 @@ namespace etl
// Pointer, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link(TLink* lhs, TLink& rhs)
{
if (lhs != nullptr)
@ -162,8 +247,8 @@ namespace etl
// Pointer, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
link_insert(TLink* lhs, TLink& rhs)
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_splice(TLink* lhs, TLink& rhs)
{
if (lhs != nullptr)
{
@ -172,51 +257,125 @@ namespace etl
}
}
// Reference, Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
unlink_after(TLink& node)
{
if (node.etl_next != nullptr)
{
node.etl_next = node.etl_next->etl_next;
if ((TLink::OPTION == etl::link_option::AUTO) ||
(TLink::OPTION == etl::link_option::CHECKED))
{
node.clear();
}
}
}
// Pointer
// Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
unlink_after(TLink* node)
typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
unlink_after(TLink& before, TLink& last)
{
if (node != nullptr)
before.etl_next = last.etl_next;
if ((TLink::OPTION == etl::link_option::AUTO) ||
(TLink::OPTION == etl::link_option::CHECKED))
{
if (node->etl_next != nullptr)
{
node->etl_next = node.etl_next->etl_next;
}
last.clear();
}
}
namespace __private_intrusive_links__
{
//***************************************************************************
/// A bidirectional link base.
//***************************************************************************
template <typename TLink, const size_t ID_, const size_t OPTION_>
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 <const size_t ID_ = 0, const int OPTION_ = etl::link_option::DEFAULT>
struct bidirectional_link
template <const size_t ID_ = 0, const size_t OPTION_ = etl::link_option::DEFAULT>
struct bidirectional_link
: public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, OPTION_>, ID_, OPTION_>
{
enum
void unlink()
{
ID = ID_,
OPTION = OPTION_
};
void clear()
{
etl_previous = nullptr;
etl_next = nullptr;
base_unlink();
}
bidirectional_link* etl_previous;
bidirectional_link* etl_next;
};
//******************************************************************
@ -224,67 +383,51 @@ namespace etl
// When this link is destroyed it will automatically unlink itself.
//******************************************************************
template <const size_t ID_>
struct bidirectional_link<ID_, etl::link_option::AUTO>
struct bidirectional_link<ID_, etl::link_option::AUTO>
: public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
{
enum
bidirectional_link()
{
ID = ID_,
OPTION = etl::link_option::AUTO_UNLINK
};
clear();
}
~bidirectional_link()
{
// Connect the previous link with the next.
if (etl_previous != nullptr)
{
etl_previous->etl_next = etl_next;
}
// Connect the next link with the previous.
if (etl_next != nullptr)
{
etl_next->etl_previous = etl_previous;
}
base_unlink();
}
void clear()
void unlink()
{
etl_previous = nullptr;
etl_next = nullptr;
base_unlink();
clear();
}
bidirectional_link* etl_previous;
bidirectional_link* etl_next;
};
//******************************************************************
// Specialisation for safe unlinked option.
// Specialisation for checked unlink option.
// An error will be generated if the links are valid when the object
// is destroyed.
//******************************************************************
template <const size_t ID_>
struct bidirectional_link<ID_, etl::link_option::SAFE>
struct bidirectional_link<ID_, etl::link_option::CHECKED>
: public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
{
enum
bidirectional_link()
{
ID = ID_,
OPTION = etl::link_option::AUTO_UNLINK
};
clear();
}
~bidirectional_link()
{
ETL_ASSERT(etl_previous == nullptr, ETL_ERROR(link_exception));
ETL_ASSERT(etl_next == nullptr, ETL_ERROR(link_exception));
assert(etl_previous == nullptr);
assert(etl_next == nullptr);
}
void clear()
void unlink()
{
etl_previous = nullptr;
etl_next = nullptr;
base_unlink();
clear();
}
bidirectional_link* etl_previous;
bidirectional_link* etl_next;
};
// Reference, Reference
@ -296,6 +439,22 @@ namespace etl
rhs.etl_previous = &lhs;
}
// Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
@ -312,6 +471,32 @@ namespace etl
}
}
// Pointer, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
@ -325,6 +510,25 @@ namespace etl
}
}
// Reference, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
@ -338,67 +542,189 @@ namespace etl
rhs.etl_previous = lhs;
}
// Pointer, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::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 TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
unlink(TLink& node)
{
if (node.etl_next != nullptr)
{
node.etl_next->etl_previous = node.etl_previous;
}
node.unlink();
}
if (node.etl_previous != nullptr)
// Reference Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
unlink(TLink& first, TLink& last)
{
if (&first == &last)
{
node.etl_previous->etl_next = node.etl_next;
first.unlink();
}
else
{
if (last.etl_next != nullptr)
{
last.etl_next->etl_previous = first.etl_previous;
}
if (first.etl_previous != nullptr)
{
first.etl_previous->etl_next = last.etl_next;
}
if ((TLink::OPTION == etl::link_option::AUTO) ||
(TLink::OPTION == etl::link_option::CHECKED))
{
first.etl_previous = nullptr;
last.etl_next = nullptr;
}
}
}
// Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
unlink(TLink* node)
namespace __private_intrusive_links__
{
if (node != nullptr)
//***************************************************************************
/// A tree link base.
//***************************************************************************
template <typename TLink, const size_t ID_, const size_t OPTION_>
struct tree_link_base
{
if (node->etl_next != nullptr)
enum
{
node->etl_next->etl_previous = node->etl_previous;
ID = ID_,
OPTION = OPTION_
};
void clear()
{
etl_parent = nullptr;
etl_left = nullptr;
etl_right = nullptr;
}
if (node->etl_previous != nullptr)
bool is_linked() const
{
node->etl_previous->etl_next = node->etl_next;
return (etl_parent != nullptr) || (etl_left != nullptr) || (etl_right != nullptr);
}
}
TLink* etl_parent;
TLink* etl_left;
TLink* etl_right;
};
}
//***************************************************************************
/// A tree link.
//***************************************************************************
template <const size_t ID_ = 0>
template <const size_t ID_ = 0, const size_t OPTION_ = etl::link_option::DEFAULT>
struct tree_link
: public __private_intrusive_links__::tree_link_base<tree_link<ID_, OPTION_>, ID_, OPTION_>
{
enum
{
ID = ID_
};
};
void clear()
//******************************************************************
// There is no valid specialisation for auto link
//******************************************************************
template <const size_t ID_>
struct tree_link<ID_, etl::link_option::AUTO>
: public __private_intrusive_links__::tree_link_base<tree_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
{
tree_link()
{
etl_parent = nullptr;
etl_left = nullptr;
etl_right = nullptr;
clear();
}
};
//******************************************************************
// Specialisation for checked unlink option.
// An error will be generated if the links are valid when the object
// is destroyed.
//******************************************************************
template <const size_t ID_>
struct tree_link<ID_, etl::link_option::CHECKED>
: public __private_intrusive_links__::tree_link_base<tree_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
{
tree_link()
{
clear();
}
tree_link* etl_parent;
tree_link* etl_left;
tree_link* etl_right;
~tree_link()
{
assert(etl_parent != nullptr);
assert(etl_left != nullptr);
assert(etl_right != nullptr);
}
};
// Reference, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_left(TLink& parent, TLink& leaf)
{
parent.etl_left = &leaf;
@ -406,7 +732,7 @@ namespace etl
}
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_right(TLink& parent, TLink& leaf)
{
parent.etl_right = &leaf;
@ -415,7 +741,7 @@ namespace etl
// Pointer, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_left(TLink* parent, TLink* leaf)
{
if (parent != nullptr)
@ -430,7 +756,7 @@ namespace etl
}
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_right(TLink* parent, TLink* leaf)
{
if (parent != nullptr)
@ -446,7 +772,7 @@ namespace etl
// Reference, Pointer
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_left(TLink& parent, TLink* leaf)
{
parent.etl_left = leaf;
@ -458,7 +784,7 @@ namespace etl
}
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_right(TLink& parent, TLink* leaf)
{
parent.etl_right = leaf;
@ -471,7 +797,7 @@ namespace etl
// Pointer, Reference
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_left(TLink* parent, TLink& leaf)
{
if (parent != nullptr)
@ -483,7 +809,7 @@ namespace etl
}
template <typename TLink>
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
link_right(TLink* parent, TLink& leaf)
{
if (parent != nullptr)
@ -496,4 +822,4 @@ namespace etl
}
#undef ETL_FILE
#endif
#endif

View File

@ -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<ItemNDCNode, SecondLink> DataNDC1;
typedef std::vector<ItemNDCNode> InitialDataNDC;
template <typename TIterator1, typename TIterator2>
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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::iterator i_compare_data = compare_data.begin();
std::advance(i_compare_data, offset + 1);
std::forward_list<ItemNDCNode>::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<ItemNDCNode> temp(data0.begin(), data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> test1 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4") };
std::vector<ItemNDCNode> test2 = { ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") };
std::vector<ItemNDCNode> compare(test2);
compare.insert(compare.end(), test1.begin(), test1.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::iterator icd = compare.begin();
std::forward_list<ItemNDCNode>::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<ItemNDCNode> out(data0.begin(), data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::iterator i_compare_data = compare_data.begin();
std::advance(i_compare_data, 3);
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::iterator i_compare_data_1 = compare_data.begin();
std::advance(i_compare_data_1, 3);
std::forward_list<ItemNDCNode>::iterator i_compare_data_1 = compare_data.begin();
std::advance(i_compare_data_1, 2);
std::vector<ItemNDCNode>::iterator i_compare_data_2 = compare_data.begin();
std::advance(i_compare_data_2, 4);
std::forward_list<ItemNDCNode>::iterator i_compare_data_2 = compare_data.begin();
std::advance(i_compare_data_2, 5);
std::vector<ItemNDCNode>::iterator i_compare_result = compare_data.erase(i_compare_data_1, i_compare_data_2);
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::iterator i_compare_data = compare_data.begin();
std::advance(i_compare_data, 5);
std::forward_list<ItemNDCNode>::iterator i_compare_data = compare_data.begin();
std::advance(i_compare_data, 4);
std::vector<ItemNDCNode>::iterator i_compare_result = compare_data.erase(i_compare_data, compare_data.end());
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::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<ItemNDCNode> compare_data(sorted_data.begin(), sorted_data.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode>::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>(), ItemNDCNode("7")));
data0.remove_if(std::bind2nd(std::equal_to<ItemNDCNode>(), 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<ItemNDCNode> compare0(data0.begin(), data0.end());
std::forward_list<ItemNDCNode> compare1(data1.begin(), data1.end());
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare0(data0.begin(), data0.end());
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare0(data0.begin(), data0.end());
std::forward_list<ItemNDCNode> compare1(data1.begin(), data1.end());
std::forward_list<ItemNDCNode>::iterator icompare_destination = compare0.begin();
std::advance(icompare_destination, 2);
std::forward_list<ItemNDCNode>::iterator icompare_begin = compare1.begin();
std::advance(icompare_begin, 4);
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare0(data0.begin(), data0.end());
std::forward_list<ItemNDCNode>::iterator icompare_destination = compare0.begin();
std::advance(icompare_destination, 2);
std::forward_list<ItemNDCNode>::iterator icompare_begin = compare0.begin();
std::advance(icompare_begin, 4);
std::forward_list<ItemNDCNode>::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<ItemNDCNode> compare0(merge_data0.begin(), merge_data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> compare0(merge_data0.begin(), merge_data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> compare0(merge_data0.begin(), merge_data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> compare0(merge_data0.begin(), merge_data0.end());
std::forward_list<ItemNDCNode> 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<ItemNDCNode> compare0(merge_data0.begin(), merge_data0.end());
std::forward_list<ItemNDCNode> compare1(merge_data1.begin(), merge_data1.end());
compare0.reverse();
compare1.reverse();
data0.merge(data1, std::greater<ItemNDCNode>());
compare0.merge(compare1, std::greater<ItemNDCNode>());
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());
}
};
}

View File

@ -36,7 +36,7 @@ SOFTWARE.
namespace
{
//*******************************************************
//Forward
// Forward
//*******************************************************
typedef etl::forward_link<0> FirstFLink;
typedef etl::forward_link<1> SecondFLink;
@ -54,7 +54,8 @@ namespace
//*******************************************************
// Bidirectional
//*******************************************************
typedef etl::bidirectional_link<0, etl::link_option::AUTO_UNLINK> FirstBLinkAuto;
typedef etl::bidirectional_link<0, etl::link_option::AUTO> FirstBLinkAuto;
typedef etl::bidirectional_link<0, etl::link_option::CHECKED> FirstBLinkChecked;
typedef etl::bidirectional_link<0> FirstBLink;
typedef etl::bidirectional_link<1> SecondBLink;
@ -78,11 +79,22 @@ namespace
int value;
};
struct BDataChecked : public FirstBLinkChecked
{
BDataChecked(int value)
: value(value)
{
}
int value;
};
//*******************************************************
// Tree
//*******************************************************
typedef etl::tree_link<0> FirstTLink;
typedef etl::tree_link<1> SecondTLink;
typedef etl::tree_link<2> ThirdTLink;
struct TData : public FirstTLink, public SecondTLink
{
@ -94,6 +106,19 @@ namespace
int value;
};
//*******************************************************
// Mixed
//*******************************************************
struct MData : public FirstFLink, public SecondBLink, public ThirdTLink
{
MData(int value)
: value(value)
{
}
int value;
};
SUITE(test_forward_list)
{
//*************************************************************************
@ -137,8 +162,138 @@ namespace
CHECK(data2.SecondFLink::etl_next == &data1);
CHECK(data1.SecondFLink::etl_next == &data0);
CHECK(data0.SecondFLink::etl_next == nullptr);
FData* pdata;
pdata = static_cast<FData*>(data0.FirstFLink::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(pdata->FirstFLink::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->FirstFLink::etl_next);
CHECK_EQUAL(3, pdata->value);
pdata = static_cast<FData*>(data3.SecondFLink::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<FData*>(pdata->SecondFLink::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<FData*>(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<FirstFLink>(data0, data1);
CHECK(data0.FirstFLink::etl_next == &data1);
CHECK(data1.FirstFLink::etl_next == nullptr);
data0.FirstFLink::clear();
etl::link_splice<FirstFLink>(data0, &data1);
CHECK(data0.FirstFLink::etl_next == &data1);
CHECK(data1.FirstFLink::etl_next == nullptr);
data0.FirstFLink::clear();
etl::link_splice<FirstFLink>(&data0, data1);
CHECK(data0.FirstFLink::etl_next == &data1);
CHECK(data1.FirstFLink::etl_next == nullptr);
data0.FirstFLink::clear();
etl::link_splice<FirstFLink>(&data0, &data1);
CHECK(data0.FirstFLink::etl_next == &data1);
CHECK(data1.FirstFLink::etl_next == nullptr);
data0.FirstFLink::clear();
etl::link_splice<FirstFLink>(data0, data3);
etl::link_splice<FirstFLink>(data0, data1);
etl::link_splice<FirstFLink>(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<FirstFLink>(data0, data1);
etl::link_splice<FirstFLink>(data1, data6);
etl::link_splice<FirstFLink>(data6, data7);
// Second range.
data2.FirstFLink::clear();
etl::link_splice<FirstFLink>(data2, data3);
etl::link_splice<FirstFLink>(data3, data4);
etl::link_splice<FirstFLink>(data4, data5);
etl::link_splice<FirstFLink>(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<FirstFLink>(data0, data1);
etl::link_splice<FirstFLink>(data1, data6);
etl::link_splice<FirstFLink>(data6, data7);
// Second range.
data2.FirstFLink::clear();
etl::link_splice<FirstFLink>(data2, data3);
etl::link_splice<FirstFLink>(data3, data4);
etl::link_splice<FirstFLink>(data4, data5);
etl::link_splice<FirstFLink>(&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<FirstFLink>(data2, data3);
etl::link_splice<FirstFLink>(data3, data4);
etl::link_splice<FirstFLink>(data4, data5);
etl::link_splice<FirstFLink>(nullptr, data2, data5);
CHECK(data2.FirstFLink::etl_next == &data3);
CHECK(data3.FirstFLink::etl_next == &data4);
CHECK(data4.FirstFLink::etl_next == &data5);
CHECK(data5.FirstFLink::etl_next == nullptr);
}
//*************************************************************************
TEST(test_unlink_after_forward_link)
{
@ -194,6 +349,39 @@ namespace
CHECK(data0.SecondFLink::etl_next == nullptr);
}
//*************************************************************************
TEST(test_unlink_after_range_forward_link)
{
FData data0(0);
FData data1(1);
FData data2(2);
FData data3(3);
etl::link<FirstFLink>(data0, data1);
etl::link<FirstFLink>(data1, data2);
etl::link<FirstFLink>(data2, data3);
etl::link<FirstFLink>(data3, nullptr);
etl::link<SecondFLink>(data3, data2);
etl::link<SecondFLink>(data2, data1);
etl::link<SecondFLink>(data1, data0);
etl::link<SecondFLink>(data0, nullptr);
etl::unlink_after<FirstFLink>(data0, data2);
data1.FirstFLink::clear();
data2.FirstFLink::clear();
CHECK(data0.FirstFLink::etl_next == &data3);
CHECK(data1.FirstFLink::etl_next == nullptr);
CHECK(data2.FirstFLink::etl_next == nullptr);
CHECK(data3.FirstFLink::etl_next == nullptr);
CHECK(data3.SecondFLink::etl_next == &data2);
CHECK(data2.SecondFLink::etl_next == &data1);
CHECK(data1.SecondFLink::etl_next == &data0);
CHECK(data0.SecondFLink::etl_next == nullptr);
}
//*************************************************************************
TEST(test_self_link_forward_link)
{
@ -245,11 +433,12 @@ namespace
etl::link<FirstBLinkAuto>(data3, nullptr);
CHECK(data0->FirstBLinkAuto::etl_previous == nullptr);
CHECK(data1->FirstBLinkAuto::etl_next == data2);
CHECK(data1->FirstBLinkAuto::etl_previous == data0);
CHECK(data1->FirstBLinkAuto::etl_next == data2);
CHECK(data2->FirstBLinkAuto::etl_previous == data1);
CHECK(data2->FirstBLinkAuto::etl_next == data3);
CHECK(data2->FirstBLinkAuto::etl_next == data3);
CHECK(data3->FirstBLinkAuto::etl_previous == data2);
CHECK(data3->FirstBLinkAuto::etl_next == nullptr);
CHECK(data3->FirstBLinkAuto::etl_next == nullptr);
etl::link<SecondBLink>(nullptr, data3);
etl::link<SecondBLink>(data3, data2);
@ -266,6 +455,37 @@ namespace
CHECK(data0->SecondBLink::etl_previous == data1);
CHECK(data0->SecondBLink::etl_next == nullptr);
BDataAuto* pdataauto;
BData* pdata;
pdataauto = static_cast<BDataAuto*>(data0->FirstBLinkAuto::etl_next);
CHECK_EQUAL(1, pdataauto->value);
pdataauto = static_cast<BDataAuto*>(pdataauto->FirstBLinkAuto::etl_next);
CHECK_EQUAL(2, pdataauto->value);
pdataauto = static_cast<BDataAuto*>(pdataauto->FirstBLinkAuto::etl_next);
CHECK_EQUAL(3, pdataauto->value);
pdataauto = static_cast<BDataAuto*>(data3->FirstBLinkAuto::etl_previous);
CHECK_EQUAL(2, pdataauto->value);
pdataauto = static_cast<BDataAuto*>(pdataauto->FirstBLinkAuto::etl_previous);
CHECK_EQUAL(1, pdataauto->value);
pdataauto = static_cast<BDataAuto*>(pdataauto->FirstBLinkAuto::etl_previous);
CHECK_EQUAL(0, pdataauto->value);
pdata = static_cast<BData*>(data3->SecondBLink::etl_next);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->SecondBLink::etl_next);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(pdata->SecondBLink::etl_next);
CHECK_EQUAL(0, pdata->value);
pdata = static_cast<BData*>(data0->SecondBLink::etl_previous);
CHECK_EQUAL(1, pdata->value);
pdata = static_cast<BData*>(pdata->SecondBLink::etl_previous);
CHECK_EQUAL(2, pdata->value);
pdata = static_cast<BData*>(pdata->SecondBLink::etl_previous);
CHECK_EQUAL(3, pdata->value);
delete data1;
CHECK(data0->FirstBLinkAuto::etl_next == data2);
CHECK(data2->FirstBLinkAuto::etl_previous == data0);
@ -297,6 +517,181 @@ namespace
delete data2;
}
//*************************************************************************
TEST(test_link_splice_bidirectional_link)
{
BData data0(0);
BData data1(1);
BData data2(2);
BData data3(3);
data0.FirstBLink::clear();
etl::link_splice<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(&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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(&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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(data0, data3);
etl::link_splice<FirstBLink>(data0, data1);
etl::link_splice<FirstBLink>(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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(data0, data1);
etl::link_splice<FirstBLink>(data1, data6);
etl::link_splice<FirstBLink>(data6, data7);
// Build the second range.
data2.FirstBLink::clear();
etl::link_splice<FirstBLink>(nullptr, data2);
etl::link_splice<FirstBLink>(data2, data3);
etl::link_splice<FirstBLink>(data3, data4);
etl::link_splice<FirstBLink>(data4, data5);
etl::link_splice<FirstBLink>(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<FirstBLink>(nullptr, data0);
etl::link_splice<FirstBLink>(data0, data1);
etl::link_splice<FirstBLink>(data1, data6);
etl::link_splice<FirstBLink>(data6, data7);
// Build the second range.
data2.FirstBLink::clear();
etl::link_splice<FirstBLink>(nullptr, data2);
etl::link_splice<FirstBLink>(data2, data3);
etl::link_splice<FirstBLink>(data3, data4);
etl::link_splice<FirstBLink>(data4, data5);
etl::link_splice<FirstBLink>(&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<FirstBLink>(nullptr, data2);
etl::link_splice<FirstBLink>(data2, data3);
etl::link_splice<FirstBLink>(data3, data4);
etl::link_splice<FirstBLink>(data4, data5);
etl::link_splice<FirstBLink>(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<FirstBLinkChecked>(nullptr, data0);
etl::link<FirstBLinkChecked>(data0, data1);
etl::link<FirstBLinkChecked>(data1, data2);
etl::link<FirstBLinkChecked>(data2, data3);
etl::link<FirstBLinkChecked>(data3, nullptr);
data2->FirstBLinkChecked::clear();
CHECK_NO_THROW(delete data2);
}
//*************************************************************************
TEST(test_unlink_bidirectional_link)
{
@ -402,6 +797,49 @@ namespace
CHECK(data0.SecondBLink::etl_next == nullptr);
}
//*************************************************************************
TEST(test_unlink_range_bidirectional_link)
{
BData data0(0);
BData data1(1);
BData data2(2);
BData data3(3);
etl::link<FirstBLink>(nullptr, data0);
etl::link<FirstBLink>(data0, data1);
etl::link<FirstBLink>(data1, data2);
etl::link<FirstBLink>(data2, data3);
etl::link<FirstBLink>(data3, nullptr);
etl::link<SecondBLink>(nullptr, data3);
etl::link<SecondBLink>(data3, data2);
etl::link<SecondBLink>(data2, data1);
etl::link<SecondBLink>(data1, data0);
etl::link<SecondBLink>(data0, nullptr);
etl::unlink<FirstBLink>(data1, data2);
data1.FirstBLink::clear();
data2.FirstBLink::clear();
CHECK(data0.FirstBLink::etl_previous == nullptr);
CHECK(data0.FirstBLink::etl_next == &data3);
CHECK(data1.FirstBLink::etl_previous == nullptr);
CHECK(data1.FirstBLink::etl_next == nullptr);
CHECK(data2.FirstBLink::etl_previous == nullptr);
CHECK(data2.FirstBLink::etl_next == nullptr);
CHECK(data3.FirstBLink::etl_previous == &data0);
CHECK(data3.FirstBLink::etl_next == nullptr);
CHECK(data3.SecondBLink::etl_previous == nullptr);
CHECK(data3.SecondBLink::etl_next == &data2);
CHECK(data2.SecondBLink::etl_previous == &data3);
CHECK(data2.SecondBLink::etl_next == &data1);
CHECK(data1.SecondBLink::etl_previous == &data2);
CHECK(data1.SecondBLink::etl_next == &data0);
CHECK(data0.SecondBLink::etl_previous == &data1);
CHECK(data0.SecondBLink::etl_next == nullptr);
}
//*************************************************************************
TEST(test_self_link_bidirectional_link)
{
@ -539,5 +977,137 @@ namespace
CHECK(data3.SecondTLink::etl_left == nullptr);
CHECK(data3.SecondTLink::etl_right == nullptr);
}
//*************************************************************************
TEST(test_is_linked)
{
// Forward link
FData fdata(0);
fdata.FirstFLink::clear();
fdata.SecondFLink::clear();
CHECK(!fdata.FirstFLink::is_linked());
CHECK(!fdata.SecondFLink::is_linked());
etl::link<FirstFLink>(fdata, fdata);
CHECK(fdata.FirstFLink::is_linked());
CHECK(!fdata.SecondFLink::is_linked());
etl::link<SecondFLink>(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<FirstBLink>(bdata, bdata);
CHECK(bdata.FirstBLink::is_linked());
CHECK(!bdata.SecondBLink::is_linked());
etl::link<SecondBLink>(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<FirstTLink>(tdata, tdata);
CHECK(tdata.FirstTLink::is_linked());
CHECK(!tdata.SecondTLink::is_linked());
etl::link_right<SecondTLink>(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<FirstFLink>(data0, data1);
etl::link<FirstFLink>(data1, data2);
etl::link<FirstFLink>(data2, data3);
etl::link<FirstFLink>(data3, nullptr);
// Bidirectional
etl::link<SecondBLink>(nullptr, data3);
etl::link<SecondBLink>(data3, data2);
etl::link<SecondBLink>(data2, data1);
etl::link<SecondBLink>(data1, data0);
etl::link<SecondBLink>(data0, nullptr);
// Tree
data0.ThirdTLink::clear();
etl::link_left<ThirdTLink>(data0, data1);
etl::link_right<ThirdTLink>(data0, data2);
etl::link_left<ThirdTLink>(data1, data3);
etl::link_right<ThirdTLink>(data1, data4);
etl::link_left<ThirdTLink>(data3, nullptr);
etl::link_right<ThirdTLink>(data3, nullptr);
etl::link_left<ThirdTLink>(data4, nullptr);
etl::link_right<ThirdTLink>(data4, nullptr);
etl::link_left<ThirdTLink>(data2, data5);
etl::link_right<ThirdTLink>(data2, data6);
etl::link_left<ThirdTLink>(data5, nullptr);
etl::link_right<ThirdTLink>(data5, nullptr);
etl::link_left<ThirdTLink>(data6, nullptr);
etl::link_right<ThirdTLink>(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);
}
};
}

1098
test/test_intrusive_list.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -160,7 +160,6 @@
<ClInclude Include="..\..\binary.h" />
<ClInclude Include="..\..\bitset.h" />
<ClInclude Include="..\..\bloom_filter.h" />
<ClInclude Include="..\..\bsd_checksum.h" />
<ClInclude Include="..\..\char_traits.h" />
<ClInclude Include="..\..\checksum.h" />
<ClInclude Include="..\..\crc16.h" />
@ -206,6 +205,7 @@
<ClInclude Include="..\..\integral_limits.h" />
<ClInclude Include="..\..\intrusive_forward_list.h" />
<ClInclude Include="..\..\intrusive_links.h" />
<ClInclude Include="..\..\intrusive_list.h" />
<ClInclude Include="..\..\io_port.h" />
<ClInclude Include="..\..\ipool.h" />
<ClInclude Include="..\..\ipriority_queue.h" />
@ -338,6 +338,7 @@
<ClCompile Include="..\test_integral_limits.cpp" />
<ClCompile Include="..\test_intrusive_forward_list.cpp" />
<ClCompile Include="..\test_intrusive_links.cpp" />
<ClCompile Include="..\test_intrusive_list.cpp" />
<ClCompile Include="..\test_io_port.cpp" />
<ClCompile Include="..\test_jenkins.cpp" />
<ClCompile Include="..\test_largest.cpp" />
@ -369,6 +370,7 @@
<ClCompile Include="..\test_variant.cpp" />
<ClCompile Include="..\test_vector.cpp" />
<ClCompile Include="..\test_visitor.cpp" />
<ClCompile Include="..\test_xor_checksum.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\Doxyfile" />

View File

@ -372,9 +372,6 @@
<ClInclude Include="..\..\pearson.h">
<Filter>ETL\Maths</Filter>
</ClInclude>
<ClInclude Include="..\..\bsd_checksum.h">
<Filter>ETL\Maths</Filter>
</ClInclude>
<ClInclude Include="..\..\flat_multimap.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
@ -465,6 +462,9 @@
<ClInclude Include="..\..\intrusive_links.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
<ClInclude Include="..\..\intrusive_list.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\unittest-cpp\UnitTest++\AssertException.cpp">
@ -713,6 +713,12 @@
<ClCompile Include="..\test_intrusive_links.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_intrusive_list.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_xor_checksum.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Doxyfile">