vibe-core/source/vibe/internal/list.d
2017-09-27 16:41:11 +02:00

202 lines
3.8 KiB
D

module vibe.internal.list;
import core.atomic;
struct CircularDList(T)
{
private {
T m_pivot;
}
this(T pivot)
{
assert(pivot.prev is null && pivot.next is null);
pivot.next = pivot.prev = pivot;
m_pivot = pivot;
assert(this.empty);
}
bool empty() const { return m_pivot.next is m_pivot; }
@property T front() { return m_pivot.next is m_pivot ? null : m_pivot.next; }
@property T back() { return m_pivot.prev is m_pivot ? null : m_pivot.prev; }
void remove(T elem)
{
assert(elem !is m_pivot);
elem.prev.next = elem.next;
elem.next.prev = elem.prev;
elem.prev = elem.next = null;
}
void insertBefore(T elem, T pivot)
{
assert(elem.prev is null && elem.next is null);
elem.prev = pivot.prev;
elem.next = pivot;
pivot.prev.next = elem;
pivot.prev = elem;
}
void insertAfter(T elem, T pivot)
{
assert(elem.prev is null && elem.next is null);
elem.prev = pivot;
elem.next = pivot.next;
pivot.next.prev = elem;
pivot.next = elem;
}
void insertFront(T elem) { insertAfter(elem, m_pivot); }
void insertBack(T elem) { insertBefore(elem, m_pivot); }
// NOTE: allowed to remove the current element
int opApply(int delegate(T) @safe nothrow del)
@safe nothrow {
T prev = m_pivot;
debug size_t counter = 0;
while (prev.next !is m_pivot) {
auto el = prev.next;
if (auto ret = del(el))
return ret;
if (prev.next is el)
prev = prev.next;
debug assert (++counter < 1_000_000, "Cycle in list?");
}
return 0;
}
}
unittest {
static final class C {
C prev, next;
int i;
this(int i) { this.i = i; }
}
alias L = CircularDList!C;
auto l = L(new C(0));
assert(l.empty);
auto c = new C(1);
l.insertBack(c);
assert(!l.empty);
assert(l.front is c);
assert(l.back is c);
foreach (c; l) assert(c.i == 1);
auto c2 = new C(2);
l.insertFront(c2);
assert(!l.empty);
assert(l.front is c2);
assert(l.back is c);
foreach (c; l) assert(c.i == 1 || c.i == 2);
l.remove(c);
assert(!l.empty);
assert(l.front is c2);
assert(l.back is c2);
foreach (c; l) assert(c.i == 2);
l.remove(c2);
assert(l.empty);
}
struct StackSList(T)
{
@safe nothrow:
import core.atomic : cas;
private T m_first;
@property T first() { return m_first; }
@property T front() { return m_first; }
bool empty() const { return m_first is null; }
void add(T elem)
{
debug iterate((el) { assert(el !is elem, "Double-insertion of list element."); return true; });
elem.next = m_first;
m_first = elem;
}
bool remove(T elem)
{
debug uint counter = 0;
T w = m_first, wp;
while (w !is elem) {
if (!w) return false;
wp = w;
w = w.next;
debug assert(++counter < 1_000_000, "Cycle in linked list?");
}
if (wp) wp.next = w.next;
else m_first = w.next;
return true;
}
void filter(scope bool delegate(T el) @safe nothrow del)
{
debug uint counter = 0;
T w = m_first, pw;
while (w !is null) {
auto wnext = w.next;
if (!del(w)) {
if (pw) pw.next = wnext;
else m_first = wnext;
} else pw = w;
w = wnext;
debug assert(++counter < 1_000_000, "Cycle in linked list?");
}
}
void iterate(scope bool delegate(T el) @safe nothrow del)
{
debug uint counter = 0;
T w = m_first;
while (w !is null) {
auto wnext = w.next;
if (!del(w)) break;
w = wnext;
debug assert(++counter < 1_000_000, "Cycle in linked list?");
}
}
}
unittest {
static final class C {
C next;
int i;
this(int i) { this.i = i; }
}
alias L = StackSList!C;
L l;
assert(l.empty);
auto c = new C(1);
l.add(c);
assert(!l.empty);
assert(l.front is c);
l.iterate((el) { assert(el.i == 1); return true; });
auto c2 = new C(2);
l.add(c2);
assert(!l.empty);
assert(l.front is c2);
l.iterate((el) { assert(el.i == 1 || el.i == 2); return true; });
l.remove(c);
assert(!l.empty);
assert(l.front is c2);
l.iterate((el) { assert(el.i == 2); return true; });
l.filter((el) => el.i == 0);
assert(l.empty);
}