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

Revision:
0:b47c2a7920c2
diff -r 000000000000 -r b47c2a7920c2 intrusive_links.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_links.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,795 @@
+///\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_LINKS__
+#define __ETL_INTRUSIVE_LINKS__
+
+#include <assert.h>
+#include <utility>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "22"
+
+//*****************************************************************************
+// 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
+{
+  //***************************************************************************
+  /// Link exception.
+  //***************************************************************************
+  class link_exception : public etl::exception
+  {
+  public:
+
+    link_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, 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_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// A forward link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct forward_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_next = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return etl_next != std::nullptr;
+      }
+
+      forward_link* etl_next;
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink& rhs)
+  {
+    lhs.etl_next = &rhs;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& rhs)
+  {
+    rhs.etl_next = lhs.etl_next;
+    lhs.etl_next = &rhs;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = rhs;
+    }
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      if (rhs != std::nullptr)
+      {
+          rhs->etl_next = lhs->etl_next;
+      }
+
+      lhs->etl_next = rhs;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink* rhs)
+  {
+    lhs.etl_next = rhs;
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_next = lhs.etl_next;
+    }
+
+    lhs.etl_next = rhs;
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &rhs;
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      rhs.etl_next  = lhs->etl_next;
+      lhs->etl_next = &rhs;
+    }
+  }
+
+  // Reference, Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::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> >::value, void>::type
+  link_splice(TLink* lhs, TLink& first, TLink& last)
+  {
+    if (lhs != std::nullptr)
+    {
+      last.etl_next = lhs->etl_next;
+      lhs->etl_next  = &first;
+    }
+    else
+    {
+      last.etl_next = std::nullptr;
+    }
+  }
+
+  // Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  unlink_after(TLink& node)
+  {
+    if (node.etl_next != std::nullptr)
+    {
+      TLink* unlinked_node = node.etl_next;
+      node.etl_next = unlinked_node->etl_next;
+    }
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  unlink_after(TLink& before, TLink& last)
+  {
+    before.etl_next = last.etl_next;
+  }
+
+  //***************************************************************************
+  /// A bidirectional link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct bidirectional_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_previous = std::nullptr;
+        etl_next     = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return (etl_previous != std::nullptr) || (etl_next != std::nullptr);
+      }
+
+      void reverse()
+      {
+        std::swap(etl_previous, etl_next);
+      }
+
+      bidirectional_link* etl_previous;
+      bidirectional_link* etl_next;
+
+    void unlink()
+    {
+        // Connect the previous link with the next.
+        if (etl_previous != std::nullptr)
+        {
+          etl_previous->etl_next = etl_next;
+        }
+
+        // Connect the next link with the previous.
+        if (etl_next != std::nullptr)
+        {
+          etl_next->etl_previous = etl_previous;
+        }
+    }
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink& rhs)
+  {
+    lhs.etl_next     = &rhs;
+    rhs.etl_previous = &lhs;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& rhs)
+  {
+    rhs.etl_next     = lhs.etl_next;
+    rhs.etl_previous = &lhs;
+
+    if (lhs.etl_next != std::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> >::value, void>::type
+  link(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = rhs;
+    }
+
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_previous = lhs;
+    }
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      if (lhs != std::nullptr)
+      {
+        rhs->etl_next = lhs->etl_next;
+      }
+
+      rhs->etl_previous = lhs;
+    }
+
+    if (lhs != std::nullptr)
+    {
+      if (lhs->etl_next != std::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> >::value, void>::type
+  link(TLink& lhs, TLink* rhs)
+  {
+    lhs.etl_next = rhs;
+
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_previous = &lhs;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_next     = lhs.etl_next;
+      rhs->etl_previous = &lhs;
+    }
+
+    if (lhs.etl_next != std::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> >::value, void>::type
+  link(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &rhs;
+    }
+
+    rhs.etl_previous = lhs;
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      rhs.etl_next = lhs->etl_next;
+    }
+
+    rhs.etl_previous = lhs;
+
+    if (lhs != std::nullptr)
+    {
+      if (lhs->etl_next != std::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> >::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 != std::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> >::value, void>::type
+  link_splice(TLink* lhs, TLink& first, TLink& last)
+  {
+    if (lhs != std::nullptr)
+    {
+      last.etl_next = lhs->etl_next;
+    }
+    else
+    {
+      last.etl_next = std::nullptr;
+    }
+
+    first.etl_previous = lhs;
+
+    if (last.etl_next != std::nullptr)
+    {
+      last.etl_next->etl_previous = &last;
+    }
+
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &first;
+    }
+  }
+
+  // Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  unlink(TLink& node)
+  {
+    node.unlink();
+  }
+
+  // Reference Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  unlink(TLink& first, TLink& last)
+  {
+    if (&first == &last)
+    {
+      first.unlink();
+    }
+    else
+    {
+      if (last.etl_next != std::nullptr)
+      {
+        last.etl_next->etl_previous = first.etl_previous;
+      }
+
+      if (first.etl_previous != std::nullptr)
+      {
+        first.etl_previous->etl_next = last.etl_next;
+      }
+    }
+  }
+
+  //***************************************************************************
+  /// A binary tree link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct tree_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_parent = std::nullptr;
+        etl_left   = std::nullptr;
+        etl_right  = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return (etl_parent != std::nullptr) || (etl_left != std::nullptr) || (etl_right != std::nullptr);
+      }
+
+      tree_link* etl_parent;
+      tree_link* etl_left;
+      tree_link* etl_right;
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink& parent, TLink& leaf)
+  {
+    parent.etl_left = &leaf;
+    leaf.etl_parent = &parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink& parent, TLink& leaf)
+  {
+    parent.etl_right = &leaf;
+    leaf.etl_parent  = &parent;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink* parent, TLink* leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_left = leaf;
+    }
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = parent;
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink* parent, TLink* leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_right = leaf;
+    }
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = parent;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink& parent, TLink* leaf)
+  {
+    parent.etl_left = leaf;
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = &parent;
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink& parent, TLink* leaf)
+  {
+    parent.etl_right = leaf;
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = &parent;
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_left = &leaf;
+    }
+
+    leaf.etl_parent = parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_right = &leaf;
+    }
+
+    leaf.etl_parent = parent;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink& parent, TLink& leaf)
+  {
+     parent.etl_right = leaf.etl_left;
+
+     if (parent.etl_right != std::nullptr)
+     {
+       parent.etl_right->etl_parent = &parent;
+     }
+
+     leaf.etl_parent   = parent.etl_parent;
+     parent.etl_parent = &leaf;
+     leaf.etl_left     = &parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink& parent, TLink& leaf)
+  {
+     parent.etl_left = leaf.etl_right;
+
+     if (parent.etl_left != std::nullptr)
+     {
+       parent.etl_left->etl_parent = &parent;
+     }
+
+     leaf.etl_parent   = parent.etl_parent;
+     parent.etl_parent = &leaf;
+     leaf.etl_right    = &parent;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      link_rotate_left(*parent, *leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      link_rotate_right(*parent, *leaf);
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      link_rotate_left(parent, *leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      link_rotate_right(parent, *leaf);
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      link_rotate_left(*parent, leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      link_rotate_right(*parent, leaf);
+    }
+  }
+
+  // Reference, Reference
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink& parent, TLink& leaf)
+  {
+    if (parent.etl_left == &leaf)
+    {
+      etl::link_rotate_right(parent, leaf);
+    }
+    else
+    {
+      etl::link_rotate_left(parent, leaf);
+    }
+  }
+
+  // Pointer, Pointer
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      if (parent->etl_left == leaf)
+      {
+        etl::link_rotate_right(*parent, *leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(*parent, *leaf);
+      }
+    }
+  }
+
+  // Reference, Pointer
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      if (parent.etl_left == leaf)
+      {
+        etl::link_rotate_right(parent, *leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(parent, *leaf);
+      }
+    }
+  }
+
+  // Pointer, Reference
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      if (parent->etl_left == &leaf)
+      {
+        etl::link_rotate_right(*parent, leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(*parent, leaf);
+      }
+    }
+  }
+}
+
+#undef ETL_FILE
+#endif
+