diff --git a/src/intrusive_list.h b/src/intrusive_list.h index ebf56f72..ff361239 100644 --- a/src/intrusive_list.h +++ b/src/intrusive_list.h @@ -112,21 +112,256 @@ namespace etl } }; + //*************************************************************************** + /// Base for intrusive list. + ///\ingroup intrusive_list + //*************************************************************************** + template + 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 + 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(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(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type& new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type& previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type& link) + { + etl::unlink(link); + --current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type* link) + { + etl::unlink(*link); + --current_size; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + link_type* get_head() + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + const link_type* get_head() const + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + link_type* get_tail() + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + const link_type* get_tail() const + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Initialise the intrusive_list. + //************************************************************************* + void initialise() + { + etl::link(terminal_link, terminal_link); + current_size = 0; + } + }; + //*************************************************************************** /// An intrusive list. ///\ingroup intrusive_list ///\note TLink must be a base of TValue. //*************************************************************************** template > - class intrusive_list + class intrusive_list : public etl::intrusive_list_base { public: typedef intrusive_list 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(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(get_tail());; } - //************************************************************************* - /// Assigns a range of values to the intrusive_list. - /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined emits a - /// intrusive_list_iterator_exception if the iterators are reversed. - //************************************************************************* - template - void assign(TIterator first, TIterator last) - { -#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(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(previous, new_link); - ++current_size; - } - - //************************************************************************* - /// Insert a link. - //************************************************************************* - void insert_link(link_type* previous, link_type& new_link) - { - // Connect to the intrusive_list. - etl::link_splice(previous, new_link); - ++current_size; - } - - //************************************************************************* - /// Insert a link. - //************************************************************************* - void insert_link(link_type& previous, link_type* new_link) - { - // Connect to the intrusive_list. - etl::link_splice(previous, new_link); - ++current_size; - } - - //************************************************************************* - /// Insert a link. - //************************************************************************* - void insert_link(link_type* previous, link_type* new_link) - { - // Connect to the intrusive_list. - etl::link_splice(previous, new_link); - ++current_size; - } - - //************************************************************************* - /// Remove a link. - //************************************************************************* - void remove_link(link_type& link) - { - etl::unlink(link); - --current_size; - } - - //************************************************************************* - /// Remove a link. - //************************************************************************* - void remove_link(link_type* link) - { - etl::unlink(*link); - --current_size; - } - - //************************************************************************* - /// Get the head link. - //************************************************************************* - link_type* get_head() - { - return terminal_link.etl_next; - } - - //************************************************************************* - /// Get the head link. - //************************************************************************* - const link_type* get_head() const - { - return terminal_link.etl_next; - } - - //************************************************************************* - /// Get the tail link. - //************************************************************************* - link_type* get_tail() - { - return terminal_link.etl_previous; - } - - //************************************************************************* - /// Get the tail link. - //************************************************************************* - const link_type* get_tail() const - { - return terminal_link.etl_previous; - } - - //************************************************************************* - /// Initialise the intrusive_list. - //************************************************************************* - void initialise() - { - etl::link(terminal_link, terminal_link); - current_size = 0; - } - // Disabled. intrusive_list(const intrusive_list& other); intrusive_list& operator = (const intrusive_list& rhs);