Merge pull request #2174 from damianday/master

Turn std.container into a package.
This commit is contained in:
monarch dodra 2014-06-25 11:56:03 +02:00
commit a3fd0d48b9
12 changed files with 6648 additions and 6536 deletions

View file

@ -87,7 +87,7 @@ DOCSRC = ../dlang.org
WEBSITE_DIR = ../web
DOC_OUTPUT_DIR = $(WEBSITE_DIR)/phobos-prerelease
BIGDOC_OUTPUT_DIR = /tmp
SRC_DOCUMENTABLES = index.d $(addsuffix .d,$(STD_MODULES) $(STD_NET_MODULES) $(STD_DIGEST_MODULES) $(EXTRA_DOCUMENTABLES))
SRC_DOCUMENTABLES = index.d $(addsuffix .d,$(STD_MODULES) $(STD_NET_MODULES) $(STD_DIGEST_MODULES) $(STD_CONTAINER_MODULES) $(EXTRA_DOCUMENTABLES))
STDDOC = $(DOCSRC)/std.ddoc
BIGSTDDOC = $(DOCSRC)/std_consolidated.ddoc
# Set DDOC, the documentation generator
@ -176,7 +176,7 @@ MAIN = $(ROOT)/emptymain.d
# Stuff in std/
STD_MODULES = $(addprefix std/, algorithm array ascii base64 bigint \
bitmanip compiler complex concurrency container conv \
bitmanip compiler complex concurrency conv \
cstream csv datetime demangle encoding exception \
file format functional getopt json math mathspecial \
mmfile numeric outbuffer parallelism path \
@ -188,6 +188,9 @@ STD_NET_MODULES = $(addprefix std/net/, isemail curl)
STD_DIGEST_MODULES = $(addprefix std/digest/, digest crc md ripemd sha)
STD_CONTAINER_MODULES = $(addprefix std/container/, package array \
binaryheap dlist rbtree slist util)
# OS-specific D modules
EXTRA_MODULES_LINUX := $(addprefix std/c/linux/, linux socket)
EXTRA_MODULES_OSX := $(addprefix std/c/osx/, socket)
@ -213,7 +216,7 @@ EXTRA_MODULES += $(EXTRA_DOCUMENTABLES) $(addprefix \
# Aggregate all D modules relevant to this build
D_MODULES = $(STD_MODULES) $(EXTRA_MODULES) $(STD_NET_MODULES) \
$(STD_DIGEST_MODULES)
$(STD_DIGEST_MODULES) $(STD_CONTAINER_MODULES)
# Add the .d suffix to the module names
D_FILES = $(addsuffix .d,$(D_MODULES))
# Aggregate all D modules over all OSs (this is for the zip file)

File diff suppressed because it is too large Load diff

1995
std/container/array.d Normal file

File diff suppressed because it is too large Load diff

440
std/container/binaryheap.d Normal file
View file

@ -0,0 +1,440 @@
module std.container.binaryheap;
import std.exception, std.algorithm, std.conv, std.range,
std.traits, std.typecons;
public import std.container.util;
// BinaryHeap
/**
Implements a $(WEB en.wikipedia.org/wiki/Binary_heap, binary heap)
container on top of a given random-access range type (usually $(D
T[])) or a random-access container type (usually $(D Array!T)). The
documentation of $(D BinaryHeap) will refer to the underlying range or
container as the $(I store) of the heap.
The binary heap induces structure over the underlying store such that
accessing the largest element (by using the $(D front) property) is a
$(BIGOH 1) operation and extracting it (by using the $(D
removeFront()) method) is done fast in $(BIGOH log n) time.
If $(D less) is the less-than operator, which is the default option,
then $(D BinaryHeap) defines a so-called max-heap that optimizes
extraction of the $(I largest) elements. To define a min-heap,
instantiate BinaryHeap with $(D "a > b") as its predicate.
Simply extracting elements from a $(D BinaryHeap) container is
tantamount to lazily fetching elements of $(D Store) in descending
order. Extracting elements from the $(D BinaryHeap) to completion
leaves the underlying store sorted in ascending order but, again,
yields elements in descending order.
If $(D Store) is a range, the $(D BinaryHeap) cannot grow beyond the
size of that range. If $(D Store) is a container that supports $(D
insertBack), the $(D BinaryHeap) may grow by adding elements to the
container.
*/
struct BinaryHeap(Store, alias less = "a < b")
if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[])))
{
// Really weird @@BUG@@: if you comment out the "private:" label below,
// std.algorithm can't unittest anymore
//private:
// The payload includes the support store and the effective length
private static struct Data
{
Store _store;
size_t _length;
}
private RefCounted!(Data, RefCountedAutoInitialize.no) _payload;
// Comparison predicate
private alias comp = binaryFun!(less);
// Convenience accessors
private @property ref Store _store()
{
assert(_payload.refCountedStore.isInitialized);
return _payload._store;
}
private @property ref size_t _length()
{
assert(_payload.refCountedStore.isInitialized);
return _payload._length;
}
// Asserts that the heap property is respected.
private void assertValid()
{
debug
{
if (!_payload.refCountedStore.isInitialized) return;
if (_length < 2) return;
for (size_t n = _length - 1; n >= 1; --n)
{
auto parentIdx = (n - 1) / 2;
assert(!comp(_store[parentIdx], _store[n]), text(n));
}
}
}
// Assuming the element at index i perturbs the heap property in
// store r, percolates it down the heap such that the heap
// property is restored.
private void percolateDown(Store r, size_t i, size_t length)
{
for (;;)
{
auto left = i * 2 + 1, right = left + 1;
if (right == length)
{
if (comp(r[i], r[left])) swap(r, i, left);
return;
}
if (right > length) return;
assert(left < length && right < length);
auto largest = comp(r[i], r[left])
? (comp(r[left], r[right]) ? right : left)
: (comp(r[i], r[right]) ? right : i);
if (largest == i) return;
swap(r, i, largest);
i = largest;
}
}
// @@@BUG@@@: add private here, std.algorithm doesn't unittest anymore
/*private*/ void pop(Store store)
{
assert(!store.empty, "Cannot pop an empty store.");
if (store.length == 1) return;
auto t1 = moveFront(store[]);
auto t2 = moveBack(store[]);
store.front = move(t2);
store.back = move(t1);
percolateDown(store, 0, store.length - 1);
}
/*private*/ static void swap(Store _store, size_t i, size_t j)
{
static if (is(typeof(swap(_store[i], _store[j]))))
{
swap(_store[i], _store[j]);
}
else static if (is(typeof(_store.moveAt(i))))
{
auto t1 = _store.moveAt(i);
auto t2 = _store.moveAt(j);
_store[i] = move(t2);
_store[j] = move(t1);
}
else // assume it's a container and access its range with []
{
auto t1 = _store[].moveAt(i);
auto t2 = _store[].moveAt(j);
_store[i] = move(t2);
_store[j] = move(t1);
}
}
public:
/**
Converts the store $(D s) into a heap. If $(D initialSize) is
specified, only the first $(D initialSize) elements in $(D s)
are transformed into a heap, after which the heap can grow up
to $(D r.length) (if $(D Store) is a range) or indefinitely (if
$(D Store) is a container with $(D insertBack)). Performs
$(BIGOH min(r.length, initialSize)) evaluations of $(D less).
*/
this(Store s, size_t initialSize = size_t.max)
{
acquire(s, initialSize);
}
/**
Takes ownership of a store. After this, manipulating $(D s) may make
the heap work incorrectly.
*/
void acquire(Store s, size_t initialSize = size_t.max)
{
_payload.refCountedStore.ensureInitialized();
_store = move(s);
_length = min(_store.length, initialSize);
if (_length < 2) return;
for (auto i = (_length - 2) / 2; ; )
{
this.percolateDown(_store, i, _length);
if (i-- == 0) break;
}
assertValid();
}
/**
Takes ownership of a store assuming it already was organized as a
heap.
*/
void assume(Store s, size_t initialSize = size_t.max)
{
_payload.refCountedStore.ensureInitialized();
_store = s;
_length = min(_store.length, initialSize);
assertValid();
}
/**
Clears the heap. Returns the portion of the store from $(D 0) up to
$(D length), which satisfies the $(LUCKY heap property).
*/
auto release()
{
if (!_payload.refCountedStore.isInitialized)
{
return typeof(_store[0 .. _length]).init;
}
assertValid();
auto result = _store[0 .. _length];
_payload = _payload.init;
return result;
}
/**
Returns $(D true) if the heap is _empty, $(D false) otherwise.
*/
@property bool empty()
{
return !length;
}
/**
Returns a duplicate of the heap. The underlying store must also
support a $(D dup) method.
*/
@property BinaryHeap dup()
{
BinaryHeap result;
if (!_payload.refCountedStore.isInitialized) return result;
result.assume(_store.dup, length);
return result;
}
/**
Returns the _length of the heap.
*/
@property size_t length()
{
return _payload.refCountedStore.isInitialized ? _length : 0;
}
/**
Returns the _capacity of the heap, which is the length of the
underlying store (if the store is a range) or the _capacity of the
underlying store (if the store is a container).
*/
@property size_t capacity()
{
if (!_payload.refCountedStore.isInitialized) return 0;
static if (is(typeof(_store.capacity) : size_t))
{
return _store.capacity;
}
else
{
return _store.length;
}
}
/**
Returns a copy of the _front of the heap, which is the largest element
according to $(D less).
*/
@property ElementType!Store front()
{
enforce(!empty, "Cannot call front on an empty heap.");
return _store.front;
}
/**
Clears the heap by detaching it from the underlying store.
*/
void clear()
{
_payload = _payload.init;
}
/**
Inserts $(D value) into the store. If the underlying store is a range
and $(D length == capacity), throws an exception.
*/
size_t insert(ElementType!Store value)
{
static if (is(typeof(_store.insertBack(value))))
{
_payload.refCountedStore.ensureInitialized();
if (length == _store.length)
{
// reallocate
_store.insertBack(value);
}
else
{
// no reallocation
_store[_length] = value;
}
}
else
{
// can't grow
enforce(length < _store.length,
"Cannot grow a heap created over a range");
_store[_length] = value;
}
// sink down the element
for (size_t n = _length; n; )
{
auto parentIdx = (n - 1) / 2;
if (!comp(_store[parentIdx], _store[n])) break; // done!
// must swap and continue
swap(_store, parentIdx, n);
n = parentIdx;
}
++_length;
debug(BinaryHeap) assertValid();
return 1;
}
/**
Removes the largest element from the heap.
*/
void removeFront()
{
enforce(!empty, "Cannot call removeFront on an empty heap.");
if (_length > 1)
{
auto t1 = moveFront(_store[]);
auto t2 = moveAt(_store[], _length - 1);
_store.front = move(t2);
_store[_length - 1] = move(t1);
}
--_length;
percolateDown(_store, 0, _length);
}
/// ditto
alias popFront = removeFront;
/**
Removes the largest element from the heap and returns a copy of
it. The element still resides in the heap's store. For performance
reasons you may want to use $(D removeFront) with heaps of objects
that are expensive to copy.
*/
ElementType!Store removeAny()
{
removeFront();
return _store[_length];
}
/**
Replaces the largest element in the store with $(D value).
*/
void replaceFront(ElementType!Store value)
{
// must replace the top
assert(!empty, "Cannot call replaceFront on an empty heap.");
_store.front = value;
percolateDown(_store, 0, _length);
debug(BinaryHeap) assertValid();
}
/**
If the heap has room to grow, inserts $(D value) into the store and
returns $(D true). Otherwise, if $(D less(value, front)), calls $(D
replaceFront(value)) and returns again $(D true). Otherwise, leaves
the heap unaffected and returns $(D false). This method is useful in
scenarios where the smallest $(D k) elements of a set of candidates
must be collected.
*/
bool conditionalInsert(ElementType!Store value)
{
_payload.refCountedStore.ensureInitialized();
if (_length < _store.length)
{
insert(value);
return true;
}
// must replace the top
assert(!_store.empty, "Cannot replace front of an empty heap.");
if (!comp(value, _store.front)) return false; // value >= largest
_store.front = value;
percolateDown(_store, 0, _length);
debug(BinaryHeap) assertValid();
return true;
}
}
/// Example from "Introduction to Algorithms" Cormen et al, p 146
unittest
{
int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
auto h = heapify(a);
// largest element
assert(h.front == 16);
// a has the heap property
assert(equal(a, [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]));
}
/// $(D BinaryHeap) implements the standard input range interface, allowing
/// lazy iteration of the underlying range in descending order.
unittest
{
int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7];
auto top5 = heapify(a).take(5);
assert(top5.equal([16, 14, 10, 9, 8]));
}
/**
Convenience function that returns a $(D BinaryHeap!Store) object
initialized with $(D s) and $(D initialSize).
*/
BinaryHeap!(Store, less) heapify(alias less = "a < b", Store)(Store s,
size_t initialSize = size_t.max)
{
return BinaryHeap!(Store, less)(s, initialSize);
}
unittest
{
{
// example from "Introduction to Algorithms" Cormen et al., p 146
int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
auto h = heapify(a);
h = heapify!"a < b"(a);
assert(h.front == 16);
assert(a == [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]);
auto witness = [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ];
for (; !h.empty; h.removeFront(), witness.popFront())
{
assert(!witness.empty);
assert(witness.front == h.front);
}
assert(witness.empty);
}
{
int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
int[] b = new int[a.length];
BinaryHeap!(int[]) h = BinaryHeap!(int[])(b, 0);
foreach (e; a)
{
h.insert(e);
}
assert(b == [ 16, 14, 10, 8, 7, 3, 9, 1, 4, 2 ], text(b));
}
}
unittest
{
// Test range interface.
int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7];
auto h = heapify(a);
static assert(isInputRange!(typeof(h)));
assert(h.equal([16, 14, 10, 9, 8, 7, 4, 3, 2, 1]));
}

787
std/container/dlist.d Normal file
View file

@ -0,0 +1,787 @@
module std.container.dlist;
import std.exception, std.range, std.traits;
public import std.container.util;
/**
Implements a doubly-linked list.
$(D DList) uses reference semantics.
*/
struct DList(T)
{
private struct Node
{
T _payload = T.init;
Node * _prev;
Node * _next;
}
private Node* _root;
private void initialize() @safe nothrow pure
{
if (_root) return;
_root = new Node();
_root._next = _root._prev = _root;
}
private ref inout(Node*) _first() @property @safe nothrow pure inout
{
assert(_root);
return _root._next;
}
private ref inout(Node*) _last() @property @safe nothrow pure inout
{
assert(_root);
return _root._prev;
}
/**
Constructor taking a number of nodes
*/
this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
{
insertBack(values);
}
/**
Constructor taking an input range
*/
this(Stuff)(Stuff stuff)
if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
{
insertBack(stuff);
}
/**
Comparison for equality.
Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of
elements in $(D rhs).
*/
bool opEquals()(ref const DList rhs) const
if (is(typeof(front == front)))
{
alias lhs = this;
const lroot = lhs._root;
const rroot = rhs._root;
if (lroot is rroot) return true;
if (lroot is null) return rroot is rroot._next;
if (rroot is null) return lroot is lroot._next;
const(Node)* pl = lhs._first;
const(Node)* pr = rhs._first;
while (true)
{
if (pl is lroot) return pr is rroot;
if (pr is rroot) return false;
// !== because of NaN
if (!(pl._payload == pr._payload)) return false;
pl = pl._next;
pr = pr._next;
}
}
/**
Defines the container's primary range, which embodies a bidirectional range.
*/
struct Range
{
private Node * _first;
private Node * _last;
private this(Node* first, Node* last)
{
assert(!!_first == !!_last, "Dlist.Range.this: Invalid arguments");
_first = first; _last = last;
}
private this(Node* n) { _first = _last = n; }
/// Input range primitives.
@property const nothrow
bool empty()
{
assert(!!_first == !!_last, "DList.Range: Invalidated state");
return !_first;
}
/// ditto
@property ref T front()
{
assert(!empty, "DList.Range.front: Range is empty");
return _first._payload;
}
/// ditto
void popFront()
{
assert(!empty, "DList.Range.popFront: Range is empty");
if (_first is _last)
{
_first = _last = null;
}
else
{
assert(_first._next && _first is _first._next._prev, "DList.Range: Invalidated state");
_first = _first._next;
}
}
/// Forward range primitive.
@property Range save() { return this; }
/// Bidirectional range primitives.
@property ref T back()
{
assert(!empty, "DList.Range.back: Range is empty");
return _last._payload;
}
/// ditto
void popBack()
{
assert(!empty, "DList.Range.popBack: Range is empty");
if (_first is _last)
{
_first = _last = null;
}
else
{
assert(_last._prev && _last is _last._prev._next, "DList.Range: Invalidated state");
_last = _last._prev;
}
}
}
unittest
{
static assert(isBidirectionalRange!Range);
}
/**
Property returning $(D true) if and only if the container has no
elements.
Complexity: $(BIGOH 1)
*/
bool empty() @property const nothrow
{
return _root is null || _root is _first;
}
/**
Removes all contents from the $(D DList).
Postcondition: $(D empty)
Complexity: $(BIGOH 1)
*/
void clear()
{
//remove actual elements.
remove(this[]);
}
/**
Duplicates the container. The elements themselves are not transitively
duplicated.
Complexity: $(BIGOH n).
*/
@property DList dup()
{
return DList(this[]);
}
/**
Returns a range that iterates over all elements of the container, in
forward order.
Complexity: $(BIGOH 1)
*/
Range opSlice()
{
if (empty)
return Range(null, null);
else
return Range(_first, _last);
}
/**
Forward to $(D opSlice().front).
Complexity: $(BIGOH 1)
*/
@property ref inout(T) front() inout
{
assert(!empty, "DList.front: List is empty");
return _first._payload;
}
/**
Forward to $(D opSlice().back).
Complexity: $(BIGOH 1)
*/
@property ref inout(T) back() inout
{
assert(!empty, "DList.back: List is empty");
return _last._payload;
}
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/+ BEGIN CONCAT FUNCTIONS HERE +/
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/**
Returns a new $(D DList) that's the concatenation of $(D this) and its
argument $(D rhs).
*/
DList opBinary(string op, Stuff)(Stuff rhs)
if (op == "~" && is(typeof(insertBack(rhs))))
{
auto ret = this.dup;
ret.insertBack(rhs);
return ret;
}
/// ditto
DList opBinary(string op)(DList rhs)
if (op == "~")
{
return ret ~ rhs[];
}
/**
Returns a new $(D DList) that's the concatenation of the argument $(D lhs)
and $(D this).
*/
DList opBinaryRight(string op, Stuff)(Stuff lhs)
if (op == "~" && is(typeof(insertFront(lhs))))
{
auto ret = this.dup;
ret.insertFront(lhs);
return ret;
}
/**
Appends the contents of the argument $(D rhs) into $(D this).
*/
DList opOpAssign(string op, Stuff)(Stuff rhs)
if (op == "~" && is(typeof(insertBack(rhs))))
{
insertBack(rhs);
return this;
}
/// ditto
DList opOpAssign(string op)(DList rhs)
if (op == "~")
{
return this ~= rhs[];
}
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/+ BEGIN INSERT FUNCTIONS HERE +/
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/**
Inserts $(D stuff) to the front/back of the container. $(D stuff) can be a
value convertible to $(D T) or a range of objects convertible to $(D
T). The stable version behaves the same, but guarantees that ranges
iterating over the container are never invalidated.
Returns: The number of elements inserted
Complexity: $(BIGOH log(n))
*/
size_t insertFront(Stuff)(Stuff stuff)
{
initialize();
return insertAfterNode(_root, stuff);
}
/// ditto
size_t insertBack(Stuff)(Stuff stuff)
{
initialize();
return insertBeforeNode(_root, stuff);
}
/// ditto
alias insert = insertBack;
/// ditto
alias stableInsert = insert;
/// ditto
alias stableInsertFront = insertFront;
/// ditto
alias stableInsertBack = insertBack;
/**
Inserts $(D stuff) after range $(D r), which must be a non-empty range
previously extracted from this container.
$(D stuff) can be a value convertible to $(D T) or a range of objects
convertible to $(D T). The stable version behaves the same, but
guarantees that ranges iterating over the container are never
invalidated.
Returns: The number of values inserted.
Complexity: $(BIGOH k + m), where $(D k) is the number of elements in
$(D r) and $(D m) is the length of $(D stuff).
*/
size_t insertBefore(Stuff)(Range r, Stuff stuff)
{
if (r._first)
return insertBeforeNode(r._first, stuff);
else
{
initialize();
return insertAfterNode(_root, stuff);
}
}
/// ditto
alias stableInsertBefore = insertBefore;
/// ditto
size_t insertAfter(Stuff)(Range r, Stuff stuff)
{
if (r._last)
return insertAfterNode(r._last, stuff);
else
{
initialize();
return insertBeforeNode(_root, stuff);
}
}
/// ditto
alias stableInsertAfter = insertAfter;
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/+ BEGIN REMOVE FUNCTIONS HERE +/
/+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/
/**
Picks one value from the front of the container, removes it from the
container, and returns it.
Precondition: $(D !empty)
Returns: The element removed.
Complexity: $(BIGOH 1).
*/
T removeAny()
{
assert(!empty, "DList.removeAny: List is empty");
auto result = move(back);
removeBack();
return result;
}
/// ditto
alias stableRemoveAny = removeAny;
/**
Removes the value at the front/back of the container. The stable version
behaves the same, but guarantees that ranges iterating over the
container are never invalidated.
Precondition: $(D !empty)
Complexity: $(BIGOH 1).
*/
void removeFront()
{
assert(!empty, "DList.removeFront: List is empty");
assert(_root is _first._prev, "DList: Inconsistent state");
connect(_root, _first._next);
}
/// ditto
alias stableRemoveFront = removeFront;
/// ditto
void removeBack()
{
assert(!empty, "DList.removeBack: List is empty");
assert(_last._next is _root, "DList: Inconsistent state");
connect(_last._prev, _root);
}
/// ditto
alias stableRemoveBack = removeBack;
/**
Removes $(D howMany) values at the front or back of the
container. Unlike the unparameterized versions above, these functions
do not throw if they could not remove $(D howMany) elements. Instead,
if $(D howMany > n), all elements are removed. The returned value is
the effective number of elements removed. The stable version behaves
the same, but guarantees that ranges iterating over the container are
never invalidated.
Returns: The number of elements removed
Complexity: $(BIGOH howMany).
*/
size_t removeFront(size_t howMany)
{
if (!_root) return 0;
size_t result;
auto p = _first;
while (p !is _root && result < howMany)
{
p = p._next;
++result;
}
connect(_root, p);
return result;
}
/// ditto
alias stableRemoveFront = removeFront;
/// ditto
size_t removeBack(size_t howMany)
{
if (!_root) return 0;
size_t result;
auto p = _last;
while (p !is _root && result < howMany)
{
p = p._prev;
++result;
}
connect(p, _root);
return result;
}
/// ditto
alias stableRemoveBack = removeBack;
/**
Removes all elements belonging to $(D r), which must be a range
obtained originally from this container.
Returns: A range spanning the remaining elements in the container that
initially were right after $(D r).
Complexity: $(BIGOH 1)
*/
Range remove(Range r)
{
assert(_root !is null, "Cannot remove from an un-initialized List");
assert(r._first, "Remove: Range is empty");
connect(r._first._prev, r._last._next);
return Range(r._last._next, _last);
}
/// ditto
Range linearRemove(Range r)
{
return remove(r);
}
/**
$(D linearRemove) functions as $(D remove), but also accepts ranges that are
result the of a $(D take) operation. This is a convenient way to remove a
fixed amount of elements from the range.
Complexity: $(BIGOH r.walkLength)
*/
Range linearRemove(Take!Range r)
{
assert(_root !is null, "Cannot remove from an un-initialized List");
assert(r.source._first, "Remove: Range is empty");
Node* first = r.source._first;
Node* last = void;
do
{
last = r.source._first;
r.popFront();
} while ( !r.empty );
return remove(Range(first, last));
}
/// ditto
alias stableRemove = remove;
/// ditto
alias stableLinearRemove = linearRemove;
private:
// Helper: Given nodes p and n, connects them.
void connect(Node* p, Node* n) @trusted nothrow pure
{
p._next = n;
n._prev = p;
}
// Helper: Inserts stuff before the node n.
size_t insertBeforeNode(Stuff)(Node* n, ref Stuff stuff)
if (isImplicitlyConvertible!(Stuff, T))
{
auto p = new Node(stuff, n._prev, n);
n._prev._next = p;
n._prev = p;
return 1;
}
// ditto
size_t insertBeforeNode(Stuff)(Node* n, ref Stuff stuff)
if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
{
if (stuff.empty) return 0;
size_t result;
Range r = createRange(stuff, result);
connect(n._prev, r._first);
connect(r._last, n);
return result;
}
// Helper: Inserts stuff after the node n.
size_t insertAfterNode(Stuff)(Node* n, ref Stuff stuff)
if (isImplicitlyConvertible!(Stuff, T))
{
auto p = new Node(stuff, n, n._next);
n._next._prev = p;
n._next = p;
return 1;
}
// ditto
size_t insertAfterNode(Stuff)(Node* n, ref Stuff stuff)
if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
{
if (stuff.empty) return 0;
size_t result;
Range r = createRange(stuff, result);
connect(r._last, n._next);
connect(n, r._first);
return result;
}
// Helper: Creates a chain of nodes from the range stuff.
Range createRange(Stuff)(ref Stuff stuff, ref size_t result)
{
Node* first = new Node(stuff.front);
Node* last = first;
++result;
for ( stuff.popFront() ; !stuff.empty ; stuff.popFront() )
{
auto p = new Node(stuff.front, last);
last = last._next = p;
++result;
}
return Range(first, last);
}
}
unittest
{
//Tests construction signatures
alias IntList = DList!int;
auto a0 = IntList();
auto a1 = IntList(0);
auto a2 = IntList(0, 1);
auto a3 = IntList([0]);
auto a4 = IntList([0, 1]);
assert(a0[].empty);
assert(equal(a1[], [0]));
assert(equal(a2[], [0, 1]));
assert(equal(a3[], [0]));
assert(equal(a4[], [0, 1]));
}
unittest
{
alias IntList = DList!int;
IntList list = IntList([0,1,2,3]);
assert(equal(list[],[0,1,2,3]));
list.insertBack([4,5,6,7]);
assert(equal(list[],[0,1,2,3,4,5,6,7]));
list = IntList();
list.insertFront([0,1,2,3]);
assert(equal(list[],[0,1,2,3]));
list.insertFront([4,5,6,7]);
assert(equal(list[],[4,5,6,7,0,1,2,3]));
}
unittest
{
alias IntList = DList!int;
IntList list = IntList([0,1,2,3]);
auto range = list[];
for( ; !range.empty; range.popFront())
{
int item = range.front;
if (item == 2)
{
list.stableLinearRemove(take(range, 1));
break;
}
}
assert(equal(list[],[0,1,3]));
list = IntList([0,1,2,3]);
range = list[];
for( ; !range.empty; range.popFront())
{
int item = range.front;
if (item == 2)
{
list.stableLinearRemove(take(range,2));
break;
}
}
assert(equal(list[],[0,1]));
list = IntList([0,1,2,3]);
range = list[];
for( ; !range.empty; range.popFront())
{
int item = range.front;
if (item == 0)
{
list.stableLinearRemove(take(range,2));
break;
}
}
assert(equal(list[],[2,3]));
list = IntList([0,1,2,3]);
range = list[];
for( ; !range.empty; range.popFront())
{
int item = range.front;
if (item == 1)
{
list.stableLinearRemove(take(range,2));
break;
}
}
assert(equal(list[],[0,3]));
}
unittest
{
auto dl = DList!string(["a", "b", "d"]);
dl.insertAfter(dl[], "e"); // insert at the end
assert(equal(dl[], ["a", "b", "d", "e"]));
auto dlr = dl[];
dlr.popBack(); dlr.popBack();
dl.insertAfter(dlr, "c"); // insert after "b"
assert(equal(dl[], ["a", "b", "c", "d", "e"]));
}
unittest
{
auto dl = DList!string(["a", "b", "d"]);
dl.insertBefore(dl[], "e"); // insert at the front
assert(equal(dl[], ["e", "a", "b", "d"]));
auto dlr = dl[];
dlr.popFront(); dlr.popFront();
dl.insertBefore(dlr, "c"); // insert before "b"
assert(equal(dl[], ["e", "a", "c", "b", "d"]));
}
unittest
{
auto d = DList!int([1, 2, 3]);
d.front = 5; //test frontAssign
assert(d.front == 5);
auto r = d[];
r.back = 1;
assert(r.back == 1);
}
// Issue 8895
unittest
{
auto a = make!(DList!int)(1,2,3,4);
auto b = make!(DList!int)(1,2,3,4);
auto c = make!(DList!int)(1,2,3,5);
auto d = make!(DList!int)(1,2,3,4,5);
assert(a == b); // this better terminate!
assert(!(a == c));
assert(!(a == d));
}
unittest
{
auto d = DList!int([1, 2, 3]);
d.front = 5; //test frontAssign
assert(d.front == 5);
auto r = d[];
r.back = 1;
assert(r.back == 1);
}
unittest
{
auto a = DList!int();
assert(a.removeFront(10) == 0);
a.insert([1, 2, 3]);
assert(a.removeFront(10) == 3);
assert(a[].empty);
}
unittest
{
//Verify all flavors of ~
auto a = DList!int();
auto b = DList!int();
auto c = DList!int([1, 2, 3]);
auto d = DList!int([4, 5, 6]);
assert((a ~ b[])[].empty);
assert((c ~ d[])[].equal([1, 2, 3, 4, 5, 6]));
assert(c[].equal([1, 2, 3]));
assert(d[].equal([4, 5, 6]));
assert((c[] ~ d)[].equal([1, 2, 3, 4, 5, 6]));
assert(c[].equal([1, 2, 3]));
assert(d[].equal([4, 5, 6]));
a~=c[];
assert(a[].equal([1, 2, 3]));
assert(c[].equal([1, 2, 3]));
a~=d[];
assert(a[].equal([1, 2, 3, 4, 5, 6]));
assert(d[].equal([4, 5, 6]));
a~=[7, 8, 9];
assert(a[].equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
//trick test:
auto r = c[];
c.removeFront();
c.removeBack();
}
unittest
{
//8905
auto a = DList!int([1, 2, 3, 4]);
auto r = a[];
a.stableRemoveBack();
a.stableInsertBack(7);
assert(a[].equal([1, 2, 3, 7]));
}
unittest //12566
{
auto dl2 = DList!int([2,7]);
dl2.removeFront();
assert(dl2[].walkLength == 1);
dl2.removeBack();
assert(dl2.empty, "not empty?!");
}

856
std/container/package.d Normal file
View file

@ -0,0 +1,856 @@
// Written in the D programming language.
/**
Defines generic containers.
Source: $(PHOBOSSRC std/container/_package.d)
Macros:
WIKI = Phobos/StdContainer
TEXTWITHCOMMAS = $0
Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code
copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders.
License: Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at $(WEB
boost.org/LICENSE_1_0.txt)).
Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu)
$(BOOKTABLE $(TEXTWITHCOMMAS Container primitives. A _container need not
implement all primitives, but if a primitive is implemented, it must
support the syntax described in the $(B syntax) column with the semantics
described in the $(B description) column, and it must not have worse worst-case
complexity than denoted in big-O notation in the $(BIGOH &middot;) column.
Below, $(D C) means a _container type, $(D c) is a value of _container
type, $(D n$(SUBx)) represents the effective length of value $(D x),
which could be a single element (in which case $(D n$(SUB x)) is $(D 1)),
a _container, or a range.),
$(TR $(TH Syntax) $(TH $(BIGOH &middot;)) $(TH Description))
$(TR $(TDNW $(D C(x))) $(TDNW $(D n$(SUB x))) $(TD Creates a
_container of type $(D C) from either another _container or a range.))
$(TR $(TDNW $(D c.dup)) $(TDNW $(D n$(SUB c))) $(TD Returns a
duplicate of the _container.))
$(TR $(TDNW $(D c ~ x)) $(TDNW $(D n$(SUB c) + n$(SUB x))) $(TD
Returns the concatenation of $(D c) and $(D r). $(D x) may be a single
element or an input range.))
$(TR $(TDNW $(D x ~ c)) $(TDNW $(D n$(SUB c) + n$(SUB x))) $(TD
Returns the concatenation of $(D x) and $(D c). $(D x) may be a
single element or an input range type.))
$(LEADINGROW Iteration)
$(TR $(TD $(D c.Range)) $(TD) $(TD The primary range
type associated with the _container.))
$(TR $(TD $(D c[])) $(TDNW $(D log n$(SUB c))) $(TD Returns a range
iterating over the entire _container, in a _container-defined order.))
$(TR $(TDNW $(D c[a .. b])) $(TDNW $(D log n$(SUB c))) $(TD Fetches a
portion of the _container from key $(D a) to key $(D b).))
$(LEADINGROW Capacity)
$(TR $(TD $(D c.empty)) $(TD $(D 1)) $(TD Returns $(D true) if the
_container has no elements, $(D false) otherwise.))
$(TR $(TD $(D c.length)) $(TDNW $(D log n$(SUB c))) $(TD Returns the
number of elements in the _container.))
$(TR $(TDNW $(D c.length = n)) $(TDNW $(D n$(SUB c) + n)) $(TD Forces
the number of elements in the _container to $(D n). If the _container
ends up growing, the added elements are initialized in a
_container-dependent manner (usually with $(D T.init)).))
$(TR $(TD $(D c.capacity)) $(TDNW $(D log n$(SUB c))) $(TD Returns the
maximum number of elements that can be stored in the _container
without triggering a reallocation.))
$(TR $(TD $(D c.reserve(x))) $(TD $(D n$(SUB c))) $(TD Forces $(D
capacity) to at least $(D x) without reducing it.))
$(LEADINGROW Access)
$(TR $(TDNW $(D c.front)) $(TDNW $(D log n$(SUB c))) $(TD Returns the
first element of the _container, in a _container-defined order.))
$(TR $(TDNW $(D c.moveFront)) $(TDNW $(D log n$(SUB c))) $(TD
Destructively reads and returns the first element of the
_container. The slot is not removed from the _container; it is left
initialized with $(D T.init). This routine need not be defined if $(D
front) returns a $(D ref).))
$(TR $(TDNW $(D c.front = v)) $(TDNW $(D log n$(SUB c))) $(TD Assigns
$(D v) to the first element of the _container.))
$(TR $(TDNW $(D c.back)) $(TDNW $(D log n$(SUB c))) $(TD Returns the
last element of the _container, in a _container-defined order.))
$(TR $(TDNW $(D c.moveBack)) $(TDNW $(D log n$(SUB c))) $(TD
Destructively reads and returns the last element of the
container. The slot is not removed from the _container; it is left
initialized with $(D T.init). This routine need not be defined if $(D
front) returns a $(D ref).))
$(TR $(TDNW $(D c.back = v)) $(TDNW $(D log n$(SUB c))) $(TD Assigns
$(D v) to the last element of the _container.))
$(TR $(TDNW $(D c[x])) $(TDNW $(D log n$(SUB c))) $(TD Provides
indexed access into the _container. The index type is
_container-defined. A container may define several index types (and
consequently overloaded indexing).))
$(TR $(TDNW $(D c.moveAt(x))) $(TDNW $(D log n$(SUB c))) $(TD
Destructively reads and returns the value at position $(D x). The slot
is not removed from the _container; it is left initialized with $(D
T.init).))
$(TR $(TDNW $(D c[x] = v)) $(TDNW $(D log n$(SUB c))) $(TD Sets
element at specified index into the _container.))
$(TR $(TDNW $(D c[x] $(I op)= v)) $(TDNW $(D log n$(SUB c)))
$(TD Performs read-modify-write operation at specified index into the
_container.))
$(LEADINGROW Operations)
$(TR $(TDNW $(D e in c)) $(TDNW $(D log n$(SUB c))) $(TD
Returns nonzero if e is found in $(D c).))
$(TR $(TDNW $(D c.lowerBound(v))) $(TDNW $(D log n$(SUB c))) $(TD
Returns a range of all elements strictly less than $(D v).))
$(TR $(TDNW $(D c.upperBound(v))) $(TDNW $(D log n$(SUB c))) $(TD
Returns a range of all elements strictly greater than $(D v).))
$(TR $(TDNW $(D c.equalRange(v))) $(TDNW $(D log n$(SUB c))) $(TD
Returns a range of all elements in $(D c) that are equal to $(D v).))
$(LEADINGROW Modifiers)
$(TR $(TDNW $(D c ~= x)) $(TDNW $(D n$(SUB c) + n$(SUB x)))
$(TD Appends $(D x) to $(D c). $(D x) may be a single element or an
input range type.))
$(TR $(TDNW $(D c.clear())) $(TDNW $(D n$(SUB c))) $(TD Removes all
elements in $(D c).))
$(TR $(TDNW $(D c.insert(x))) $(TDNW $(D n$(SUB x) * log n$(SUB c)))
$(TD Inserts $(D x) in $(D c) at a position (or positions) chosen by $(D c).))
$(TR $(TDNW $(D c.stableInsert(x)))
$(TDNW $(D n$(SUB x) * log n$(SUB c))) $(TD Same as $(D c.insert(x)),
but is guaranteed to not invalidate any ranges.))
$(TR $(TDNW $(D c.linearInsert(v))) $(TDNW $(D n$(SUB c))) $(TD Same
as $(D c.insert(v)) but relaxes complexity to linear.))
$(TR $(TDNW $(D c.stableLinearInsert(v))) $(TDNW $(D n$(SUB c)))
$(TD Same as $(D c.stableInsert(v)) but relaxes complexity to linear.))
$(TR $(TDNW $(D c.removeAny())) $(TDNW $(D log n$(SUB c)))
$(TD Removes some element from $(D c) and returns it.))
$(TR $(TDNW $(D c.stableRemoveAny())) $(TDNW $(D log n$(SUB c)))
$(TD Same as $(D c.removeAny()), but is guaranteed to not invalidate any
iterators.))
$(TR $(TDNW $(D c.insertFront(v))) $(TDNW $(D log n$(SUB c)))
$(TD Inserts $(D v) at the front of $(D c).))
$(TR $(TDNW $(D c.stableInsertFront(v))) $(TDNW $(D log n$(SUB c)))
$(TD Same as $(D c.insertFront(v)), but guarantees no ranges will be
invalidated.))
$(TR $(TDNW $(D c.insertBack(v))) $(TDNW $(D log n$(SUB c)))
$(TD Inserts $(D v) at the back of $(D c).))
$(TR $(TDNW $(D c.stableInsertBack(v))) $(TDNW $(D log n$(SUB c)))
$(TD Same as $(D c.insertBack(v)), but guarantees no ranges will be
invalidated.))
$(TR $(TDNW $(D c.removeFront())) $(TDNW $(D log n$(SUB c)))
$(TD Removes the element at the front of $(D c).))
$(TR $(TDNW $(D c.stableRemoveFront())) $(TDNW $(D log n$(SUB c)))
$(TD Same as $(D c.removeFront()), but guarantees no ranges will be
invalidated.))
$(TR $(TDNW $(D c.removeBack())) $(TDNW $(D log n$(SUB c)))
$(TD Removes the value at the back of $(D c).))
$(TR $(TDNW $(D c.stableRemoveBack())) $(TDNW $(D log n$(SUB c)))
$(TD Same as $(D c.removeBack()), but guarantees no ranges will be
invalidated.))
$(TR $(TDNW $(D c.remove(r))) $(TDNW $(D n$(SUB r) * log n$(SUB c)))
$(TD Removes range $(D r) from $(D c).))
$(TR $(TDNW $(D c.stableRemove(r)))
$(TDNW $(D n$(SUB r) * log n$(SUB c)))
$(TD Same as $(D c.remove(r)), but guarantees iterators are not
invalidated.))
$(TR $(TDNW $(D c.linearRemove(r))) $(TDNW $(D n$(SUB c)))
$(TD Removes range $(D r) from $(D c).))
$(TR $(TDNW $(D c.stableLinearRemove(r))) $(TDNW $(D n$(SUB c)))
$(TD Same as $(D c.linearRemove(r)), but guarantees iterators are not
invalidated.))
$(TR $(TDNW $(D c.removeKey(k))) $(TDNW $(D log n$(SUB c)))
$(TD Removes an element from $(D c) by using its key $(D k).
The key's type is defined by the _container.))
$(TR $(TDNW $(D )) $(TDNW $(D )) $(TD ))
)
*/
module std.container;
public import std.container.array;
public import std.container.binaryheap;
public import std.container.dlist;
public import std.container.rbtree;
public import std.container.slist;
import std.typetuple;
/* The following documentation and type $(D TotalContainer) are
intended for developers only.
$(D TotalContainer) is an unimplemented container that illustrates a
host of primitives that a container may define. It is to some extent
the bottom of the conceptual container hierarchy. A given container
most often will choose to only implement a subset of these primitives,
and define its own additional ones. Adhering to the standard primitive
names below allows generic code to work independently of containers.
Things to remember: any container must be a reference type, whether
implemented as a $(D class) or $(D struct). No primitive below
requires the container to escape addresses of elements, which means
that compliant containers can be defined to use reference counting or
other deterministic memory management techniques.
A container may choose to define additional specific operations. The
only requirement is that those operations bear different names than
the ones below, lest user code gets confused.
Complexity of operations should be interpreted as "at least as good
as". If an operation is required to have $(BIGOH n) complexity, it
could have anything lower than that, e.g. $(BIGOH log(n)). Unless
specified otherwise, $(D n) inside a $(BIGOH) expression stands for
the number of elements in the container.
*/
struct TotalContainer(T)
{
/**
If the container has a notion of key-value mapping, $(D KeyType)
defines the type of the key of the container.
*/
alias KeyType = T;
/**
If the container has a notion of multikey-value mapping, $(D
KeyTypes[k]), where $(D k) is a zero-based unsigned number, defines
the type of the $(D k)th key of the container.
A container may define both $(D KeyType) and $(D KeyTypes), e.g. in
the case it has the notion of primary/preferred key.
*/
alias KeyTypes = TypeTuple!T;
/**
If the container has a notion of key-value mapping, $(D ValueType)
defines the type of the value of the container. Typically, a map-style
container mapping values of type $(D K) to values of type $(D V)
defines $(D KeyType) to be $(D K) and $(D ValueType) to be $(D V).
*/
alias ValueType = T;
/**
Defines the container's primary range, which embodies one of the
ranges defined in $(XREFMODULE range).
Generally a container may define several types of ranges.
*/
struct Range
{
/++
Range primitives.
+/
@property bool empty()
{
assert(0);
}
/// Ditto
@property ref T front() //ref return optional
{
assert(0);
}
/// Ditto
@property void front(T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T moveFront()
{
assert(0);
}
/// Ditto
void popFront()
{
assert(0);
}
/// Ditto
@property ref T back() //ref return optional
{
assert(0);
}
/// Ditto
@property void back(T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T moveBack()
{
assert(0);
}
/// Ditto
void popBack()
{
assert(0);
}
/// Ditto
T opIndex(size_t i) //ref return optional
{
assert(0);
}
/// Ditto
void opIndexAssign(size_t i, T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T opIndexUnary(string op)(size_t i) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
void opIndexOpAssign(string op)(size_t i, T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T moveAt(size_t i)
{
assert(0);
}
/// Ditto
@property size_t length()
{
assert(0);
}
}
/**
Property returning $(D true) if and only if the container has no
elements.
Complexity: $(BIGOH 1)
*/
@property bool empty()
{
assert(0);
}
/**
Returns a duplicate of the container. The elements themselves are not
transitively duplicated.
Complexity: $(BIGOH n).
*/
@property TotalContainer dup()
{
assert(0);
}
/**
Returns the number of elements in the container.
Complexity: $(BIGOH log(n)).
*/
@property size_t length()
{
assert(0);
}
/**
Returns the maximum number of elements the container can store without
(a) allocating memory, (b) invalidating iterators upon insertion.
Complexity: $(BIGOH log(n)).
*/
@property size_t capacity()
{
assert(0);
}
/**
Ensures sufficient capacity to accommodate $(D n) elements.
Postcondition: $(D capacity >= n)
Complexity: $(BIGOH log(e - capacity)) if $(D e > capacity), otherwise
$(BIGOH 1).
*/
void reserve(size_t e)
{
assert(0);
}
/**
Returns a range that iterates over all elements of the container, in a
container-defined order. The container should choose the most
convenient and fast method of iteration for $(D opSlice()).
Complexity: $(BIGOH log(n))
*/
Range opSlice()
{
assert(0);
}
/**
Returns a range that iterates the container between two
specified positions.
Complexity: $(BIGOH log(n))
*/
Range opSlice(size_t a, size_t b)
{
assert(0);
}
/**
Forward to $(D opSlice().front) and $(D opSlice().back), respectively.
Complexity: $(BIGOH log(n))
*/
@property ref T front() //ref return optional
{
assert(0);
}
/// Ditto
@property void front(T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T moveFront()
{
assert(0);
}
/// Ditto
@property ref T back() //ref return optional
{
assert(0);
}
/// Ditto
@property void back(T value) //Only when front does not return by ref
{
assert(0);
}
/// Ditto
T moveBack()
{
assert(0);
}
/**
Indexing operators yield or modify the value at a specified index.
*/
ref T opIndex(KeyType) //ref return optional
{
assert(0);
}
/// ditto
void opIndexAssign(KeyType i, T value) //Only when front does not return by ref
{
assert(0);
}
/// ditto
T opIndexUnary(string op)(KeyType i) //Only when front does not return by ref
{
assert(0);
}
/// ditto
void opIndexOpAssign(string op)(KeyType i, T value) //Only when front does not return by ref
{
assert(0);
}
/// ditto
T moveAt(KeyType i)
{
assert(0);
}
/**
$(D k in container) returns true if the given key is in the container.
*/
bool opBinaryRight(string op)(KeyType k) if (op == "in")
{
assert(0);
}
/**
Returns a range of all elements containing $(D k) (could be empty or a
singleton range).
*/
Range equalRange(KeyType k)
{
assert(0);
}
/**
Returns a range of all elements with keys less than $(D k) (could be
empty or a singleton range). Only defined by containers that store
data sorted at all times.
*/
Range lowerBound(KeyType k)
{
assert(0);
}
/**
Returns a range of all elements with keys larger than $(D k) (could be
empty or a singleton range). Only defined by containers that store
data sorted at all times.
*/
Range upperBound(KeyType k)
{
assert(0);
}
/**
Returns a new container that's the concatenation of $(D this) and its
argument. $(D opBinaryRight) is only defined if $(D Stuff) does not
define $(D opBinary).
Complexity: $(BIGOH n + m), where m is the number of elements in $(D
stuff)
*/
TotalContainer opBinary(string op)(Stuff rhs) if (op == "~")
{
assert(0);
}
/// ditto
TotalContainer opBinaryRight(string op)(Stuff lhs) if (op == "~")
{
assert(0);
}
/**
Forwards to $(D insertAfter(this[], stuff)).
*/
void opOpAssign(string op)(Stuff stuff) if (op == "~")
{
assert(0);
}
/**
Removes all contents from the container. The container decides how $(D
capacity) is affected.
Postcondition: $(D empty)
Complexity: $(BIGOH n)
*/
void clear()
{
assert(0);
}
/**
Sets the number of elements in the container to $(D newSize). If $(D
newSize) is greater than $(D length), the added elements are added to
unspecified positions in the container and initialized with $(D
.init).
Complexity: $(BIGOH abs(n - newLength))
Postcondition: $(D _length == newLength)
*/
@property void length(size_t newLength)
{
assert(0);
}
/**
Inserts $(D stuff) in an unspecified position in the
container. Implementations should choose whichever insertion means is
the most advantageous for the container, but document the exact
behavior. $(D stuff) can be a value convertible to the element type of
the container, or a range of values convertible to it.
The $(D stable) version guarantees that ranges iterating over the
container are never invalidated. Client code that counts on
non-invalidating insertion should use $(D stableInsert). Such code would
not compile against containers that don't support it.
Returns: The number of elements added.
Complexity: $(BIGOH m * log(n)), where $(D m) is the number of
elements in $(D stuff)
*/
size_t insert(Stuff)(Stuff stuff)
{
assert(0);
}
///ditto
size_t stableInsert(Stuff)(Stuff stuff)
{
assert(0);
}
/**
Same as $(D insert(stuff)) and $(D stableInsert(stuff)) respectively,
but relax the complexity constraint to linear.
*/
size_t linearInsert(Stuff)(Stuff stuff)
{
assert(0);
}
///ditto
size_t stableLinearInsert(Stuff)(Stuff stuff)
{
assert(0);
}
/**
Picks one value in an unspecified position in the container, removes
it from the container, and returns it. Implementations should pick the
value that's the most advantageous for the container, but document the
exact behavior. The stable version behaves the same, but guarantees that
ranges iterating over the container are never invalidated.
Precondition: $(D !empty)
Returns: The element removed.
Complexity: $(BIGOH log(n)).
*/
T removeAny()
{
assert(0);
}
/// ditto
T stableRemoveAny()
{
assert(0);
}
/**
Inserts $(D value) to the front or back of the container. $(D stuff)
can be a value convertible to the container's element type or a range
of values convertible to it. The stable version behaves the same, but
guarantees that ranges iterating over the container are never
invalidated.
Returns: The number of elements inserted
Complexity: $(BIGOH log(n)).
*/
size_t insertFront(Stuff)(Stuff stuff)
{
assert(0);
}
/// ditto
size_t stableInsertFront(Stuff)(Stuff stuff)
{
assert(0);
}
/// ditto
size_t insertBack(Stuff)(Stuff stuff)
{
assert(0);
}
/// ditto
size_t stableInsertBack(T value)
{
assert(0);
}
/**
Removes the value at the front or back of the container. The stable
version behaves the same, but guarantees that ranges iterating over
the container are never invalidated. The optional parameter $(D
howMany) instructs removal of that many elements. If $(D howMany > n),
all elements are removed and no exception is thrown.
Precondition: $(D !empty)
Complexity: $(BIGOH log(n)).
*/
void removeFront()
{
assert(0);
}
/// ditto
void stableRemoveFront()
{
assert(0);
}
/// ditto
void removeBack()
{
assert(0);
}
/// ditto
void stableRemoveBack()
{
assert(0);
}
/**
Removes $(D howMany) values at the front or back of the
container. Unlike the unparameterized versions above, these functions
do not throw if they could not remove $(D howMany) elements. Instead,
if $(D howMany > n), all elements are removed. The returned value is
the effective number of elements removed. The stable version behaves
the same, but guarantees that ranges iterating over the container are
never invalidated.
Returns: The number of elements removed
Complexity: $(BIGOH howMany * log(n)).
*/
size_t removeFront(size_t howMany)
{
assert(0);
}
/// ditto
size_t stableRemoveFront(size_t howMany)
{
assert(0);
}
/// ditto
size_t removeBack(size_t howMany)
{
assert(0);
}
/// ditto
size_t stableRemoveBack(size_t howMany)
{
assert(0);
}
/**
Removes all values corresponding to key $(D k).
Complexity: $(BIGOH m * log(n)), where $(D m) is the number of
elements with the same key.
Returns: The number of elements removed.
*/
size_t removeKey(KeyType k)
{
assert(0);
}
/**
Inserts $(D stuff) before, after, or instead range $(D r), which must
be a valid range previously extracted from this container. $(D stuff)
can be a value convertible to the container's element type or a range
of objects convertible to it. The stable version behaves the same, but
guarantees that ranges iterating over the container are never
invalidated.
Returns: The number of values inserted.
Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff)
*/
size_t insertBefore(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/// ditto
size_t stableInsertBefore(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/// ditto
size_t insertAfter(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/// ditto
size_t stableInsertAfter(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/// ditto
size_t replace(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/// ditto
size_t stableReplace(Stuff)(Range r, Stuff stuff)
{
assert(0);
}
/**
Removes all elements belonging to $(D r), which must be a range
obtained originally from this container. The stable version behaves the
same, but guarantees that ranges iterating over the container are
never invalidated.
Returns: A range spanning the remaining elements in the container that
initially were right after $(D r).
Complexity: $(BIGOH m * log(n)), where $(D m) is the number of
elements in $(D r)
*/
Range remove(Range r)
{
assert(0);
}
/// ditto
Range stableRemove(Range r)
{
assert(0);
}
/**
Same as $(D remove) above, but has complexity relaxed to linear.
Returns: A range spanning the remaining elements in the container that
initially were right after $(D r).
Complexity: $(BIGOH n)
*/
Range linearRemove(Range r)
{
assert(0);
}
/// ditto
Range stableLinearRemove(Range r)
{
assert(0);
}
}
unittest {
TotalContainer!int test;
}

1763
std/container/rbtree.d Normal file

File diff suppressed because it is too large Load diff

634
std/container/slist.d Normal file
View file

@ -0,0 +1,634 @@
module std.container.slist;
import std.exception, std.range, std.traits;
public import std.container.util;
/**
Implements a simple and fast singly-linked list.
*/
struct SList(T)
{
private struct Node
{
T _payload;
Node * _next;
this(T a, Node* b) { _payload = a; _next = b; }
}
private Node * _root;
private static Node * findLastNode(Node * n)
{
assert(n);
auto ahead = n._next;
while (ahead)
{
n = ahead;
ahead = n._next;
}
return n;
}
private static Node * findLastNode(Node * n, size_t limit)
{
assert(n && limit);
auto ahead = n._next;
while (ahead)
{
if (!--limit) break;
n = ahead;
ahead = n._next;
}
return n;
}
private static Node * findNode(Node * n, Node * findMe)
{
assert(n);
auto ahead = n._next;
while (ahead != findMe)
{
n = ahead;
enforce(n);
ahead = n._next;
}
return n;
}
/**
Constructor taking a number of nodes
*/
this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
{
insertFront(values);
}
/**
Constructor taking an input range
*/
this(Stuff)(Stuff stuff)
if (isInputRange!Stuff
&& isImplicitlyConvertible!(ElementType!Stuff, T)
&& !is(Stuff == T[]))
{
insertFront(stuff);
}
/**
Comparison for equality.
Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of
elements in $(D rhs).
*/
bool opEquals(const SList rhs) const
{
return opEquals(rhs);
}
/// ditto
bool opEquals(ref const SList rhs) const
{
const(Node) * n1 = _root, n2 = rhs._root;
for (;; n1 = n1._next, n2 = n2._next)
{
if (!n1) return !n2;
if (!n2 || n1._payload != n2._payload) return false;
}
}
/**
Defines the container's primary range, which embodies a forward range.
*/
struct Range
{
private Node * _head;
private this(Node * p) { _head = p; }
/// Input range primitives.
@property bool empty() const { return !_head; }
/// ditto
@property ref T front()
{
assert(!empty, "SList.Range.front: Range is empty");
return _head._payload;
}
/// ditto
void popFront()
{
assert(!empty, "SList.Range.popFront: Range is empty");
_head = _head._next;
}
/// Forward range primitive.
@property Range save() { return this; }
T moveFront()
{
assert(!empty, "SList.Range.moveFront: Range is empty");
return move(_head._payload);
}
bool sameHead(Range rhs)
{
return _head && _head == rhs._head;
}
}
unittest
{
static assert(isForwardRange!Range);
}
/**
Property returning $(D true) if and only if the container has no
elements.
Complexity: $(BIGOH 1)
*/
@property bool empty() const
{
return _root is null;
}
/**
Duplicates the container. The elements themselves are not transitively
duplicated.
Complexity: $(BIGOH n).
*/
@property SList dup()
{
return SList(this[]);
}
/**
Returns a range that iterates over all elements of the container, in
forward order.
Complexity: $(BIGOH 1)
*/
Range opSlice()
{
return Range(_root);
}
/**
Forward to $(D opSlice().front).
Complexity: $(BIGOH 1)
*/
@property ref T front()
{
assert(!empty, "SList.front: List is empty");
return _root._payload;
}
unittest
{
auto s = SList!int(1, 2, 3);
s.front = 42;
assert(s == SList!int(42, 2, 3));
}
/**
Returns a new $(D SList) that's the concatenation of $(D this) and its
argument. $(D opBinaryRight) is only defined if $(D Stuff) does not
define $(D opBinary).
*/
SList opBinary(string op, Stuff)(Stuff rhs)
if (op == "~" && is(typeof(SList(rhs))))
{
auto toAdd = SList(rhs);
static if (is(Stuff == SList))
{
toAdd = toAdd.dup;
}
if (empty) return toAdd;
// TODO: optimize
auto result = dup;
auto n = findLastNode(result._root);
n._next = toAdd._root;
return result;
}
/**
Removes all contents from the $(D SList).
Postcondition: $(D empty)
Complexity: $(BIGOH 1)
*/
void clear()
{
_root = null;
}
/**
Inserts $(D stuff) to the front of the container. $(D stuff) can be a
value convertible to $(D T) or a range of objects convertible to $(D
T). The stable version behaves the same, but guarantees that ranges
iterating over the container are never invalidated.
Returns: The number of elements inserted
Complexity: $(BIGOH m), where $(D m) is the length of $(D stuff)
*/
size_t insertFront(Stuff)(Stuff stuff)
if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
{
size_t result;
Node * n, newRoot;
foreach (item; stuff)
{
auto newNode = new Node(item, null);
(newRoot ? n._next : newRoot) = newNode;
n = newNode;
++result;
}
if (!n) return 0;
// Last node points to the old root
n._next = _root;
_root = newRoot;
return result;
}
/// ditto
size_t insertFront(Stuff)(Stuff stuff)
if (isImplicitlyConvertible!(Stuff, T))
{
auto newRoot = new Node(stuff, _root);
_root = newRoot;
return 1;
}
/// ditto
alias insert = insertFront;
/// ditto
alias stableInsert = insert;
/// ditto
alias stableInsertFront = insertFront;
/**
Picks one value from the front of the container, removes it from the
container, and returns it.
Precondition: $(D !empty)
Returns: The element removed.
Complexity: $(BIGOH 1).
*/
T removeAny()
{
assert(!empty, "SList.removeAny: List is empty");
auto result = move(_root._payload);
_root = _root._next;
return result;
}
/// ditto
alias stableRemoveAny = removeAny;
/**
Removes the value at the front of the container. The stable version
behaves the same, but guarantees that ranges iterating over the
container are never invalidated.
Precondition: $(D !empty)
Complexity: $(BIGOH 1).
*/
void removeFront()
{
assert(!empty, "SList.removeFront: List is empty");
_root = _root._next;
}
/// ditto
alias stableRemoveFront = removeFront;
/**
Removes $(D howMany) values at the front or back of the
container. Unlike the unparameterized versions above, these functions
do not throw if they could not remove $(D howMany) elements. Instead,
if $(D howMany > n), all elements are removed. The returned value is
the effective number of elements removed. The stable version behaves
the same, but guarantees that ranges iterating over the container are
never invalidated.
Returns: The number of elements removed
Complexity: $(BIGOH howMany * log(n)).
*/
size_t removeFront(size_t howMany)
{
size_t result;
while (_root && result < howMany)
{
_root = _root._next;
++result;
}
return result;
}
/// ditto
alias stableRemoveFront = removeFront;
/**
Inserts $(D stuff) after range $(D r), which must be a range
previously extracted from this container. Given that all ranges for a
list end at the end of the list, this function essentially appends to
the list and uses $(D r) as a potentially fast way to reach the last
node in the list. Ideally $(D r) is positioned near or at the last
element of the list.
$(D stuff) can be a value convertible to $(D T) or a range of objects
convertible to $(D T). The stable version behaves the same, but
guarantees that ranges iterating over the container are never
invalidated.
Returns: The number of values inserted.
Complexity: $(BIGOH k + m), where $(D k) is the number of elements in
$(D r) and $(D m) is the length of $(D stuff).
Examples:
--------------------
auto sl = SList!string(["a", "b", "d"]);
sl.insertAfter(sl[], "e"); // insert at the end (slowest)
assert(std.algorithm.equal(sl[], ["a", "b", "d", "e"]));
sl.insertAfter(std.range.take(sl[], 2), "c"); // insert after "b"
assert(std.algorithm.equal(sl[], ["a", "b", "c", "d", "e"]));
--------------------
*/
size_t insertAfter(Stuff)(Range r, Stuff stuff)
{
if (!_root)
{
enforce(!r._head);
return insertFront(stuff);
}
enforce(r._head);
auto n = findLastNode(r._head);
SList tmp;
auto result = tmp.insertFront(stuff);
n._next = tmp._root;
return result;
}
/**
Similar to $(D insertAfter) above, but accepts a range bounded in
count. This is important for ensuring fast insertions in the middle of
the list. For fast insertions after a specified position $(D r), use
$(D insertAfter(take(r, 1), stuff)). The complexity of that operation
only depends on the number of elements in $(D stuff).
Precondition: $(D r.original.empty || r.maxLength > 0)
Returns: The number of values inserted.
Complexity: $(BIGOH k + m), where $(D k) is the number of elements in
$(D r) and $(D m) is the length of $(D stuff).
*/
size_t insertAfter(Stuff)(Take!Range r, Stuff stuff)
{
auto orig = r.source;
if (!orig._head)
{
// Inserting after a null range counts as insertion to the
// front
return insertFront(stuff);
}
enforce(!r.empty);
// Find the last valid element in the range
foreach (i; 1 .. r.maxLength)
{
if (!orig._head._next) break;
orig.popFront();
}
// insert here
SList tmp;
tmp._root = orig._head._next;
auto result = tmp.insertFront(stuff);
orig._head._next = tmp._root;
return result;
}
/// ditto
alias stableInsertAfter = insertAfter;
/**
Removes a range from the list in linear time.
Returns: An empty range.
Complexity: $(BIGOH n)
*/
Range linearRemove(Range r)
{
if (!_root)
{
enforce(!r._head);
return this[];
}
auto n = findNode(_root, r._head);
n._next = null;
return Range(null);
}
/**
Removes a $(D Take!Range) from the list in linear time.
Returns: A range comprehending the elements after the removed range.
Complexity: $(BIGOH n)
*/
Range linearRemove(Take!Range r)
{
auto orig = r.source;
// We have something to remove here
if (orig._head == _root)
{
// remove straight from the head of the list
for (; !r.empty; r.popFront())
{
removeFront();
}
return this[];
}
if (!r.maxLength)
{
// Nothing to remove, return the range itself
return orig;
}
// Remove from somewhere in the middle of the list
enforce(_root);
auto n1 = findNode(_root, orig._head);
auto n2 = findLastNode(orig._head, r.maxLength);
n1._next = n2._next;
return Range(n1._next);
}
/// ditto
alias stableLinearRemove = linearRemove;
}
unittest
{
auto s = SList!int(1, 2, 3);
auto n = s.findLastNode(s._root);
assert(n && n._payload == 3);
}
unittest
{
auto s = SList!int(1, 2, 5, 10);
assert(walkLength(s[]) == 4);
}
unittest
{
auto src = take([0, 1, 2, 3], 3);
auto s = SList!int(src);
assert(s == SList!int(0, 1, 2));
}
unittest
{
auto a = SList!int(1, 2, 3);
auto b = SList!int(4, 5, 6);
// @@@BUG@@@ in compiler
//auto c = a ~ b;
auto d = [ 4, 5, 6 ];
auto e = a ~ d;
assert(e == SList!int(1, 2, 3, 4, 5, 6));
}
unittest
{
auto a = SList!int(1, 2, 3);
auto c = a ~ 4;
assert(c == SList!int(1, 2, 3, 4));
}
unittest
{
auto s = SList!int(1, 2, 3, 4);
s.insertFront([ 42, 43 ]);
assert(s == SList!int(42, 43, 1, 2, 3, 4));
}
unittest
{
auto s = SList!int(1, 2, 3);
assert(s.removeAny() == 1);
assert(s == SList!int(2, 3));
assert(s.stableRemoveAny() == 2);
assert(s == SList!int(3));
}
unittest
{
auto s = SList!int(1, 2, 3);
s.removeFront();
assert(equal(s[], [2, 3]));
s.stableRemoveFront();
assert(equal(s[], [3]));
}
unittest
{
auto s = SList!int(1, 2, 3, 4, 5, 6, 7);
assert(s.removeFront(3) == 3);
assert(s == SList!int(4, 5, 6, 7));
}
unittest
{
auto a = SList!int(1, 2, 3);
auto b = SList!int(1, 2, 3);
assert(a.insertAfter(a[], b[]) == 3);
}
unittest
{
auto s = SList!int(1, 2, 3, 4);
auto r = take(s[], 2);
assert(s.insertAfter(r, 5) == 1);
assert(s == SList!int(1, 2, 5, 3, 4));
}
unittest
{
// insertAfter documentation example
auto sl = SList!string(["a", "b", "d"]);
sl.insertAfter(sl[], "e"); // insert at the end (slowest)
assert(std.algorithm.equal(sl[], ["a", "b", "d", "e"]));
sl.insertAfter(std.range.take(sl[], 2), "c"); // insert after "b"
assert(std.algorithm.equal(sl[], ["a", "b", "c", "d", "e"]));
}
unittest
{
auto s = SList!int(1, 2, 3, 4, 5);
auto r = s[];
popFrontN(r, 3);
auto r1 = s.linearRemove(r);
assert(s == SList!int(1, 2, 3));
assert(r1.empty);
}
unittest
{
auto s = SList!int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
auto r = s[];
popFrontN(r, 3);
auto r1 = take(r, 4);
assert(equal(r1, [4, 5, 6, 7]));
auto r2 = s.linearRemove(r1);
assert(s == SList!int(1, 2, 3, 8, 9, 10));
assert(equal(r2, [8, 9, 10]));
}
unittest
{
auto lst = SList!int(1, 5, 42, 9);
assert(!lst.empty);
assert(lst.front == 1);
assert(walkLength(lst[]) == 4);
auto lst2 = lst ~ [ 1, 2, 3 ];
assert(walkLength(lst2[]) == 7);
auto lst3 = lst ~ [ 7 ];
assert(walkLength(lst3[]) == 5);
}
unittest
{
auto s = make!(SList!int)(1, 2, 3);
}
unittest
{
// 5193
static struct Data
{
const int val;
}
SList!Data list;
}
unittest
{
auto s = SList!int([1, 2, 3]);
s.front = 5; //test frontAssign
assert(s.front == 5);
auto r = s[];
r.front = 1; //test frontAssign
assert(r.front == 1);
}

85
std/container/util.d Normal file
View file

@ -0,0 +1,85 @@
module std.container.util;
import std.algorithm;
/**
Returns an initialized object. This function is mainly for eliminating
construction differences between structs and classes. It allows code to not
worry about whether the type it's constructing is a struct or a class.
Examples:
--------------------
auto arr = make!(Array!int)([4, 2, 3, 1]);
assert(equal(arr[], [4, 2, 3, 1]));
auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]);
assert(equal(rbt[], [4, 3, 2, 1]));
alias makeList = make!(DList!int);
auto list = makeList([1, 7, 42]);
assert(equal(list[], [1, 7, 42]));
--------------------
*/
template make(T)
if (is(T == struct) || is(T == class))
{
T make(Args...)(Args arguments)
if (is(T == struct) && __traits(compiles, T(arguments)))
{
return T(arguments);
}
T make(Args...)(Args arguments)
if (is(T == class) && __traits(compiles, new T(arguments)))
{
return new T(arguments);
}
}
//Verify Examples.
unittest
{
import std.container;
auto arr = make!(Array!int)([4, 2, 3, 1]);
assert(equal(arr[], [4, 2, 3, 1]));
auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]);
assert(equal(rbt[], [4, 3, 2, 1]));
alias makeList = make!(DList!int);
auto list = makeList([1, 7, 42]);
assert(equal(list[], [1, 7, 42]));
auto s = make!(SList!int)(1, 2, 3);
assert(equal(s[], [1, 2, 3]));
}
unittest
{
import std.container;
auto arr1 = make!(Array!dchar)();
assert(arr1.empty);
auto arr2 = make!(Array!dchar)("hello"d);
assert(equal(arr2[], "hello"d));
auto rtb1 = make!(RedBlackTree!dchar)();
assert(rtb1.empty);
auto rtb2 = make!(RedBlackTree!dchar)('h', 'e', 'l', 'l', 'o');
assert(equal(rtb2[], "ehlo"d));
}
// Issue 8895
unittest
{
import std.container;
auto a = make!(DList!int)(1,2,3,4);
auto b = make!(DList!int)(1,2,3,4);
auto c = make!(DList!int)(1,2,3,5);
auto d = make!(DList!int)(1,2,3,4,5);
assert(a == b); // this better terminate!
assert(!(a == c));
assert(!(a == d));
}

View file

@ -18,6 +18,7 @@ public import std.base64;
public import std.compiler;
public import std.concurrency;
public import std.conv;
public import std.container;
public import std.cstream;
public import std.datetime;
public import std.demangle;

View file

@ -129,6 +129,11 @@ SRC_STD_3b= std\datetime.d
#can't place SRC_STD_DIGEST in SRC_STD_REST because of out-of-memory issues
SRC_STD_DIGEST= std\digest\crc.d std\digest\sha.d std\digest\md.d \
std\digest\ripemd.d std\digest\digest.d
SRC_STD_CONTAINER= std\container\array.d std\container\binaryheap.d \
std\container\dlist.d std\container\rbtree.d std\container\slist.d \
std\container\util.d std\container\package.d
SRC_STD_4= std\uuid.d $(SRC_STD_DIGEST)
SRC_STD_5_HEAVY= std\algorithm.d
@ -136,8 +141,8 @@ SRC_STD_5_HEAVY= std\algorithm.d
SRC_STD_6= std\variant.d \
std\syserror.d std\zlib.d \
std\stream.d std\socket.d std\socketstream.d \
std\container.d std\conv.d \
std\zip.d std\cstream.d
std\conv.d std\zip.d std\cstream.d \
$(SRC_STD_CONTAINER)
SRC_STD_REST= std\regex.d \
std\stdint.d \
@ -152,7 +157,7 @@ SRC_STD_ALL= $(SRC_STD_1_HEAVY) $(SRC_STD_2_HEAVY) $(SRC_STD_2a_HEAVY) \
SRC= unittest.d index.d
SRC_STD= std\zlib.d std\zip.d std\stdint.d std\container.d std\conv.d std\utf.d std\uri.d \
SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.d \
std\math.d std\string.d std\path.d std\datetime.d \
std\csv.d std\file.d std\compiler.d std\system.d \
std\outbuffer.d std\base64.d \
@ -287,7 +292,12 @@ DOCS= $(DOC)\object.html \
$(DOC)\std_concurrency.html \
$(DOC)\std_compiler.html \
$(DOC)\std_complex.html \
$(DOC)\std_container.html \
$(DOC)\std_container_array.html \
$(DOC)\std_container_binaryheap.html \
$(DOC)\std_container_dlist.html \
$(DOC)\std_container_rbtree.html \
$(DOC)\std_container_slist.html \
$(DOC)\std_container_package.html \
$(DOC)\std_conv.html \
$(DOC)\std_digest_crc.html \
$(DOC)\std_digest_sha.html \
@ -440,7 +450,13 @@ cov : $(SRC_TO_COMPILE) $(LIB)
$(DMD) -cov=54 -unittest -main -run std\stream.d
$(DMD) -cov=53 -unittest -main -run std\socket.d
$(DMD) -cov=0 -unittest -main -run std\socketstream.d
$(DMD) -cov=88 -unittest -main -run std\container.d
$(DMD) -cov=95 -unittest -main -run std\container\array.d
$(DMD) -cov=68 -unittest -main -run std\container\binaryheap.d
$(DMD) -cov=91 -unittest -main -run std\container\dlist.d
$(DMD) -cov=93 -unittest -main -run std\container\rbtree.d
$(DMD) -cov=92 -unittest -main -run std\container\slist.d
$(DMD) -cov=100 -unittest -main -run std\container\util.d
$(DMD) -cov=100 -unittest -main -run std\container\package.d
$(DMD) -cov=90 -unittest -main -run std\conv.d
$(DMD) -cov=0 -unittest -main -run std\zip.d
$(DMD) -cov=92 -unittest -main -run std\cstream.d
@ -558,8 +574,26 @@ $(DOC)\std_complex.html : $(STDDOC) std\complex.d
$(DOC)\std_conv.html : $(STDDOC) std\conv.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_conv.html $(STDDOC) std\conv.d
$(DOC)\std_container.html : $(STDDOC) std\container.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container.html $(STDDOC) std\container.d
$(DOC)\std_container_array.html : $(STDDOC) std\container\array.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_array.html $(STDDOC) std\container\array.d
$(DOC)\std_container_binaryheap.html : $(STDDOC) std\container\binaryheap.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_binaryheap.html $(STDDOC) std\container\binaryheap.d
$(DOC)\std_container_dlist.html : $(STDDOC) std\container\dlist.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_dlist.html $(STDDOC) std\container\dlist.d
$(DOC)\std_container_rbtree.html : $(STDDOC) std\container\rbtree.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_rbtree.html $(STDDOC) std\container\rbtree.d
$(DOC)\std_container_slist.html : $(STDDOC) std\container\slist.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_slist.html $(STDDOC) std\container\slist.d
$(DOC)\std_container_util.html : $(STDDOC) std\container\util.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_util.html $(STDDOC) std\container\util.d
$(DOC)\std_container_package.html : $(STDDOC) std\container\package.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_package.html $(STDDOC) std\container\package.d
$(DOC)\std_cstream.html : $(STDDOC) std\cstream.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_cstream.html $(STDDOC) std\cstream.d
@ -765,7 +799,7 @@ $(DOC)\etc_c_zlib.html : $(STDDOC) etc\c\zlib.d
zip : win32.mak win64.mak posix.mak $(STDDOC) $(SRC) \
$(SRC_STD) $(SRC_STD_C) $(SRC_STD_WIN) \
$(SRC_STD_C_WIN) $(SRC_STD_C_LINUX) $(SRC_STD_C_OSX) $(SRC_STD_C_FREEBSD) \
$(SRC_ETC) $(SRC_ETC_C) $(SRC_ZLIB) $(SRC_STD_NET) $(SRC_STD_DIGEST) \
$(SRC_ETC) $(SRC_ETC_C) $(SRC_ZLIB) $(SRC_STD_NET) $(SRC_STD_DIGEST) $(SRC_STD_CONTAINER) \
$(SRC_STD_INTERNAL) $(SRC_STD_INTERNAL_DIGEST) $(SRC_STD_INTERNAL_MATH) \
$(SRC_STD_INTERNAL_WINDOWS)
del phobos.zip
@ -786,6 +820,7 @@ zip : win32.mak win64.mak posix.mak $(STDDOC) $(SRC) \
zip32 -u phobos $(SRC_ZLIB)
zip32 -u phobos $(SRC_STD_NET)
zip32 -u phobos $(SRC_STD_DIGEST)
zip32 -u phobos $(SRC_STD_CONTAINER)
phobos.zip : zip

View file

@ -129,8 +129,14 @@ SRC_STD_3b= std\signals.d std\typetuple.d std\traits.d \
#can't place SRC_STD_DIGEST in SRC_STD_REST because of out-of-memory issues
SRC_STD_DIGEST= std\digest\crc.d std\digest\sha.d std\digest\md.d \
std\digest\ripemd.d std\digest\digest.d
SRC_STD_CONTAINER= std\container\array.d std\container\binaryheap.d \
std\container\dlist.d std\container\rbtree.d std\container\slist.d \
std\container\util.d std\container\package.d
SRC_STD_4= std\uuid.d $(SRC_STD_DIGEST)
SRC_STD_5_HEAVY= std\algorithm.d
SRC_STD_6a=std\variant.d
@ -139,7 +145,6 @@ SRC_STD_6c=std\zlib.d
SRC_STD_6d=std\stream.d
SRC_STD_6e=std\socket.d
SRC_STD_6f=std\socketstream.d
SRC_STD_6g=std\container.d
SRC_STD_6h=std\conv.d
SRC_STD_6i=std\zip.d
SRC_STD_6j=std\cstream.d
@ -162,7 +167,7 @@ SRC_STD_ALL= $(SRC_STD_1_HEAVY) $(SRC_STD_2_HEAVY) $(SRC_STD_2a_HEAVY) \
$(SRC_STD_6d) \
$(SRC_STD_6e) \
$(SRC_STD_6f) \
$(SRC_STD_6g) \
$(SRC_STD_CONTAINER) \
$(SRC_STD_6h) \
$(SRC_STD_6i) \
$(SRC_STD_6j) \
@ -171,7 +176,7 @@ SRC_STD_ALL= $(SRC_STD_1_HEAVY) $(SRC_STD_2_HEAVY) $(SRC_STD_2a_HEAVY) \
SRC= unittest.d index.d
SRC_STD= std\zlib.d std\zip.d std\stdint.d std\container.d std\conv.d std\utf.d std\uri.d \
SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.d \
std\math.d std\string.d std\path.d std\datetime.d \
std\csv.d std\file.d std\compiler.d std\system.d \
std\outbuffer.d std\base64.d \
@ -306,7 +311,13 @@ DOCS= $(DOC)\object.html \
$(DOC)\std_concurrency.html \
$(DOC)\std_compiler.html \
$(DOC)\std_complex.html \
$(DOC)\std_container.html \
$(DOC)\std_container_array.html \
$(DOC)\std_container_binaryheap.html \
$(DOC)\std_container_dlist.html \
$(DOC)\std_container_rbtree.html \
$(DOC)\std_container_slist.html \
$(DOC)\std_container_util.html \
$(DOC)\std_container_package.html \
$(DOC)\std_conv.html \
$(DOC)\std_digest_crc.html \
$(DOC)\std_digest_sha.html \
@ -421,7 +432,7 @@ unittest : $(LIB)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6h.obj $(SRC_STD_6h)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6i.obj $(SRC_STD_6i)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6f.obj $(SRC_STD_6f)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6g.obj $(SRC_STD_6g)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6g.obj $(SRC_STD_CONTAINER)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6j.obj $(SRC_STD_6j)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest6k.obj $(SRC_STD_6k)
$(DMD) $(UDFLAGS) -c -unittest -ofunittest7.obj $(SRC_STD_7)
@ -538,8 +549,26 @@ $(DOC)\std_complex.html : $(STDDOC) std\complex.d
$(DOC)\std_conv.html : $(STDDOC) std\conv.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_conv.html $(STDDOC) std\conv.d
$(DOC)\std_container.html : $(STDDOC) std\container.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container.html $(STDDOC) std\container.d
$(DOC)\std_container_array.html : $(STDDOC) std\container\array.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_array.html $(STDDOC) std\container\array.d
$(DOC)\std_container_binaryheap.html : $(STDDOC) std\container\binaryheap.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_binaryheap.html $(STDDOC) std\container\binaryheap.d
$(DOC)\std_container_dlist.html : $(STDDOC) std\container\dlist.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_dlist.html $(STDDOC) std\container\dlist.d
$(DOC)\std_container_rbtree.html : $(STDDOC) std\container\rbtree.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_rbtree.html $(STDDOC) std\container\rbtree.d
$(DOC)\std_container_slist.html : $(STDDOC) std\container\slist.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_slist.html $(STDDOC) std\container\slist.d
$(DOC)\std_container_util.html : $(STDDOC) std\container\util.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_util.html $(STDDOC) std\container\util.d
$(DOC)\std_container_package.html : $(STDDOC) std\container\package.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_package.html $(STDDOC) std\container\package.d
$(DOC)\std_cstream.html : $(STDDOC) std\cstream.d
$(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_cstream.html $(STDDOC) std\cstream.d
@ -745,7 +774,7 @@ $(DOC)\etc_c_zlib.html : $(STDDOC) etc\c\zlib.d
zip : win32.mak win64.mak posix.mak $(STDDOC) $(SRC) \
$(SRC_STD) $(SRC_STD_C) $(SRC_STD_WIN) \
$(SRC_STD_C_WIN) $(SRC_STD_C_LINUX) $(SRC_STD_C_OSX) $(SRC_STD_C_FREEBSD) \
$(SRC_ETC) $(SRC_ETC_C) $(SRC_ZLIB) $(SRC_STD_NET) $(SRC_STD_DIGEST) \
$(SRC_ETC) $(SRC_ETC_C) $(SRC_ZLIB) $(SRC_STD_NET) $(SRC_STD_DIGEST) $(SRC_STD_CONTAINER) \
$(SRC_STD_INTERNAL) $(SRC_STD_INTERNAL_DIGEST) $(SRC_STD_INTERNAL_MATH) \
$(SRC_STD_INTERNAL_WINDOWS)
del phobos.zip
@ -766,6 +795,7 @@ zip : win32.mak win64.mak posix.mak $(STDDOC) $(SRC) \
zip32 -u phobos $(SRC_ZLIB)
zip32 -u phobos $(SRC_STD_NET)
zip32 -u phobos $(SRC_STD_DIGEST)
zip32 -u phobos $(SRC_STD_CONTAINER)
phobos.zip : zip