Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Revision:
0:b47c2a7920c2
diff -r 000000000000 -r b47c2a7920c2 intrusive_forward_list.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_forward_list.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1049 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INTRUSIVE_FORWARD_LIST__
+#define __ETL_INTRUSIVE_FORWARD_LIST__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+#include "algorithm.h"
+
+#undef ETL_FILE
+#define ETL_FILE "20"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_exception : public exception
+  {
+  public:
+
+    intrusive_forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Empty exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_empty : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_empty(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_iterator_exception : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_iterator_exception(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:iterator", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Index exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_index_exception : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_index_exception(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:bounds", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// 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_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Base for intrusive forward list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  template <typename TLink>
+  class intrusive_forward_list_base
+  {
+  public:
+
+    // Node typedef.
+    typedef TLink link_type;
+
+    //*************************************************************************
+    /// Clears the intrusive_forward_list.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Assigns a range of values to the intrusive_forward_list.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      intmax_t d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(intrusive_forward_list_iterator_exception));
+#endif
+
+      initialise();
+
+      link_type* p_last_link = &start_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_forward_list.
+    //*************************************************************************
+    void push_front(link_type& value)
+    {
+      insert_link_after(start_link, value);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the front of the intrusive_forward_list.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_forward_list_empty));
+#endif
+      remove_link_after(start_link);
+    }
+
+    //*************************************************************************
+    /// Reverses the intrusive_forward_list.
+    //*************************************************************************
+    void reverse()
+    {
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      link_type* first = std::nullptr;             // To keep first link
+      link_type* second = start_link.etl_next; // To keep second link
+      link_type* track = start_link.etl_next; // Track the list
+
+      while (track != NULL)
+      {
+        track = track->etl_next;  // Track point to next link;
+        second->etl_next = first; // Second link point to first
+        first = second;          // Move first link to next
+        second = track;           // Move second link to next
+      }
+
+      etl::link<link_type>(start_link, first);
+    }
+
+    //*************************************************************************
+    /// Returns true if the list has no elements.
+    //*************************************************************************
+    bool empty() const
+    {
+      return start_link.etl_next == std::nullptr;
+    }
+
+    //*************************************************************************
+    /// Returns the number of elements.
+    //*************************************************************************
+    size_t size() const
+    {
+      return current_size;
+    }
+
+  protected:
+
+    link_type start_link; ///< The link that acts as the intrusive_forward_list start.
+
+    size_t current_size; ///< Counts the number of elements in the list.
+
+    //*************************************************************************
+    /// Is the intrusive_forward_list a trivial length?
+    //*************************************************************************
+    bool is_trivial_list() const
+    {
+      return (start_link.link_type::etl_next == std::nullptr) || (start_link.link_type::etl_next->etl_next == std::nullptr);;
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link_after(link_type& position, link_type& link)
+    {
+      // Connect to the intrusive_forward_list.
+      etl::link_splice<link_type>(position, link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Remove a link.
+    //*************************************************************************
+    void remove_link_after(link_type& link)
+    {
+      link_type* p_next = link.etl_next;
+
+      if (p_next != std::nullptr)
+      {
+        etl::unlink_after<link_type>(link);
+        --current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    link_type& get_head()
+    {
+      return *start_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    const link_type& get_head() const
+    {
+      return *start_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Initialise the intrusive_forward_list.
+    //*************************************************************************
+    void initialise()
+    {
+      start_link.etl_next = std::nullptr;
+      current_size = 0;
+    }
+  };
+
+  //***************************************************************************
+  /// 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> >
+  class intrusive_forward_list : public etl::intrusive_forward_list_base<TLink>
+  {
+  public:
+
+    // Node typedef.
+    typedef typename etl::intrusive_forward_list_base<TLink>::link_type link_type;
+
+    // STL style typedefs.
+    typedef TValue            value_type;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef size_t            size_type;
+
+    typedef intrusive_forward_list<TValue, TLink> list_type;
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, value_type>
+    {
+    public:
+
+      friend class intrusive_forward_list;
+
+      iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      iterator(value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return *p_value;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      pointer operator &()
+      {
+        return p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      pointer operator ->()
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      value_type* p_value;
+    };
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class intrusive_forward_list;
+
+      const_iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      const_iterator(const value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      const_iterator(const typename intrusive_forward_list::iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      const value_type* p_value;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    intrusive_forward_list()
+    {
+      this->initialise();
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~intrusive_forward_list()
+    {
+      this->clear();
+    }
+
+    //*************************************************************************
+    /// Constructor from range
+    //*************************************************************************
+    template <typename TIterator>
+    intrusive_forward_list(TIterator first, TIterator last)
+    {
+      this->assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(static_cast<value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    iterator before_begin()
+    {
+      return iterator(static_cast<value_type&>(this->start_link));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator before_begin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->start_link));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return static_cast<value_type&>(this->get_head());
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return static_cast<const value_type&>(this->get_head());;
+    }
+
+    //*************************************************************************
+    /// Inserts a value to the intrusive_forward_list after the specified position.
+    //*************************************************************************
+    iterator insert_after(iterator position, value_type& value)
+    {
+      this->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)
+    {
+      while (first != last)
+      {
+        // Set up the next free link.
+        this->insert_link_after(*position.p_value, *first++);
+        ++position;
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase_after(iterator position)
+    {
+      iterator next(position);
+      if (next != end())
+      {
+        ++next;
+        if (next != end())
+        {
+          ++next;
+          this->remove_link_after(*position.p_value);
+        }
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase_after(iterator first, iterator last)
+    {
+      if (first != end() && (first != last))
+      {
+        this->current_size -= std::distance(first, last) - 1;
+
+        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);
+
+        if (p_next == std::nullptr)
+        {
+          return end();
+        }
+        else
+        {
+          return last;
+        }
+      }
+      else
+      {
+        return last;
+      }
+    }
+
+    //*************************************************************************
+    /// Removes all but the one element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    template <typename TIsEqual>
+    void unique(TIsEqual isEqual)
+    {
+      if (this->empty())
+      {
+        return;
+      }
+
+      link_type* last    = &this->get_head();
+      link_type* current = last->etl_next;
+
+      while (current != std::nullptr)
+      {
+        // Is this value the same as the last?
+        if (isEqual(*static_cast<value_type*>(current), *static_cast<value_type*>(last)))
+        {
+          this->remove_link_after(*last);
+        }
+        else
+        {
+          // Move on one.
+          last = current;
+        }
+
+        current = last->etl_next;
+      }
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    //*************************************************************************
+    void sort()
+    {
+      sort(std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses a supplied predicate function or functor.
+    /// This is not my algorithm. I got it off the web somewhere.
+    //*************************************************************************
+    template <typename TCompare>
+    void sort(TCompare compare)
+    {
+      iterator i_left;
+      iterator i_right;
+      iterator i_link;
+      iterator i_head;
+      iterator i_tail;
+      int      list_size = 1;
+      int      number_of_merges;
+      int      left_size;
+      int      right_size;
+
+      if (this->is_trivial_list())
+      {
+        return;
+      }
+
+      while (true)
+      {
+        i_left = begin();
+        i_head = before_begin();
+        i_tail = before_begin();
+
+        number_of_merges = 0;  // Count the number of merges we do in this pass.
+
+        while (i_left != end())
+        {
+          ++number_of_merges;  // There exists a merge to be done.
+          i_right = i_left;
+          left_size = 0;
+
+          // Step 'list_size' places along from left
+          for (int i = 0; i < list_size; ++i)
+          {
+            ++left_size;
+
+            ++i_right;
+
+            if (i_right == end())
+            {
+              break;
+            }
+          }
+
+          // If right hasn't fallen off end, we have two lists to merge.
+          right_size = list_size;
+
+          // Now we have two lists. Merge them.
+          while (left_size > 0 || (right_size > 0 && i_right != end()))
+          {
+            // Decide whether the next link of merge comes from left or right.
+            if (left_size == 0)
+            {
+              // Left is empty. The link must come from right.
+              i_link = i_right;
+              ++i_right;
+              --right_size;
+            }
+            else if (right_size == 0 || i_right == end())
+            {
+              // Right is empty. The link must come from left.
+              i_link = i_left;
+              ++i_left;
+              --left_size;
+            }
+            else if (!compare(*i_right, *i_left))
+            {
+              // First link of left is lower or same. The link must come from left.
+              i_link = i_left;
+              ++i_left;
+              --left_size;
+            }
+            else
+            {
+              // First link of right is lower. The link must come from right.
+              i_link  = i_right;
+              ++i_right;
+              --right_size;
+            }
+
+            // Add the next link to the merged head.
+            if (i_head == before_begin())
+            {
+              etl::link<link_type>(i_head.p_value, i_link.p_value);
+              i_head = i_link;
+              i_tail = i_link;
+            }
+            else
+            {
+              etl::link<link_type>(i_tail.p_value, i_link.p_value);
+              i_tail = i_link;
+            }
+
+            i_tail.p_value->link_type::etl_next = std::nullptr;
+          }
+
+          // Now left has stepped `list_size' places along, and right has too.
+          i_left = i_right;
+        }
+
+        // If we have done only one merge, we're finished.
+        if (number_of_merges <= 1)   // Allow for number_of_merges == 0, the empty head case
+        {
+            return;
+        }
+
+        // Otherwise repeat, merging lists twice the size
+        list_size *= 2;
+      }
+    }
+
+    //*************************************************************************
+    // Removes the values specified.
+    //*************************************************************************
+    void remove(const_reference value)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (*i_item == value)
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes according to a predicate.
+    //*************************************************************************
+    template <typename TPredicate>
+    void remove_if(TPredicate predicate)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (predicate(*i_item))
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice another list into this one.
+    //*************************************************************************
+    void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other)
+    {
+      // No point splicing to ourself!
+      if (&other != this)
+      {
+        if (!other.empty())
+        {
+          link_type& first = other.get_head();
+
+          if (&other != this)
+          {
+            this->current_size += other.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 != std::nullptr)
+          {
+            last = last->link_type::etl_next;
+          }
+
+          etl::link<link_type>(last, after);
+
+          other.initialise();
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice an element from another list into this one.
+    //*************************************************************************
+    void splice(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, 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 (&other != this)
+      {
+        ++this->current_size;
+        --other.current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Splice a range of elements from another list into this one.
+    //*************************************************************************
+    void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, iterator begin_, iterator end_)
+    {
+      if (!other.empty())
+      {
+        if (&other != this)
+        {
+          size_t n = std::distance(begin_, end_) - 1;
+          this->current_size += n;
+          other.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& other)
+    {
+      merge(other, std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    template <typename TCompare>
+    void merge(list_type& other, TCompare compare)
+    {
+      if (!other.empty())
+      {
+#if defined(ETL_DEBUG)
+        ETL_ASSERT(etl::is_sorted(other.begin(), other.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*>(&other.get_head());
+        value_type* other_terminal = std::nullptr;
+
+        value_type* before      = static_cast<value_type*>(&this->start_link);
+        value_type* before_next = get_next(before);
+        value_type* terminal    = std::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);
+          }
+        }
+
+        this->current_size += other.size();
+
+        other.initialise();
+      }
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Get the next value.
+    //*************************************************************************
+    value_type* get_next(link_type* link) const
+    {
+      return static_cast<value_type*>(link->etl_next);
+    }
+
+    // Disabled.
+    intrusive_forward_list(const intrusive_forward_list& other);
+    intrusive_forward_list& operator = (const intrusive_forward_list& rhs);
+  };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+