summaryrefslogtreecommitdiff
path: root/compiler/coco/core/include/coco/ADT/DLinkedList.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/coco/core/include/coco/ADT/DLinkedList.h')
-rw-r--r--compiler/coco/core/include/coco/ADT/DLinkedList.h288
1 files changed, 288 insertions, 0 deletions
diff --git a/compiler/coco/core/include/coco/ADT/DLinkedList.h b/compiler/coco/core/include/coco/ADT/DLinkedList.h
new file mode 100644
index 000000000..e3c275041
--- /dev/null
+++ b/compiler/coco/core/include/coco/ADT/DLinkedList.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COCO_ADT_DLINKED_LIST_H__
+#define __COCO_ADT_DLINKED_LIST_H__
+
+#include <cassert>
+#include <type_traits>
+
+namespace coco
+{
+
+// **CAUTION** Child SHOULD inherit DLinkedList<Child, Parent>::Node
+template <typename Child, typename Parent> struct DLinkedList
+{
+ /// @brief A hook for Child-Join event
+ static void joined(Parent *, Child *);
+ /// @brief A hook for Child-Leave event
+ static void leaving(Parent *, Child *);
+
+ class Head
+ {
+ public:
+ Head(Parent *parent) : _parent{parent}
+ {
+ _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
+ child->parent(_parent);
+
+ // Notify Child-Joining event
+ joined(_parent, child);
+ }
+
+ public:
+ void delist(Child *child)
+ {
+ assert(child->parent() == _parent);
+ assert(!empty());
+
+ // Notify Child-Leaving event
+ leaving(_parent, child);
+
+ if (child == _head)
+ {
+ _head = child->next();
+ }
+
+ if (child == _tail)
+ {
+ _tail = child->prev();
+ }
+
+ // Update parent-child relation
+ child->parent(nullptr);
+ }
+
+ public:
+ void prepend(Child *child)
+ {
+ if (empty())
+ {
+ enlist(child);
+ }
+ else
+ {
+ child->insertBefore(_head);
+ }
+ }
+
+ public:
+ void append(Child *child)
+ {
+ if (empty())
+ {
+ enlist(child);
+ }
+ else
+ {
+ child->insertAfter(_tail);
+ }
+ }
+
+ private:
+ Parent *const _parent;
+
+ private:
+ Child *_head;
+ Child *_tail;
+ };
+
+ // NOTE Client SHOULD implement this static method
+ static Head *head(Parent *);
+
+ class Node
+ {
+ public:
+ friend class Head;
+
+ public:
+ Node()
+ {
+ static_assert(std::is_base_of<Node, Child>::value,
+ "Type `Child` must be subclass of `Node`.");
+
+ _prev = nullptr;
+ _next = nullptr;
+ }
+
+ public:
+ virtual ~Node()
+ {
+ // Each Child should unlink itself on destruction
+ //
+ // NOTE detach invokes "leaving" hook which may access the internal of each Child,
+ // so it is not safe to invoke detach here
+ assert(parent() == nullptr);
+ }
+
+ public:
+ Parent *parent(void) const { return _parent; }
+
+ private:
+ Child *curr(void) { return reinterpret_cast<Child *>(this); }
+ const Child *curr(void) const { return reinterpret_cast<const Child *>(this); }
+
+ public:
+ Child *prev(void) const { return _prev; }
+ Child *next(void) const { return _next; }
+
+ public:
+ void insertBefore(Node *next)
+ {
+ assert(next != nullptr);
+ assert(next->parent() != nullptr);
+ assert(head(next->parent()) != nullptr);
+
+ assert(_prev == nullptr);
+ assert(_next == nullptr);
+
+ // Update the link of the current node
+ _prev = next->prev();
+ _next = next->curr();
+
+ if (auto prev = next->prev())
+ {
+ prev->_next = curr();
+ }
+ next->_prev = curr();
+
+ // Update parent-child relation
+ assert(parent() == nullptr);
+ head(next->parent())->enlist(curr());
+ assert(parent() == next->parent());
+ }
+
+ public:
+ void insertAfter(Node *prev)
+ {
+ assert(prev != nullptr);
+ assert(prev->parent() != nullptr);
+ assert(head(prev->parent()) != nullptr);
+
+ assert(_prev == nullptr);
+ assert(_next == nullptr);
+
+ // Update the link of the current node
+ _prev = prev->curr();
+ _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);
+ head(prev->parent())->enlist(curr());
+ assert(parent() == prev->parent());
+ };
+
+ public:
+ void detach(void)
+ {
+ // Update parent-child relation
+ assert(parent() != nullptr);
+ assert(head(parent()) != nullptr);
+ head(parent())->delist(curr());
+ assert(parent() == nullptr);
+
+ // Update the link of sibling nodes
+ if (prev())
+ {
+ prev()->_next = next();
+ }
+
+ if (next())
+ {
+ next()->_prev = prev();
+ }
+
+ // Update the link of the current node
+ _prev = nullptr;
+ _next = nullptr;
+ }
+
+ private:
+ // WARN Do NOT invoke this method outside Head::enlist
+ void parent(Parent *p) { _parent = p; }
+
+ private:
+ // WARN Do NOT modify this field inside Node.
+ Parent *_parent = nullptr;
+ Child *_prev;
+ Child *_next;
+ };
+};
+
+} // namespace coco
+
+#endif // __COCO_ADT_DLINKED_LIST_H__