[coco] Add 'DLinkedList' traits (#703)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Thu, 19 Jul 2018 05:41:22 +0000 (14:41 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 19 Jul 2018 05:41:22 +0000 (14:41 +0900)
* [coco] Add 'DLinkedList' traits

This commit adds 'DLinkedList<Child, Parent>::Node' and
'DLinkedList<Child, Parent>::Head' traits.

coco IR entities will use these traits to support traverse and
manipulation of the order of entities.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
* Update assert per feedback

contrib/coco/core/include/coco/ADT/DLinkedList.h [new file with mode: 0644]
contrib/coco/core/src/ADT/DLinkedList.test.cpp [new file with mode: 0644]

diff --git a/contrib/coco/core/include/coco/ADT/DLinkedList.h b/contrib/coco/core/include/coco/ADT/DLinkedList.h
new file mode 100644 (file)
index 0000000..bf19fe9
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef __COCO_ADT_DLINKED_LIST_H__
+#define __COCO_ADT_DLINKED_LIST_H__
+
+#include "coco/ADT/PtrLink.h"
+
+#include <cassert>
+
+namespace coco
+{
+
+// **CAUTION** Child SHOULD inherit DLinkedList<Child, Parent>::Node
+template<typename Child, typename Parent> struct DLinkedList
+{
+  class Head
+  {
+  public:
+    Head(Parent *parent, PtrLink<Child, Parent> *link) : _parent{parent}, _link{link}
+    {
+      _head = nullptr;
+      _tail = nullptr;
+    }
+
+  public:
+    Head(const Head &) = delete;
+    Head(Head &&) = delete;
+
+  public:
+    Child *head(void) const { return _head; }
+    Child *tail(void) const { return _tail; }
+
+  public:
+    bool empty(void) const
+    {
+      if (_head == nullptr)
+      {
+        assert(_head == _tail);
+        return true;
+      }
+
+      assert(_head != nullptr);
+      assert(_tail != nullptr);
+      return false;
+    }
+
+  public:
+    void enlist(Child *child)
+    {
+      assert((child->prev() == nullptr) || (child->prev()->parent() == _parent));
+      assert((child->next() == nullptr) || (child->next()->parent() == _parent));
+
+      if (empty())
+      {
+        _head = child;
+        _tail = child;
+      }
+      else
+      {
+        if (child->next() == _head)
+        {
+          // _child is a new head
+          assert(child->prev() == nullptr);
+          _head = child;
+        }
+
+        if (child->prev() == _tail)
+        {
+          // _child is a new tail
+          assert(child->next() == nullptr);
+          _tail = child;
+        }
+      }
+
+      // Update parent-child relation
+      _link->set(child, _parent);
+    }
+
+  public:
+    void append(Child *child)
+    {
+      if (empty())
+      {
+        enlist(child);
+      }
+      else
+      {
+        child->insertAfter(_tail);
+      }
+    }
+
+  private:
+    Parent * const _parent;
+    PtrLink<Child, Parent> * const _link;
+
+  private:
+    Child * _head;
+    Child * _tail;
+  };
+
+  class Node
+  {
+  public:
+    Node(const PtrLink<Child, Parent> *link) : _link{link}
+    {
+      _prev = nullptr;
+      _next = nullptr;
+    }
+
+  public:
+    virtual ~Node() = default;
+
+  public:
+    Parent *parent(void) const { return _link->find(reinterpret_cast<const Child *>(this)); }
+
+  public:
+    Child *prev(void) const { return _prev; }
+    Child *next(void) const { return _next; }
+
+  public:
+    virtual Head *head(void) const = 0;
+
+  public:
+    void insertAfter(Child *prev)
+    {
+      assert(prev != nullptr);
+      assert(prev->head() != nullptr);
+
+      assert(_prev == nullptr);
+      assert(_next == nullptr);
+
+      // REQUIRE Child should inherit Node class
+      auto curr = reinterpret_cast<Child *>(this);
+
+      // Update the link of the current node
+      _prev = prev;
+      _next = prev->next();
+
+      // Update the link of the sibling nodes
+      if (auto next = prev->next())
+      {
+        next->_prev = curr;
+      }
+      prev->_next = curr;
+
+      // Update parent-child relation
+      assert(parent() == nullptr);
+      prev->head()->enlist(curr);
+      assert(parent() == prev->parent());
+    };
+
+  private:
+    const PtrLink<Child, Parent> * const _link;
+
+  private:
+    Child *_prev;
+    Child *_next;
+  };
+};
+
+} // namespace coco
+
+#endif // __COCO_ADT_DLINKED_LIST_H__
diff --git a/contrib/coco/core/src/ADT/DLinkedList.test.cpp b/contrib/coco/core/src/ADT/DLinkedList.test.cpp
new file mode 100644 (file)
index 0000000..8459df3
--- /dev/null
@@ -0,0 +1,88 @@
+#include "coco/ADT/DLinkedList.h"
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+class Parent;
+class Child;
+
+using ChildList = coco::DLinkedList<Child, Parent>::Head;
+
+class Parent
+{
+public:
+  Parent(coco::PtrLink<Child, Parent> *link) : _list{this, link}
+  {
+    // DO NOTHING
+  }
+
+public:
+  ChildList *children(void) { return &_list; }
+
+private:
+  ChildList _list;
+};
+
+class Child : public coco::DLinkedList<Child, Parent>::Node
+{
+public:
+  Child(const coco::PtrLink<Child, Parent> *link) : coco::DLinkedList<Child, Parent>::Node{link}
+  {
+    // DO NOTHING
+  }
+
+public:
+  ChildList *head(void) const override { return parent()->children(); }
+};
+
+} // namespace
+
+TEST(ADT_DLINKED_LINK, insert_two_elements)
+{
+  auto link = new coco::PtrLink<::Child, ::Parent>{};
+  auto parent = new ::Parent{link};
+
+  ASSERT_EQ(parent->children()->head(), nullptr);
+  ASSERT_EQ(parent->children()->tail(), nullptr);
+
+  auto child_1 = new ::Child{link};
+
+  ASSERT_EQ(child_1->parent(), nullptr);
+  ASSERT_EQ(child_1->prev(), nullptr);
+  ASSERT_EQ(child_1->next(), nullptr);
+
+  parent->children()->append(child_1);
+
+  ASSERT_EQ(child_1->parent(), parent);
+  ASSERT_EQ(child_1->prev(), nullptr);
+  ASSERT_EQ(child_1->next(), nullptr);
+
+  ASSERT_EQ(parent->children()->head(), child_1);
+  ASSERT_EQ(parent->children()->tail(), child_1);
+
+  auto child_2 = new ::Child{link};
+
+  ASSERT_EQ(child_2->parent(), nullptr);
+  ASSERT_EQ(child_2->prev(), nullptr);
+  ASSERT_EQ(child_2->next(), nullptr);
+
+  child_2->insertAfter(child_1);
+
+  ASSERT_EQ(child_2->parent(), parent);
+  ASSERT_EQ(child_2->prev(), child_1);
+  ASSERT_EQ(child_2->next(), nullptr);
+
+  ASSERT_EQ(child_1->parent(), parent);
+  ASSERT_EQ(child_1->prev(), nullptr);
+  ASSERT_EQ(child_1->next(), child_2);
+
+  ASSERT_EQ(parent->children()->head(), child_1);
+  ASSERT_EQ(parent->children()->tail(), child_2);
+
+  delete child_2;
+  delete child_1;
+  delete parent;
+  delete link;
+}