Skip to content

Commit

Permalink
src: add typesafe intrusive list
Browse files Browse the repository at this point in the history
This is a replacement for the QUEUE macros.  It implements the same
functionality but in a way that lets the compiler typecheck it.

PR-URL: #667
Reviewed-By: Bert Belder <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Trevor Norris <[email protected]>
  • Loading branch information
bnoordhuis committed Feb 11, 2015
1 parent 7061669 commit 58eb00c
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 0 deletions.
102 changes: 102 additions & 0 deletions src/util-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,108 @@

namespace node {

template <typename T>
ListNode<T>::ListNode() : prev_(this), next_(this) {}

template <typename T>
ListNode<T>::~ListNode() {
Remove();
}

template <typename T>
void ListNode<T>::Remove() {
prev_->next_ = next_;
next_->prev_ = prev_;
prev_ = this;
next_ = this;
}

template <typename T>
bool ListNode<T>::IsEmpty() const {
return prev_ == this;
}

template <typename T, ListNodeMember(T) M>
ListHead<T, M>::Iterator::Iterator(ListNode<T>* node) : node_(node) {}

template <typename T, ListNodeMember(T) M>
T* ListHead<T, M>::Iterator::operator*() const {
return ContainerOf(M, node_);
}

template <typename T, ListNodeMember(T) M>
const typename ListHead<T, M>::Iterator&
ListHead<T, M>::Iterator::operator++() {
node_ = node_->next_;
return *this;
}

template <typename T, ListNodeMember(T) M>
bool ListHead<T, M>::Iterator::operator!=(const Iterator& that) const {
return node_ != that.node_;
}

template <typename T, ListNodeMember(T) M>
ListHead<T, M>::~ListHead() {
while (IsEmpty() == false)
head_.next_->Remove();
}

template <typename T, ListNodeMember(T) M>
void ListHead<T, M>::MoveBack(ListHead* that) {
if (IsEmpty())
return;
ListNode<T>* to = &that->head_;
head_.next_->prev_ = to->prev_;
to->prev_->next_ = head_.next_;
head_.prev_->next_ = to;
to->prev_ = head_.prev_;
head_.prev_ = &head_;
head_.next_ = &head_;
}

template <typename T, ListNodeMember(T) M>
void ListHead<T, M>::PushBack(T* element) {
ListNode<T>* that = &(element->*M);
head_.prev_->next_ = that;
that->prev_ = head_.prev_;
that->next_ = &head_;
head_.prev_ = that;
}

template <typename T, ListNodeMember(T) M>
void ListHead<T, M>::PushFront(T* element) {
ListNode<T>* that = &(element->*M);
head_.next_->prev_ = that;
that->prev_ = &head_;
that->next_ = head_.next_;
head_.next_ = that;
}

template <typename T, ListNodeMember(T) M>
bool ListHead<T, M>::IsEmpty() const {
return head_.IsEmpty();
}

template <typename T, ListNodeMember(T) M>
T* ListHead<T, M>::PopFront() {
if (IsEmpty())
return nullptr;
ListNode<T>* node = head_.next_;
node->Remove();
return ContainerOf(M, node);
}

template <typename T, ListNodeMember(T) M>
typename ListHead<T, M>::Iterator ListHead<T, M>::begin() const {
return Iterator(head_.next_);
}

template <typename T, ListNodeMember(T) M>
typename ListHead<T, M>::Iterator ListHead<T, M>::end() const {
return Iterator(const_cast<ListNode<T>*>(&head_));
}

template <typename Inner, typename Outer>
ContainerOfHelper<Inner, Outer>::ContainerOfHelper(Inner Outer::*field,
Inner* pointer)
Expand Down
63 changes: 63 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,69 @@ namespace node {

#define UNREACHABLE() abort()

// TAILQ-style intrusive list node.
template <typename T>
class ListNode;

template <typename T>
using ListNodeMember = ListNode<T> T::*;

// VS 2013 doesn't understand dependent templates.
#ifdef _MSC_VER
#define ListNodeMember(T) ListNodeMember
#else
#define ListNodeMember(T) ListNodeMember<T>
#endif

// TAILQ-style intrusive list head.
template <typename T, ListNodeMember(T) M>
class ListHead;

template <typename T>
class ListNode {
public:
inline ListNode();
inline ~ListNode();
inline void Remove();
inline bool IsEmpty() const;

private:
template <typename U, ListNodeMember(U) M> friend class ListHead;
ListNode* prev_;
ListNode* next_;
DISALLOW_COPY_AND_ASSIGN(ListNode);
};

template <typename T, ListNodeMember(T) M>
class ListHead {
public:
class Iterator {
public:
inline T* operator*() const;
inline const Iterator& operator++();
inline bool operator!=(const Iterator& that) const;

private:
friend class ListHead;
inline explicit Iterator(ListNode<T>* node);
ListNode<T>* node_;
};

inline ListHead() = default;
inline ~ListHead();
inline void MoveBack(ListHead* that);
inline void PushBack(T* element);
inline void PushFront(T* element);
inline bool IsEmpty() const;
inline T* PopFront();
inline Iterator begin() const;
inline Iterator end() const;

private:
ListNode<T> head_;
DISALLOW_COPY_AND_ASSIGN(ListHead);
};

// The helper is for doing safe downcasts from base types to derived types.
template <typename Inner, typename Outer>
class ContainerOfHelper {
Expand Down

0 comments on commit 58eb00c

Please sign in to comment.