xxxxxxxxxx
struct SList(T)
{
import std.range.primitives : isInputRange, isForwardRange, ElementType;
import std.traits : isImplicitlyConvertible;
private struct Node
{
Node * _next;
T _payload;
}
private struct NodeWithoutPayload
{
Node* _next;
}
static assert(NodeWithoutPayload._next.offsetof == Node._next.offsetof);
private Node * _root;
private void initialize() nothrow pure
{
if (_root) return;
_root = cast (Node*) new NodeWithoutPayload();
}
private ref inout(Node*) _first() nothrow pure inout
{
assert(_root);
return _root._next;
}
this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
{
insertFront(values);
}
this(Stuff)(Stuff stuff)
if (isInputRange!Stuff
&& isImplicitlyConvertible!(ElementType!Stuff, T)
&& !is(Stuff == T[]))
{
insertFront(stuff);
}
bool empty() const
{
return _root is null || _first is null;
}
ref T front()
{
assert(!empty, "SList.front: List is empty");
return _first._payload;
}
unittest
{
auto s = SList!int(1, 2, 3);
s.front = 42;
assert(s == SList!int(42, 2, 3));
}
size_t insertFront(Stuff)(Stuff stuff)
if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
{
initialize();
size_t result;
Node * n, newRoot;
foreach (item; stuff)
{
auto newNode = new Node(null, item);
(newRoot ? n._next : newRoot) = newNode;
n = newNode;
++result;
}
if (!n) return 0;
// Last node points to the old root
n._next = _first;
_first = newRoot;
return result;
}
/// ditto
size_t insertFront(Stuff)(Stuff stuff)
if (isImplicitlyConvertible!(Stuff, T))
{
initialize();
auto newRoot = new Node(_first, stuff);
_first = newRoot;
return 1;
}
}
///
unittest
{
auto s = SList!int(1, 2, 3);
}