mirror of
https://github.com/dlang/phobos.git
synced 2025-05-06 19:16:13 +03:00
856 lines
20 KiB
D
856 lines
20 KiB
D
module std.slist;
|
|
|
|
import std.contracts; // enforce
|
|
import std.stdio;
|
|
import std.conv; // testing
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* Singly-linked list. The intent is to make it as efficient as the
|
|
* simplest hand-coded list. Therefore, no tricks are employed - no
|
|
* phantom node, no circularity, no fat iterators, just a straight
|
|
* list of nodes terminated by $(D_PARAM null). Therefore, $(D_PARAM
|
|
* SList) only supports forward iteration, does not have access to its
|
|
* last element, and only supports adding elements to the front or
|
|
* after the current iterator.
|
|
*/
|
|
struct SList(T) {
|
|
private:
|
|
struct Node
|
|
{
|
|
T value;
|
|
//node* prev;
|
|
Node* next;
|
|
}
|
|
Node *root;
|
|
public:
|
|
alias T Value;
|
|
//Alias T* Pointer;
|
|
//Alias T Reference;
|
|
//Alias T ConstReference;
|
|
alias .Iterator!(SList) Iterator;
|
|
|
|
/**
|
|
* Builds a list of $(D_PARAM length) elements, initialized with
|
|
* $(D_PARAM value). */
|
|
static SList opCall(size_t length, T value)
|
|
{
|
|
auto nodes = new Node[length];
|
|
nodes[0].value = value;
|
|
foreach (ref e; nodes[1 .. $])
|
|
{
|
|
e.value = value;
|
|
(&e)[-1].next = &e;
|
|
}
|
|
SList result;
|
|
result.root = &nodes[0];
|
|
return result;
|
|
}
|
|
|
|
// todo: eliminate this duplication
|
|
/**
|
|
* Build a list of $(D_PARAM length) elements, initialized with
|
|
* $(D_PARAM T.init). */
|
|
static SList opCall(size_t length = 0)
|
|
{
|
|
if (!length)
|
|
{
|
|
SList result;
|
|
return result;
|
|
}
|
|
auto nodes = new Node[length];
|
|
foreach (ref e; nodes[1 .. $])
|
|
{
|
|
(&e)[-1].next = &e;
|
|
}
|
|
SList result;
|
|
result.root = &nodes[0];
|
|
return result;
|
|
}
|
|
|
|
// static SList opCall(U)(Iterator!(U) b, Iterator!(U) e)
|
|
// {
|
|
// }
|
|
|
|
// void opAssign(U)(List!(U) rhs)
|
|
// {
|
|
// for (auto i = begin(rhs); i != end(rhs); next(i))
|
|
// {
|
|
// }
|
|
// }
|
|
|
|
/**
|
|
* Compares a list with an array for element-wise equality.
|
|
*/
|
|
int opEquals(U)(const(U)[] v)
|
|
{
|
|
size_t j = 0;
|
|
for (auto i = begin(*this); i != end(*this); next(i))
|
|
{
|
|
if (v.length <= j || v[j++] != get(i)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
template Ref(T)
|
|
{
|
|
alias T Ref;
|
|
}
|
|
|
|
/**
|
|
* Returns an iterator to the head of the list.
|
|
*/
|
|
Iterator!(SList!(T)) begin(T)(ref SList!(T) lst)
|
|
{
|
|
return Iterator!(SList!(T))(lst.root);
|
|
}
|
|
|
|
/**
|
|
* Returns an iterator after the end of the list ($(D_PARAM null) in fact).
|
|
*/
|
|
Iterator!(SList!(T)) end(T)(ref SList!(T) lst)
|
|
{
|
|
return Iterator!(SList!(T))(null);
|
|
}
|
|
|
|
/**
|
|
* Returns the first element in the list. Precondition: $(D_PARAM
|
|
* !isEmpty(lst)).
|
|
*/
|
|
Ref!(T) front(T)(ref SList!(T) lst)
|
|
in
|
|
{
|
|
enforce(lst.root, "Attempting to fetch the front of an empty list");
|
|
}
|
|
body
|
|
{
|
|
return lst.root.value;
|
|
}
|
|
|
|
/**
|
|
* Pushes $(D_PARAM elems) to the front of the list $(D_PARAM lst),
|
|
* and returns an iterator to the root of the list.
|
|
*/
|
|
Iterator!(SList!(T)) pushFront(T, U...)(ref SList!(T) lst, U elems)
|
|
{
|
|
auto newNodes = new lst.Node[elems.length];
|
|
foreach (i, e; elems)
|
|
{
|
|
newNodes[i].value = e;
|
|
if (i + 1 < elems.length) newNodes[i].next = &newNodes[i + 1];
|
|
}
|
|
newNodes[$ - 1].next = lst.root;
|
|
return Iterator!(SList!(T))(lst.root = newNodes.ptr);
|
|
}
|
|
|
|
/**
|
|
* True if and only if $(D_PARAM lst) is empty.
|
|
*/
|
|
bool isEmpty(T)(ref SList!(T) lst)
|
|
{
|
|
return lst.root == null;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
SList!(int) lst;
|
|
assert(isEmpty(lst));
|
|
pushFront(lst, 42);
|
|
assert(!isEmpty(lst));
|
|
assert(front(lst) == 42);
|
|
}
|
|
|
|
/**
|
|
* List iterator. Models forward iteration.
|
|
*/
|
|
|
|
struct Iterator(L : SList!(T), T)
|
|
{
|
|
private L.Node* crt;
|
|
static Iterator opCall(L.Node* n) {
|
|
Iterator r;
|
|
r.crt = n;
|
|
return r;
|
|
}
|
|
static Iterator opCall(L lst) {
|
|
Iterator r;
|
|
r.crt = lst.root;
|
|
return r;
|
|
}
|
|
bool opEquals(Iterator rhs) { return crt == rhs.crt; }
|
|
}
|
|
|
|
/**
|
|
* Read the value pointed to by the iterator.
|
|
*/
|
|
T get(T)(Iterator!(SList!(T)) i)
|
|
{
|
|
return assert(i.crt), i.crt.value;
|
|
}
|
|
|
|
/**
|
|
* Assign to the value pointed to by the iterator.
|
|
*/
|
|
T set(T, U)(ref Iterator!(SList!(T)) i, U rhs)
|
|
{
|
|
return assert(i.crt), i.crt.value = rhs;
|
|
}
|
|
|
|
/**
|
|
* Increment the iterator.
|
|
*/
|
|
void next(T)(ref Iterator!(SList!(T)) i)
|
|
{
|
|
assert(i.crt);
|
|
i.crt = i.crt.next;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
// test uninitialized list
|
|
auto lst = SList!(double)(42);
|
|
uint counter = 0;
|
|
for (auto i = begin(lst); i != end(lst); next(i))
|
|
{
|
|
assert(get(i) != get(i));
|
|
++counter;
|
|
}
|
|
}
|
|
auto lst = SList!(double)(42, 5);
|
|
uint counter = 0;
|
|
for (auto i = begin(lst); i != end(lst); next(i))
|
|
{
|
|
assert(get(i) == 5);
|
|
++counter;
|
|
}
|
|
counter = 0;
|
|
for (auto i = begin(lst); i != end(lst); next(i))
|
|
{
|
|
assert(get(i) == 5);
|
|
if (counter & 1) set(i, 234);
|
|
++counter;
|
|
}
|
|
assert(counter == 42);
|
|
counter = 0;
|
|
for (auto i = begin(lst); i != end(lst); next(i))
|
|
{
|
|
if (counter & 1) assert(get(i) == 234);
|
|
else assert(get(i) == 5);
|
|
++counter;
|
|
}
|
|
assert(counter == 42);
|
|
}
|
|
|
|
/**
|
|
* Pops the element in the front of the list $(D_PARAM lst).
|
|
*/
|
|
void popFront(T)(ref SList!(T) lst)
|
|
{
|
|
assert(lst.root);
|
|
lst.root = lst.root.next;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)(1, 5);
|
|
assert(front(lst) == 5);
|
|
popFront(lst);
|
|
assert(isEmpty(lst));
|
|
}
|
|
|
|
/**
|
|
* Inserts an element with value $(D_PARAM value) in $(D_PARAM lst)
|
|
* after $(D_PARAM i). Returns an iterator to the element just inserted.
|
|
*/
|
|
Iterator!(SList!(T)) insertAfter(T, U)(ref SList!(T) lst,
|
|
Iterator!(SList!(T)) i, U value)
|
|
{
|
|
assert(i.crt);
|
|
auto newNode = new lst.Node;
|
|
newNode.value = value;
|
|
newNode.next = i.crt.next;
|
|
i.crt.next = newNode;
|
|
return Iterator!(SList!(T))(newNode);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)(1, 5);
|
|
assert(front(lst) == 5);
|
|
popFront(lst);
|
|
assert(isEmpty(lst));
|
|
pushFront(lst, 6);
|
|
auto i = begin(lst);
|
|
insertAfter(lst, i, 43);
|
|
assert(get(i) == 6);
|
|
next(i);
|
|
assert(get(i) == 43);
|
|
next(i);
|
|
assert(i == end(lst));
|
|
}
|
|
|
|
/**
|
|
* Pushes a range to the front of the list $(D_PARAM lst), and returns
|
|
* an iterator to the last element inserted.
|
|
*/
|
|
void insertAfter(T, U)(ref SList!(T) lst, Iterator!(SList!(T)) i,
|
|
Iterator!(U) begin, Iterator!(U) end)
|
|
{
|
|
for (; begin != end; next(begin))
|
|
{
|
|
i = insertAfter(lst, i, get(begin));
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)(2, 5);
|
|
auto lst1 = SList!(int)(2, 44);
|
|
auto i = begin(lst);
|
|
//next(i);
|
|
insertAfter(lst, i, begin(lst1), end(lst1));
|
|
assert(get(i) == 5);
|
|
next(i);
|
|
assert(get(i) == 44);
|
|
next(i);
|
|
assert(get(i) == 44);
|
|
next(i);
|
|
assert(get(i) == 5);
|
|
next(i);
|
|
assert(i == end(lst));
|
|
}
|
|
|
|
/**
|
|
* Pushes $(D_PARAM n) copies of $(D_PARAM value) to the front of the
|
|
* list $(D_PARAM lst), and returns an iterator to the last element
|
|
* inserted.
|
|
*/
|
|
void insertAfter(T, U)(ref SList!(T) lst, Iterator!(SList!(T)) i,
|
|
size_t n, U value)
|
|
{
|
|
for (; n-- > 0; )
|
|
{
|
|
i = insertAfter(lst, i, value);
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)(2, 5);
|
|
auto lst1 = SList!(int)(2, 44);
|
|
auto i = begin(lst);
|
|
//next(i);
|
|
insertAfter(lst, i, 2u, 44);
|
|
assert(get(i) == 5);
|
|
next(i);
|
|
assert(get(i) == 44);
|
|
next(i);
|
|
assert(get(i) == 44);
|
|
next(i);
|
|
assert(get(i) == 5);
|
|
next(i);
|
|
assert(i == end(lst));
|
|
}
|
|
|
|
/**
|
|
* Erases the element after the one pointed to by $(D_PARAM i).
|
|
*/
|
|
Iterator!(SList!(T)) eraseAfter(T)(ref SList!(T), Iterator!(SList!(T)) i)
|
|
{
|
|
assert(i.crt);
|
|
assert(i.crt.next);
|
|
i.crt.next = i.crt.next.next;
|
|
return i;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)();
|
|
pushFront(lst, 1, 2, 3);
|
|
auto i = begin(lst);
|
|
eraseAfter(lst, i);
|
|
assert(get(i) == 1);
|
|
next(i);
|
|
assert(get(i) == 3);
|
|
next(i);
|
|
assert(i == end(lst));
|
|
}
|
|
|
|
/**
|
|
* Erases the elements from the element after the one pointed to by
|
|
* $(D_PARAM begin), up to (and including) the one pointed to by
|
|
* $(D_PARAM end).
|
|
*/
|
|
Iterator!(SList!(T)) eraseAfter(T)(ref SList!(T) lst, Iterator!(SList!(T)) begin,
|
|
Iterator!(SList!(T)) end)
|
|
{
|
|
begin.crt.next = end.crt.next;
|
|
return begin;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)();
|
|
pushFront(lst, 1, 2, 3, 4);
|
|
auto i = begin(lst), j = i;
|
|
eraseAfter(lst, i, j);
|
|
assert(lst == [ 1, 2, 3, 4 ], to!(string)(front(lst)));
|
|
next(j);
|
|
eraseAfter(lst, i, j);
|
|
assert(lst == [ 1, 3, 4 ], to!(string)(front(lst)));
|
|
}
|
|
|
|
/**
|
|
* Erases the elements from the element after the one pointed to by
|
|
* $(D_PARAM begin), up to (and including) the one pointed to by
|
|
* $(D_PARAM end).
|
|
*/
|
|
void clear(T)(ref SList!(T) lst)
|
|
{
|
|
lst.root = null;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)();
|
|
pushFront(lst, 1, 2, 3);
|
|
clear(lst);
|
|
assert(isEmpty(lst));
|
|
}
|
|
|
|
/**
|
|
* Inserts or erases elements at the front of $(D_PARAM lst) such that
|
|
* the size becomes $(D_PARAM n).
|
|
*/
|
|
void resize(T)(ref SList!(T) lst, size_t n)
|
|
{
|
|
resize(lst, n, T.init);
|
|
}
|
|
|
|
/** ditto
|
|
*/
|
|
void resize(T, U)(ref SList!(T) lst, size_t n, U value)
|
|
{
|
|
auto b = begin(lst);
|
|
if (b == end(lst))
|
|
{
|
|
// empty list
|
|
lst = SList!(T)(n, value);
|
|
}
|
|
else
|
|
{
|
|
size_t length = 1;
|
|
for (; b.crt.next !is null; next(b))
|
|
{
|
|
++length;
|
|
}
|
|
if (length < n)
|
|
{
|
|
n -= length;
|
|
auto tail = SList!(T)(n, value);
|
|
b.crt.next = tail.root;
|
|
}
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)();
|
|
pushFront(lst, 1, 2, 3);
|
|
// @@@ BUG IN COMPILER: SHOULD ACCEPT CALL WITHOUT 'u'
|
|
resize(lst, 2u);
|
|
assert(lst == [ 1, 2, 3 ]);
|
|
resize(lst, 3u);
|
|
assert(lst == [ 1, 2, 3 ]);
|
|
resize(lst, 5u, 42);
|
|
assert(lst == [ 1.0, 2, 3, 42, 42 ]);
|
|
}
|
|
|
|
/**
|
|
* Computes the distance between two iterators in linear or better time.
|
|
*/
|
|
size_t distanceLin(T)(Iterator!(T) from, Iterator!(T) to)
|
|
{
|
|
size_t result;
|
|
for (; from != to; next(from))
|
|
{
|
|
++result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto lst = SList!(double)(5, 667.45);
|
|
assert(distanceLin(begin(lst), end(lst)) == 5);
|
|
}
|
|
|
|
/**
|
|
* Computes the last valid iterator before $(D_PARAM to) in linear or
|
|
* better time.
|
|
*/
|
|
Iterator!(T) lastLin(T)(Iterator!(T) from, Iterator!(T) to)
|
|
{
|
|
if (from == to) return from;
|
|
for (;;)
|
|
{
|
|
auto save = from;
|
|
next(from);
|
|
if (from == to) return save;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
SList!(double) lst;
|
|
pushFront(lst, 5, 10, 23, 667.45);
|
|
assert(get(lastLin(begin(lst), end(lst))) == 667.45);
|
|
}
|
|
|
|
/**
|
|
* Reads the value pointed to by the iterator, and increments the iterator.
|
|
*/
|
|
bool getNext(It : Iterator!(List!(T)))(It i, ref T target)
|
|
{
|
|
if (!i.crt) return false;
|
|
target = i.crt.value;
|
|
next(i);
|
|
return true;
|
|
}
|
|
|
|
/+
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
size_t size(T)(inout SList!(T) lst) {
|
|
//if (lst.size != lst.size.max) return lst.size;
|
|
// compute the size
|
|
//lst.size = 0;
|
|
auto size = 0;
|
|
for (auto n = lst.root; n; n = n.next) {
|
|
// ++lst.size;
|
|
++size;
|
|
}
|
|
//return lst.size;
|
|
return size;
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
assert(size(list) == 0);
|
|
push_back(list, 1);
|
|
assert(size(list) == 1);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator begin(T)(inout SList!(T) list) {
|
|
return list.iterator(list.root);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator end(T)(inout SList!(T) list) {
|
|
return list.iterator(null);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
bool is_empty(T)(inout SList!(T) lst) {
|
|
return lst.root == null;
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
assert(is_empty(list));
|
|
list.iterator i = begin(list);
|
|
assert(i.done());
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator push_front(T, U)(inout SList!(T) lst, U elem) {
|
|
auto newNode = new lst.node;
|
|
newNode.value = elem;
|
|
if (!lst.root) {
|
|
newNode.prev = newNode;
|
|
newNode.next = null;
|
|
} else {
|
|
assert(lst.root.prev);
|
|
newNode.prev = lst.root.prev;
|
|
newNode.next = lst.root;
|
|
lst.root.prev = newNode;
|
|
}
|
|
return lst.iterator(lst.root = newNode);
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
assert(is_empty(list));
|
|
//
|
|
list.iterator i = begin(list);
|
|
assert(i.done());
|
|
//
|
|
push_front(list, 1);
|
|
i = begin(list);
|
|
assert(!i.done);
|
|
assert(i.get == 1);
|
|
i.next();
|
|
assert(i.done);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator push_back(T, U)(inout SList!(T) lst, U elem) {
|
|
if (!lst.root) return push_front(lst, elem);
|
|
auto newNode = new lst.node;
|
|
newNode.value = elem;
|
|
auto ante = lst.root.prev;
|
|
assert(ante && ante.next == null);
|
|
newNode.prev = ante;
|
|
ante.next = newNode;
|
|
return lst.iterator(lst.root.prev = newNode);
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
assert(size(list) == 0);
|
|
assert(is_empty(list));
|
|
push_back(list, 1);
|
|
assert(size(list) == 1);
|
|
assert(!is_empty(list));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
T back(T)(inout SList!(T) lst) {
|
|
assert(lst.root && lst.root.prev);
|
|
return lst.root.prev.value;
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
push_back(list, 1);
|
|
assert(size(list) == 1);
|
|
assert(!is_empty(list));
|
|
assert(back(list) == 1);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
T front(T)(inout SList!(T) lst) {
|
|
assert(lst.root);
|
|
return lst.root.value;
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
push_back(list, 1);
|
|
assert(front(list) == 1);
|
|
push_back(list, 2);
|
|
assert(front(list) == 1);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
void pop_front(T)(inout SList!(T) lst) {
|
|
enforce(!is_empty(lst));
|
|
auto yank = lst.root;
|
|
auto newRoot = yank.next;
|
|
if (!newRoot) {
|
|
// last mohican
|
|
lst.root = null;
|
|
} else {
|
|
// two or more elements
|
|
newRoot.prev = yank.prev;
|
|
lst.root = newRoot;
|
|
}
|
|
}
|
|
|
|
unittest {
|
|
SList!(int) list;
|
|
push_back(list, 1);
|
|
push_back(list, 2);
|
|
pop_front(list);
|
|
assert(front(list) == 2 && back(list) == 2);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
void pop_back(T)(inout SList!(T) lst) {
|
|
enforce(!is_empty(lst));
|
|
auto yank = lst.root.prev;
|
|
auto newBack = yank.prev;
|
|
if (yank == newBack) {
|
|
// remove the last element
|
|
lst.root = null;
|
|
return;
|
|
}
|
|
lst.root.prev = newBack;
|
|
newBack.next = null;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator insert(T, Iter, U)
|
|
(inout SList!(T) lst, Iter i, U elem) {
|
|
if (lst.root == i.crt) return push_front(lst, elem);
|
|
if (!i.crt) return push_back(lst, elem);
|
|
// Now for the "real" case: i is somewhere in the middle of the list
|
|
auto newNode = new lst.node;
|
|
// fill the new node correctly for insertion _before_ i.crt
|
|
auto post = i.crt;
|
|
auto ante = post.prev;
|
|
newNode.value = elem;
|
|
newNode.next = post;
|
|
newNode.prev = ante;
|
|
post.prev = newNode;
|
|
ante.next = newNode;
|
|
return lst.iterator(newNode);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
SList!(T).iterator erase(T, Iter)
|
|
(inout SList!(T) lst, Iter i) {
|
|
enforce(lst.root && i.crt);
|
|
if (lst.root == i.crt) {
|
|
pop_front(lst);
|
|
return lst.iterator(lst.root);
|
|
}
|
|
if (i.crt == lst.root.prev) {
|
|
pop_back(lst);
|
|
return lst.iterator(null);
|
|
}
|
|
// Now for the "real" case: i is somewhere in the middle of the list
|
|
auto post = i.crt.next;
|
|
auto ante = i.crt.prev;
|
|
post.prev = ante;
|
|
ante.next = post;
|
|
return lst.iterator(post);
|
|
}
|
|
|
|
struct CircularQueue(T) {
|
|
private SList!(T) store;
|
|
private size_t size;
|
|
//
|
|
static CircularQueue opCall(uint size, T init = T.init) {
|
|
CircularQueue!(T) result;
|
|
result.store = SList!(T)(size, init);
|
|
result.size = size;
|
|
return result;
|
|
}
|
|
struct iterator {
|
|
SList!(T).iterator val;
|
|
void next() {
|
|
val.next();
|
|
}
|
|
T get() {
|
|
return val.get;
|
|
}
|
|
}
|
|
iterator begin() {
|
|
iterator result;
|
|
result.val = .begin(this.store);
|
|
return result;
|
|
}
|
|
iterator end() {
|
|
iterator result;
|
|
result.val = .end(this.store);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
T front(T, U=void)(inout CircularQueue!(T) lst) {
|
|
return front(lst.store);
|
|
}
|
|
|
|
void push(T)(inout CircularQueue!(T) lst, T element) {
|
|
// just move the root!
|
|
lst.store.root.value = element;
|
|
// fix the asymmetry of the last element
|
|
assert(!lst.store.root.prev.next);
|
|
lst.store.root.prev.next = lst.store.root;
|
|
lst.store.root = lst.store.root.next;
|
|
lst.store.root.prev.next = null;
|
|
lst.store.check();
|
|
}
|
|
|
|
size_t size(T, U=void)(inout CircularQueue!(T) lst) {
|
|
return lst.size;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
import std.random;
|
|
import std.string;
|
|
import std.stdio;
|
|
|
|
unittest {
|
|
SList!(uint) list;
|
|
uint[] witness;
|
|
|
|
void PositionRandomly(out list.iterator iter, out uint advance) {
|
|
if (!witness.length) return;
|
|
advance = rand() % witness.length;
|
|
iter = begin(list);
|
|
for (auto j = 0; j != advance; ++j) {
|
|
iter.next;
|
|
assert(!iter.done);
|
|
}
|
|
assert(iter.get == witness[advance], toString(advance));
|
|
}
|
|
|
|
for (auto i = 1_000_000; i > 0; --i) {
|
|
list.check();
|
|
list.iterator iter2 = begin(list);
|
|
for (uint j = 0; j != witness.length; ++j, iter2.next) {
|
|
assert(witness[j] == iter2.get);
|
|
}
|
|
writef(i, "\r");
|
|
switch (rand() & 7) {
|
|
case 0:
|
|
witness ~= rand();
|
|
push_back(list, witness[$-1]);
|
|
break;
|
|
case 1:
|
|
witness = rand() ~ witness;
|
|
push_front(list, witness[0]);
|
|
break;
|
|
case 2:
|
|
if (witness.length) {
|
|
witness = witness[0 .. $ - 1];
|
|
pop_back(list);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (witness.length) {
|
|
witness = witness[1 .. $];
|
|
pop_front(list);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (witness.length) {
|
|
list.iterator iter;
|
|
uint advance;
|
|
PositionRandomly(iter, advance);
|
|
witness = witness[0 .. advance] ~ rand() ~ witness[advance .. $];
|
|
insert(list, iter, witness[advance]);
|
|
}
|
|
break;
|
|
case 5:
|
|
if (witness.length) {
|
|
list.iterator iter;
|
|
uint advance;
|
|
PositionRandomly(iter, advance);
|
|
witness = witness[0 .. advance] ~ witness[advance + 1 .. $];
|
|
erase(list, iter);
|
|
}
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
default: ;//assert(false);
|
|
}
|
|
}
|
|
writefln("wyda ");
|
|
}
|
|
|
|
// T enforce(T)(T expression, char[] message = "Enforcement failed") {
|
|
// if (!expression) throw new Exception(message);
|
|
// return expression;
|
|
// }
|
|
|
|
version (selftest) {
|
|
void main() {}
|
|
}
|
|
|
|
+/
|