Moved common code to base class.

This commit is contained in:
John Wellbelove 2017-06-26 19:09:13 +01:00
parent a51530a96c
commit d79bdc89c6

View File

@ -112,21 +112,256 @@ namespace etl
}
};
//***************************************************************************
/// Base for intrusive list.
///\ingroup intrusive_list
//***************************************************************************
template <typename TLink>
class intrusive_list_base
{
public:
// Node typedef.
typedef TLink link_type;
//*************************************************************************
/// 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 <typename TIterator>
void assign(TIterator first, TIterator last)
{
#if defined(ETL_DEBUG)
intmax_t 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<link_type>(p_last_link, link);
p_last_link = &link;
++current_size;
}
}
//*************************************************************************
/// Pushes a value to the front of the intrusive_list.
//*************************************************************************
void push_front(link_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(link_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());
}
//*************************************************************************
/// Clears the intrusive_list.
//*************************************************************************
void clear()
{
initialise();
}
//*************************************************************************
/// 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();
}
//*************************************************************************
/// 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.
//*************************************************************************
size_t size() const
{
return current_size;
}
protected:
/// The link that acts as the intrusive_list start & end.
link_type terminal_link;
size_t 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<link_type>(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<link_type>(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<link_type>(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<link_type>(previous, new_link);
++current_size;
}
//*************************************************************************
/// Remove a link.
//*************************************************************************
void remove_link(link_type& link)
{
etl::unlink<link_type>(link);
--current_size;
}
//*************************************************************************
/// Remove a link.
//*************************************************************************
void remove_link(link_type* link)
{
etl::unlink<link_type>(*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;
}
};
//***************************************************************************
/// An intrusive list.
///\ingroup intrusive_list
///\note TLink must be a base of TValue.
//***************************************************************************
template <typename TValue, typename TLink = etl::bidirectional_link<0> >
class intrusive_list
class intrusive_list : public etl::intrusive_list_base<TLink>
{
public:
typedef intrusive_list<TValue, TLink> list_type;
// Node typedef.
typedef TLink link_type;
// STL style typedefs.
typedef TValue value_type;
typedef value_type* pointer;
@ -410,14 +645,6 @@ namespace etl
return const_iterator(static_cast<const value_type&>(terminal_link));
}
//*************************************************************************
/// Clears the intrusive_list.
//*************************************************************************
void clear()
{
initialise();
}
//*************************************************************************
/// Gets a reference to the first element.
//*************************************************************************
@ -450,93 +677,6 @@ namespace etl
return *static_cast<const value_type*>(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 <typename TIterator>
void assign(TIterator first, TIterator last)
{
#if defined(ETL_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<link_type>(p_last_link, link);
p_last_link = &link;
++current_size;
}
}
//*************************************************************************
/// Pushes a value to the front of the intrusive_list.
//*************************************************************************
void push_front(link_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.
//*************************************************************************
@ -788,22 +928,6 @@ namespace etl
}
}
//*************************************************************************
/// 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.
//*************************************************************************
size_t size() const
{
return current_size;
}
//*************************************************************************
/// Splice another list into this one.
//*************************************************************************
@ -936,120 +1060,6 @@ namespace etl
}
}
private:
/// The link that acts as the intrusive_list start & end.
link_type terminal_link;
size_t 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<link_type>(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<link_type>(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<link_type>(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<link_type>(previous, new_link);
++current_size;
}
//*************************************************************************
/// Remove a link.
//*************************************************************************
void remove_link(link_type& link)
{
etl::unlink<link_type>(link);
--current_size;
}
//*************************************************************************
/// Remove a link.
//*************************************************************************
void remove_link(link_type* link)
{
etl::unlink<link_type>(*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);