blob: 9ce83c22655ca9ed6d41a306627d7608b9d90d96 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
namespace overnet {
template <class T>
class InternalListNode;
template <class T, InternalListNode<T> T::*NodePtr>
class InternalList;
template <class T>
class InternalListNode {
template <class U, InternalListNode<U> U::*NodePtr>
friend class InternalList;
public:
InternalListNode() = default;
InternalListNode(const InternalListNode&) = delete;
InternalListNode& operator=(const InternalListNode&) = delete;
~InternalListNode() { assert(owner_ == nullptr); }
private:
T* next_ = nullptr;
T* prev_ = nullptr;
#ifndef NDEBUG
void* owner_ = nullptr;
#endif
};
template <class T, InternalListNode<T> T::*NodePtr>
class InternalList {
public:
InternalList() = default;
InternalList(const InternalList&) = delete;
InternalList& operator=(const InternalList&) = delete;
~InternalList() {
while (head_) Remove(head_);
}
T* Front() { return head_; }
bool Empty() const { return head_ == nullptr; }
void PushBack(T* p) {
#ifndef NDEBUG
assert(Node(p)->owner_ == nullptr);
Node(p)->owner_ = this;
#endif
assert(Node(p)->next_ == nullptr);
assert(Node(p)->prev_ == nullptr);
if (tail_ == nullptr) {
assert(head_ == nullptr);
head_ = tail_ = p;
} else {
assert(Node(tail_)->next_ == nullptr);
Node(p)->prev_ = tail_;
Node(tail_)->next_ = p;
tail_ = p;
}
size_++;
}
void PushFront(T* p) {
#ifndef NDEBUG
assert(Node(p)->owner_ == nullptr);
Node(p)->owner_ = this;
#endif
assert(Node(p)->next_ == nullptr);
assert(Node(p)->prev_ == nullptr);
if (head_ == nullptr) {
assert(tail_ == nullptr);
head_ = tail_ = p;
} else {
assert(Node(head_)->prev_ == nullptr);
Node(p)->next_ = head_;
Node(head_)->prev_ = p;
head_ = p;
}
size_++;
}
void Remove(T* p) {
#ifndef NDEBUG
assert(Node(p)->owner_ == this);
Node(p)->owner_ = nullptr;
#endif
if (p == head_) {
head_ = Node(p)->next_;
if (head_ == nullptr) {
assert(p == tail_);
head_ = tail_ = nullptr;
} else {
Node(head_)->prev_ = nullptr;
}
} else if (p == tail_) {
tail_ = Node(p)->prev_;
assert(tail_ != nullptr); // otherwise p == head_ at start is true
Node(tail_)->next_ = nullptr;
} else {
Node(Node(p)->next_)->prev_ = Node(p)->prev_;
Node(Node(p)->prev_)->next_ = Node(p)->next_;
}
Node(p)->next_ = Node(p)->prev_ = nullptr;
size_--;
}
T* PopFront() {
T* p = Front();
if (p) Remove(p);
return p;
}
class Iterator {
public:
Iterator(T* node) : p_(node) {}
bool operator!=(Iterator other) const { return p_ != other.p_; }
Iterator& operator++() {
p_ = Node(p_)->next_;
return *this;
}
T* operator*() { return p_; }
private:
T* p_;
};
Iterator begin() { return Iterator(head_); }
Iterator end() { return Iterator(nullptr); }
size_t Size() const { return size_; }
private:
static InternalListNode<T>* Node(T* p) { return &(p->*NodePtr); }
T* head_ = nullptr;
T* tail_ = nullptr;
size_t size_ = 0;
};
} // namespace overnet