mirror of
https://github.com/dlang/phobos.git
synced 2025-04-26 05:00:35 +03:00
Merge pull request #2174 from damianday/master
Turn std.container into a package.
This commit is contained in:
commit
a3fd0d48b9
12 changed files with 6648 additions and 6536 deletions
|
@ -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)
|
||||
|
|
6517
std/container.d
6517
std/container.d
File diff suppressed because it is too large
Load diff
1995
std/container/array.d
Normal file
1995
std/container/array.d
Normal file
File diff suppressed because it is too large
Load diff
440
std/container/binaryheap.d
Normal file
440
std/container/binaryheap.d
Normal 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
787
std/container/dlist.d
Normal 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
856
std/container/package.d
Normal 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 ·) 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 ·)) $(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
1763
std/container/rbtree.d
Normal file
File diff suppressed because it is too large
Load diff
634
std/container/slist.d
Normal file
634
std/container/slist.d
Normal 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
85
std/container/util.d
Normal 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));
|
||||
}
|
|
@ -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;
|
||||
|
|
51
win32.mak
51
win32.mak
|
@ -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
|
||||
|
||||
|
|
46
win64.mak
46
win64.mak
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue