Mercurial > projects > aid
changeset 7:b9fe92a2d8ad default tip
Removed old code.
author | revcompgeek |
---|---|
date | Tue, 06 May 2008 22:20:26 -0600 |
parents | ff92c77006c7 |
children | |
files | trunk/backprop_test.d trunk/bcd/sys/times.cc trunk/bcd/sys/times.d trunk/mintl/ChangeLog trunk/mintl/adapter.d trunk/mintl/all.d trunk/mintl/array.d trunk/mintl/arrayheap.d trunk/mintl/arraylist.d trunk/mintl/deque.d trunk/mintl/hashaa.d trunk/mintl/index.html trunk/mintl/linux.mak trunk/mintl/list.d trunk/mintl/locks.html trunk/mintl/mem.d trunk/mintl/multiaa.d trunk/mintl/queue.d trunk/mintl/set.d trunk/mintl/share.d trunk/mintl/slist.d trunk/mintl/sortedaa.d trunk/mintl/sorting.d trunk/mintl/stack.d trunk/mintl/unittest.d trunk/mintl/win32.mak |
diffstat | 26 files changed, 1 insertions(+), 10329 deletions(-) [+] |
line wrap: on
line diff
--- a/trunk/backprop_test.d Tue May 06 21:43:55 2008 -0600 +++ b/trunk/backprop_test.d Tue May 06 22:20:26 2008 -0600 @@ -9,8 +9,6 @@ import std.string; import std.stream; -//double[][] trainingInputs, trainingOutputs; -//uint numInputs; uint[] outputsArray; struct TrainingExample { @@ -104,56 +102,6 @@ return e; } -/*void initTrainingExample(int example) { - if(example == 0) { - numInputs = 3; - outputsArray = [2,1]; - trainingInputs = [[0, 0, 0], - [0, 0, 1], - [0, 1, 0], - [0, 1, 1], - [1, 0, 0], - [1, 0, 1], - [1, 1, 0], - [1, 1, 1]]; - - trainingOutputs = [[0.1], - [0.9], - [0.9], - [0.1], - [0.9], - [0.1], - [0.1], - [0.9]]; - } else if(example == 1) { - numInputs = 2; - outputsArray = [2,1]; - trainingInputs = [[0, 0], - [1, 0], - [0, 1], - [1, 1]]; - - trainingOutputs = [[0.9], - [0.1], - [0.1], - [0.9]]; - } else if(example == 2) { - numInputs = 8; - outputsArray = [3,8]; - trainingInputs = [ - [0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - [0.1, 0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - [0.1, 0.1, 0.9, 0.1, 0.1, 0.1, 0.1, 0.1], - [0.1, 0.1, 0.1, 0.9, 0.1, 0.1, 0.1, 0.1], - [0.1, 0.1, 0.1, 0.1, 0.9, 0.1, 0.1, 0.1], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.9, 0.1, 0.1], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.9, 0.1], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.9]]; - - trainingOutputs = trainingInputs; - } -}*/ - void main(char[][] args) { double learningRate = 0.2, momentum = 0.3, randomSize = 0.1, errorMin = 0.05; int /*trainingExample = 0,*/ maxIters = 10000; // 0 to 2 @@ -185,27 +133,6 @@ case "--error-min": errorMin = toDouble(args[++i]); break; - /*case "-n": - case "--example-number": - trainingExample = toInt(args[++i]); - if(trainingExample > 2 || trainingExample < 0) - throw new Error("example number must be between 0 and 2"); - case "-x": - case "--example": - switch(args[++i]) { - case "parity": - trainingExample = 0; - break; - case "xor": - trainingExample = 1; - break; - case "identity": - trainingExample = 2; - break; - default: - throw new Error("Wrong example name. Must be parity, xor or identity"); - } - break;*/ case "-q": case "--quiet": quiet = true; @@ -232,12 +159,7 @@ throw new Error("Unknown switch: " ~ args[i]); } } - //} catch(ArrayBoundsError) { - // throw new Error("Wrong number of paramaters"); - //} - - //initTrainingExample(trainingExample); - + writefln("Starting training with: " ~ example.name); OutputFunctionPtr[] functions;
--- a/trunk/bcd/sys/times.cc Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* THIS FILE GENERATED BY bcd.gen */ -#include <stdlib.h> -#include <string.h> -#include "../bind.h" -#include "times.h" -extern "C" { -void _BCD_delete_3tms( *This) { -delete This; -} -typedef long unsigned int _BCD__67___darwin_clock_t; -typedef _BCD__67___darwin_clock_t _BCD__6_clock_t; -typedef * _BCD__8___darwin_ucontext64_t; -typedef * _BCD__10___darwin_ucontext_t; -typedef * _BCD__12___darwin_stack_t; -typedef unsigned char _BCD_array__13[16]; -typedef _BCD_array__13 _BCD__14___darwin_uuid_t; -typedef unsigned int _BCD__83___uint32_t; -typedef _BCD__83___uint32_t _BCD__16___darwin_useconds_t; -typedef _BCD__83___uint32_t _BCD__17___darwin_uid_t; -typedef int _BCD__84___int32_t; -typedef _BCD__84___int32_t _BCD__19___darwin_suseconds_t; -typedef _BCD__83___uint32_t _BCD__20___darwin_sigset_t; -typedef * _BCD__22___darwin_pthread_t; -typedef * _BCD__24___darwin_pthread_rwlockattr_t; -typedef * _BCD__26___darwin_pthread_rwlock_t; -typedef * _BCD__28___darwin_pthread_once_t; -typedef * _BCD__30___darwin_pthread_mutexattr_t; -typedef * _BCD__32___darwin_pthread_mutex_t; -typedef long unsigned int _BCD__33___darwin_pthread_key_t; -typedef * _BCD__35___darwin_pthread_condattr_t; -typedef * _BCD__37___darwin_pthread_cond_t; -typedef * _BCD__39___darwin_pthread_attr_t; -typedef _BCD__84___int32_t _BCD__40___darwin_pid_t; -typedef long long int _BCD__82___int64_t; -typedef _BCD__82___int64_t _BCD__42___darwin_off_t; -typedef short unsigned int _BCD__85___uint16_t; -typedef _BCD__85___uint16_t _BCD__44___darwin_mode_t; -typedef * _BCD__46___darwin_mcontext64_t; -typedef * _BCD__48___darwin_mcontext_t; -typedef unsigned int _BCD__78___darwin_natural_t; -typedef _BCD__78___darwin_natural_t _BCD__50___darwin_mach_port_name_t; -typedef _BCD__50___darwin_mach_port_name_t _BCD__49___darwin_mach_port_t; -typedef _BCD__83___uint32_t _BCD__51___darwin_ino_t; -typedef _BCD__83___uint32_t _BCD__52___darwin_id_t; -typedef _BCD__83___uint32_t _BCD__53___darwin_gid_t; -typedef unsigned int _BCD__54___darwin_fsfilcnt_t; -typedef unsigned int _BCD__55___darwin_fsblkcnt_t; -typedef _BCD__84___int32_t _BCD__56___darwin_dev_t; -typedef _BCD__84___int32_t _BCD__57___darwin_blksize_t; -typedef _BCD__82___int64_t _BCD__58___darwin_blkcnt_t; -typedef long int _BCD__64___darwin_time_t; -typedef long int _BCD__65___darwin_ssize_t; -typedef _BCD__83___uint32_t _BCD__66___darwin_socklen_t; -typedef int _BCD__68___darwin_wint_t; -typedef int _BCD__70___darwin_wchar_t; -typedef _BCD__70___darwin_wchar_t _BCD__69___darwin_rune_t; -typedef char * _BCD__72___darwin_va_list; -typedef long unsigned int _BCD__73___darwin_size_t; -typedef int _BCD__74___darwin_ptrdiff_t; -typedef union _BCD__76___darwin_mbstate_t; -typedef int _BCD__77___darwin_ct_rune_t; -typedef long int _BCD__79___darwin_intptr_t; -typedef long long unsigned int _BCD__81___uint64_t; -typedef short int _BCD__87___int16_t; -typedef unsigned char _BCD__89___uint8_t; -typedef signed char _BCD__91___int8_t; -}
--- a/trunk/bcd/sys/times.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* THIS FILE GENERATED BY bcd.gen */ -module bcd.sys.times; -align(4): -//public import bcd.sys._types; -alias uint clock_t; -extern (C) uint times(tms *); -struct tms { -uint tms_utime; -uint tms_stime; -uint tms_cutime; -uint tms_cstime; -} -long iutime(){ - tms t; - times(&t); - return t.tms_utime; -}
--- a/trunk/mintl/ChangeLog Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -2.7.2 - * all: update to dmd.1.014 - -2.7.1 - * all: update to dmd.129 - * share, set, multiaa: add static make() that calls add(...) - * hashaa, sortedaa: add block allocated nodes and recycling. add trim() - -2.7 - * arraylist/deque: mixin RandomAccessSort - * list/hashaa: mixin SequentialSort - * sorting: new templates for sorting algorithms - * hashaa: fix insertion bug with rehashing - -2.6.2 - * hashaa/sortedaa: remove enum from 2.6.1 and make get() and put(). - * multiaa: re-enable and uncomment unittests - * set: clean up mixins were for builtin AA support - * all: shorten opApply code by relying on opApplyIter - * arraylist, deque: fix len wrapping code and next() bug - * all.d: added "no warrenty" clause - -2.6.1 - * deque/arraylist: switched to start/len instead of head/tail to - make wrapping easier - * hashaa/sortedaa: redo indexing api to allow NullOnMiss, ThrowOnMiss - and InsertOnMiss for get(). Replace opIn with contains. Remove lookup. - Add 'missing' property for lookups that miss. - -2.6 - * all: simplify mixins by adding type aliases ContainerType, ValueType - IndexType, IterType - * lists: add value getter/setter for one-item slices - * all: add opCmp - * all: add ReadOnly parameter and readonly/readwrite property - * lists: add opIn, count, swap, find, fill, copy algorithms - * hashaa: for consistency with other containers rename LinkedAA - to HashAA and make the default for adapters - * all: update to dmd.126 - -2.5 - * list.d: CList to CircularList and CSList to CircularSList - * all: change move(), moveHead(), moveTail() to next() - * all: added take() and takeHead/Tail to return value if any - * concurrent/aa.d: ConcurrentAA changes to implement Collection - * arraylist.d: grow ArrayList capacity geometrically - * all: remove toArray and replace with values - * all: remove toSeq since instantiating CFoo is equivalent - * linked/sortedaa.d: change fromHead, fromTail to head/tail - * lists: add head/tail properties to get one-item slices of head/tail - * list.d: remove length setter and make length==0 mean unknown length - that gets computed only when required - * list.d: make head null indicate empty list, tail hold cache - * sortedaa.d: add from(key) and to(key) - * deque.d: simplify code by not resizing block size and making it cyclic - * arraylist.d: fix copyBlock bug copying between arrays of different size - * adapter.d: mixins for adapters - * stack.d: adapter for stack - * queue.d: adapter for queue - * set.d: adapter for sets and multi-sets - * multiaa.d: adapter for multi-aa - * index.html: update for above and add class.html. - * mintl.cls: new package containing interfaces and classes - - separate download - * mem.d: new module for customer allocators - * all: add clear() to support custom allocators - -2.2 - * all: replaced length sizes with size_t instead of uint and be careful - about overflows - * arraylist.d: change ArrayList to dynamically grow instead of error - * util.d: removed and moved aliases to target's module - * seq.d: removed and moved contents to share.d - * all: unify bounds checking code into a shared fcn for each module - * opIn: return a pointer to the element or null. - * index.html: update for above and document MinTLNoIndexChecking. - -2.1.1 - * list.d: moved mixin in list.d and slist.d to match new dmd - behavior dmd.119 - * array.d: removed obsolete AA helper functions - * arraylist.d: added capacity, length setter and array to ArrayList - to let it - act more like an array-with-capacity. The only overhead is an extra - head value that is always 0. - * arraylist.d: fixed bug in ArrayList moveBlock when copying to end - of array - -2.1 - * concurrent: split out concurrent containers into a different - distribution - -2.02 - * libmintl_debug.a and mintl_debug.lib debug builds of library - -2.01 - * array.d: remove AA utilities by default since the new implementation - breaks the old routines. old code is available with version AllowAAUtils - * arraylist.d: update for int/uint implicit conversion rules - * win32.mak: update to build unittest with SRC instead of mintl.lib - * linux.mak: same - * concurrent/*.d: add volatile statements back in - * concurrent/dualstack.d: removeTail gets result from t not next - * concurrent/aa.d: add debug print statements - * concurrent/priorityqueue.d: add slower yields to unittest - * concurrent/linkedqueue.d: add slower yields to unittest
--- a/trunk/mintl/adapter.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/** \file adapter.d - * \brief Mixins for adapter containers like stack, queue, set. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 1.1 - */ - -module mintl.adapter; - -template MAdaptBuiltin(alias impl, Container) { - size_t length() { return impl.length; } - int opEquals(Container c) { return impl == c.impl; } -} - -template MAdaptBasic(alias impl, Container) { - bool isEmpty() { return impl.isEmpty; } - Container.ValueType opIndex(Container.IndexType n) { return impl[n]; } - static if (!Container.isReadOnly) { - void opIndexAssign(Container.ValueType v, Container.IndexType n) { impl[n] = v; } - } - int opApply(int delegate(inout Container.ValueType x) dg){return impl.opApply(dg);} - int opApply(int delegate(inout Container.IndexType, inout Container.ValueType x) dg){return impl.opApply(dg);} - Container dup() { - Container res; - res.impl = impl.dup; - return res; - } -} - -template MAdaptList(alias impl, Container) { - static if (!Container.isReadOnly) { - void addHead(Container.ValueType v) {impl.addHead(v);} - void addHead(Container v) {impl.addHead(v.impl);} - void addTail(Container.ValueType v) {impl.addTail(v);} - void addTail(Container v) {impl.addTail(v.impl);} - Container.ValueType takeTail() {return impl.takeTail();} - void removeTail() {impl.removeTail();} - Container.ValueType takeHead() {return impl.takeHead();} - void removeHead() {impl.removeHead();} - void clear(){impl.clear();} - } - int opCmp(Container c) { return impl.opCmp(c.impl); } -} -
--- a/trunk/mintl/all.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/** \file all.d - * \brief Minimal Template Library global import. For concurrent - * containers import mintl.concurrent.all. For class and interface - * API import mintl.cls.all. - * See index.html for documentation. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -/* The MinTL library and sub-libraries are provided 'as-is', without - * any express or implied warranty. In no event will the authors be - * held liable for any damages arising from the use of this software. - */ - -module mintl.all; - -// builtin array helper functions -import mintl.array; - -// linked lists -import mintl.list; -import mintl.slist; - -// special associative arrays -import mintl.hashaa; -import mintl.sortedaa; - -// circular buffer or array with capacity -import mintl.arraylist; - -// heap (complete binary tree) -import mintl.arrayheap; - -// deque (block allocated double-ended queue) -import mintl.deque; - -// adapter containers -import mintl.stack; -import mintl.queue; -import mintl.set; -import mintl.multiaa; - -// shared exceptions and definitions -import mintl.share; -
--- a/trunk/mintl/array.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/** \file array.d - * \brief Utility functions for dynamic and associative arrays. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.6 - */ - -module mintl.array; - -// sort with custom compare delegate -template sort(Value:Value[]) { - void sort(Value[] data, int delegate(Value* l, Value* r) cmp = null) { - void swap( Value* t1, Value* t2 ) { - Value t = *t1; *t1 = *t2; *t2 = t; - } - void insertionSort(Value[] data) { - Value* head = &data[0]; - Value* tail = head+data.length; - Value* i = head+1; - while(i < tail) { - Value* j = i; - for (; j > head && cmp(j - 1,j) > 0; j--) { - swap(j - 1,j); - } - i++; - } - } - void dosort(Value[] data) { - if (data.length < 2) { - return; - } else if (data.length < 8) { - insertionSort(data); - return; - } - Value *head = &data[0]; - Value *tail = head+data.length-1; - Value *p = head+1; - Value *q = tail; - swap(head,head+data.length/2); - if (cmp(p,q) > 0) swap(p,q); - if (cmp(head,q) > 0) swap(head,q); - if (cmp(p,head) > 0) swap(p,head); - while (1) { - do p++; while (cmp(p, head) < 0); - do q--; while (cmp(q, head) > 0); - if (p > q) break; - swap(p,q); - } - swap(head,q); - if (head < q) - dosort(head[0 .. q-head+1]); - if (p < tail) - dosort(p[0 .. tail-p+1]); - } - TypeInfo ti = typeid(Value); - if (cmp is null) { - cmp = cast(typeof(cmp))&ti.compare; - } - dosort(data); - } -} - -/** Reserve a capacity for a dynamic array. If the array already has - * more elements or if the original length is zero it does nothing. - * Compiler-dependent. - * \param x the array to modify - * \param n the requested capacity - */ -template reserve(Value : Value[]) { - void reserve(inout Value[] x, size_t n) { - size_t oldlen = x.length; - if ((oldlen < n) && (oldlen > 0)) { - x.length = n; - x.length = oldlen; - } - } -} - -/** Iterate backwards over a dynamic array. This function should be - * used on the target array in a foreach statement or - * or as the target to a call to toSeq <tt>x.backwards.toSeq</tt> - * \param x the array to iterate over. - */ -template backwards(Value : Value[]) { - DArrayReverseIter!(Value) backwards(Value[] x) { - DArrayReverseIter!(Value) y; - y.x = x; - return y; - } -} - -/* Private helper for reverse iteration */ -private struct DArrayReverseIter(Value) { - Value[] x; - int opApply(int delegate(inout Value val) dg) { - int res = 0; - for (size_t n=x.length; n > 0; ) { - res = dg(x[--n]); - if (res) break; - } - return res; - } - int opApply(int delegate(inout size_t n, inout Value val) dg) { - int res = 0; - size_t cnt = 0; - for (size_t n=x.length; n > 0; cnt++) { - res = dg(cnt,x[--n]); - if (res) break; - } - return res; - } -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - private import std.random; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.array unittest\n"); - - int[] x; - x.length = 1; - reserve!(int[])(x,100); - int[] y = x; - x.length = 90; - assert( cast(int*)x == cast(int*)y ); - version (MinTLVerboseUnittest) - printf("pass\n"); - - int[] t1,t2; - t1.length = 4; - t2.length = 4; - for(int k=0;k<4;k++) t1[k] = k*100; - foreach(size_t n, int val; backwards!(int[])(t1)) { - t2[n] = val; - } - assert( t1.reverse == t2 ); - version (MinTLVerboseUnittest) - printf("pass\n"); - - double[int] c; - c[100] = 1.1; - c[300] = 2.2; - c[-100] = 3.3; - double v; - assert( 100 in c ); - assert( !(200 in c) ); - assert( 300 in c ); - for (int k=0;k<1000;k++) { - c[k*100] = 1; - } - - // test simple sorting - static int[] data = [40,300,-20,100,400,200]; - int[] s1 = data.dup; - sort!(int[])(s1); - static int[] s2 = [-20,40,100,200,300,400]; - assert( s1 == s2 ); - - // test a large sort with default order - double[] s3; - for (int k=0;k<1000;k++) { - s3 ~= 1.0*rand()/100000.0 - 500000.0; - } - double[] s4 = s3.dup; - sort!(double[])(s3); - for (int k=0;k<999;k++) { - assert( s3[k] <= s3[k+1] ); - } - // test a large sort with custom order - int cmp(double*x,double*y){return *x>*y?-1:*x==*y?0:1;} - sort!(double[])(s4,&cmp); - for (int k=0;k<999;k++) { - assert( s4[k] >= s4[k+1] ); - } - - version (MinTLVerboseUnittest) - printf("finished mintl.array unittest\n"); - } -}
--- a/trunk/mintl/arrayheap.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,333 +0,0 @@ -/** \file arrayheap.d - * \brief A heap (complete binary tree) backed by an array - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.6 - */ - -module mintl.arrayheap; - -private { - import mintl.share; // for ~ and ~= - import mintl.mem; - //import std.string; -} - -/** \class ArrayHeap - * \brief A heap (complete binary tree) backed by an array - * - * An ArrayHeap!(Value) is a heap of data of type Value backed - * by an array. Adding to the tail and removing the head of the heap - * are O(log(n)) operations. The items in the heap are maintained - * in sorted order with the largest item at index 0 and for the nth item - * the items at index 2*n+1 and 2*n+2 are smaller (or equal to) - * item n. - * - * The optional allocator parameter ArrayHeap!(Value,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct ArrayHeap(Value, Alloc = GCAllocator) { - - alias ArrayHeap ContainerType; - alias Value ValueType; - alias size_t IndexType; - - Value[] data; ///< backing array. null by default, grows as needed - - invariant { - assert( tail <= data.length ); - } - - /** signature for a custom comparison function */ - alias int delegate(Value* a, Value* b) CompareFcn; - - /** Set custom comparison function. */ - void compareFcn(CompareFcn cmp) { - cmpFcn = cmp; - } - - /** Get heap contents as dynamic array slice of backing array. */ - Value[] values() { - return data[0..tail]; - } - - /** Adds an item to the heap. Increases capacity if needed. */ - void addTail(Value v) { - capacity(tail+1); - data[tail++] = v; - fixupTail(); - } - - /** Removes and returns the head item of the heap. If the target - * heap is empty an IndexOutOfBoundsException is thrown unless - * version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - version (MinTLNoIndexChecking) { - // no error checking - } else { - if (tail == 0) - throw new IndexOutOfBoundsException(); - } - Value val = data[0]; - data[0] = data[--tail]; - data[tail] = Value.init; - fixupHead(); - return val; - } - - /** Removes the head item of the heap. */ - void removeHead() { - version (MinTLNoIndexChecking) { - // no error checking - } else { - if (tail == 0) - throw new IndexOutOfBoundsException(); - } - data[0] = data[--tail]; - data[tail] = Value.init; - fixupHead(); - } - - /** Get the length of heap. */ - size_t length() { - return tail; - } - - /** Test if container is empty. */ - bool isEmpty() { - return tail == 0; - } - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - if (data.ptr) - Alloc.gcFree(data.ptr); - } - *this = ArrayHeap.init; - } - - /** Get the nth item in the heap from head. */ - Value opIndex(size_t n) { - return data[n]; - } - - /** Get a pointer to the nth item in the heap */ - Value* lookup(size_t n) { - return &data[n]; - } - - /** Set the nth item in the heap. */ - void opIndexAssign(Value val, size_t n) { - data[n] = val; - } - - /** Duplicates a heap. */ - ArrayHeap dup() { - ArrayHeap res; - static if (is(Alloc == GCAllocator)) { - res.data = data.dup; - } else { - Value* p = cast(Value*)Alloc.malloc(data.length * Value.sizeof); - res.data = p[0 .. data.length]; - res.data[] = data[]; - } - res.tail = tail; - res.cmpFcn = cmpFcn; - return res; - } - - /** Test for equality of two heaps. */ - int opEquals(ArrayHeap c) { - size_t len = length; - if (len !is c.length) - return 0; - size_t a,b; - a = 0; - b = 0; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < len; k++) { - if (!ti.equals(&data[a],&c.data[b])) - return 0; - a++; - b++; - } - return 1; - } - - /** Compare two heaps. */ - int opCmp(ArrayHeap c) { - size_t len = length; - if (len > c.length) - len = c.length; - size_t a,b; - a = 0; - b = 0; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < len; k++) { - int cmp = ti.compare(&data[a],&c.data[b]); - if (cmp) - return cmp; - a++; - b++; - } - return cast(int)length - cast(int)c.length; - } - - /** Returns a short string representation of the heap. */ - /+char[] toString() { - return "[ArrayHeap length " ~ std.string.toString(tail) ~ "]"; - }+/ - - /** Iterates over the heap from head to tail calling delegate to - * perform an action. The value is passed to the delegate. - */ - int opApplyNoKey(int delegate(inout Value x) dg){ - int res = 0; - for (size_t k=0; k < tail; k++) { - res = dg(data[k]); - if (res) break; - } - return res; - } - - /** Iterates over the heap from head to tail calling delegate to - * perform an action. The index from 0 and the value are passed - * to the delegate. - */ - int opApplyWithKey(int delegate(inout size_t n, inout Value x) dg){ - int res = 0; - for (size_t k=0; k < tail; k++) { - res = dg(k,data[k]); - if (res) break; - } - return res; - } - - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - - /** Ensure the minimum capacity of heap. */ - void capacity(size_t cap) { - if (cap > data.length) { - cap = (cap+1)*2; - static if (is(Alloc == GCAllocator)) { - data.length = cap; - } else { - Value* p = data.ptr; - p = cast(Value*)Alloc.gcRealloc(p,cap*Value.sizeof); - p[data.length .. cap] = Value.init; - data = p[0 .. cap]; - } - } - } - - // Helper functions - - // enforce heap invariant after a new head - private void fixupHead() { - size_t n = 0; - TypeInfo ti = typeid(Value); - if (cmpFcn is null) { - cmpFcn = cast(CompareFcn)&ti.compare; - } - for (;;) { - size_t n1 = 2*n+1; - if (n1 >= tail) break; - if ((n1 != tail-1) && (cmpFcn(&data[n1],&data[n1+1]) < 0)) - n1++; - if (cmpFcn(&data[n],&data[n1]) < 0) { - ti.swap(&data[n],&data[n1]); - n = n1; - } else { - break; - } - } - } - - // enforce heap invariant after a new tail - private void fixupTail() { - size_t n = tail-1; - TypeInfo ti = typeid(Value); - if (cmpFcn is null) { - cmpFcn = cast(CompareFcn)&ti.compare; - } - size_t n1 = (n-1)>>1; - while ((n > 0) && (cmpFcn(&data[n],&data[n1]) > 0)) { - ti.swap(&data[n],&data[n1]); - n = n1; - n1 = (n-1)>>1; - } - } - - // added by h3 - void eraseNoDelete() { - tail = 0; - } - - private CompareFcn cmpFcn; - private size_t tail; -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - private import std.string; - unittest { - version (MinTLVerboseUnittest) - printf("started mintl.arrayheap unittest\n"); - - ArrayHeap!(int) x,y,z; - x.data = new int[10]; - x.addTail(5); - x.addTail(3); - x.addTail(4); - assert( x.length == 3 ); - assert( x[0] == 5 ); - assert( x[x.length-1] == 4 ); - - y = x.dup; - - assert( x == y ); - - assert( x.takeHead == 5 ); - assert( x.takeHead == 4 ); - assert( x.takeHead == 3 ); - assert( x.length == 0 ); - - y.addTail(6); - int[10] y2; - int k=0; - foreach(int val; y) { - y2[k++] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 5 ); - assert( y2[2] == 4 ); - assert( y2[3] == 3 ); - - k=0; - foreach(size_t n, int val; y) { - y2[n] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 5 ); - assert( y2[2] == 4 ); - assert( y2[3] == 3 ); - - ArrayHeap!(int,MallocNoRoots) xm; - for (int k=0;k<100;k++) - xm.addTail(k); - for (int k=0;k<100;k++) - assert( xm.takeHead == 99-k ); - xm.clear(); - - version (MinTLVerboseUnittest) - printf("finished mintl.arrayheap unittest\n"); - } -}
--- a/trunk/mintl/arraylist.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,858 +0,0 @@ -/** \file arraylist.d - * \brief A list backed by an array. This container can - * also be used as an array with managed capacity by only - * inserting and removing from the tail and keeping the head fixed - * at 0. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.arraylist; - -private import mintl.share; // for ~ and ~= -private import mintl.sorting; -import mintl.mem; - -private extern(C) void *memmove(void *, void *, uint); - -//debug = dArrayList; // can also pass at command line - -/** \class ArrayList - * \brief A bounded list backed by an array - * - * An ArrayList!(Value) is a list of data of type Value backed - * by a circular array. The performance of ArrayLists is on the same - * order as for arrays except adding an element to the head of an - * ArrayList is constant. The backing array can be dynamic or static - * arrays and should be set prior to use by assigning to the - * <tt>data</tt> property or the <tt>capacity</tt> property. The - * ArrayList will automatically grow the backing array if needed. - * - * An ArrayList can also be used as an array with managed capacity. - * To do so only insert and remove from the tail and keep the head fixed - * at 0. - * - * The optional ReadOnly parameter ArrayList!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter ArrayList!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct ArrayList(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias ArrayList ContainerType; - alias ArrayList SliceType; - alias Value ValueType; - alias size_t IndexType; - alias ReadOnly isReadOnly; - - Value[] data; ///< backing array. null by default. - - invariant { - assert( data.length == 0 || start < data.length ); - assert( len <= data.length ); - } - - /** Get a ReadOnly view of the container */ - .ArrayList!(Value, true, Alloc) readonly() { - .ArrayList!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .ArrayList!(Value, false, Alloc) readwrite() { - .ArrayList!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (!ReadOnly) { - - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. Increases capacity if needed. - */ - void addTail(Value v) { - capacity(length+1); - data[addi(start,len)] = v; - len++; - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. Increases capacity if needed. - */ - void addTail(ArrayList v) { - size_t vlen = v.length; - capacity(len+vlen); - copyBlock(v,data,addi(start,len),vlen); - len += vlen; - } - - /** overload ~ and ~= */ - mixin MListCatOperators!(ArrayList); - - /** Removes and returns the tail item of the list. If the target - * list is empty an IndexOutOfBoundsException is thrown unless - * version=MinTLNoIndexChecking is set. - */ - Value takeTail() { - boundsCheck(length-1); - len--; - size_t n = addi(start,len); - Value val = data[n]; - data[n] = Value.init; - return val; - } - - /** Removes the tail item of the list. */ - void removeTail() { - boundsCheck(length-1); - len--; - data[addi(start,len)] = Value.init; - } - - /** Prepends an item to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert an - * after a sub-list. Increases capacity if needed. - */ - void addHead(Value v) { - debug(dArrayList) printf(" add %d %u\n",start-1,dec(start)); - capacity(len+1); - start = dec(start); - data[start] = v; - len++; - } - - /** Prepends a list to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert a - * list before a sub-list. Increases capacity if needed. - */ - void addHead(ArrayList v) { - size_t vlen = v.length; - capacity(len+vlen); - size_t newhead = subi(start,vlen); - copyBlock(v,data,newhead,vlen); - start = newhead; - len += vlen; - } - - /** Removes and returns the head item of the list. If the target - * list is empty an IndexOutOfBoundsException is thrown unless - * version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - boundsCheck(length-1); - Value val = data[start]; - data[start] = Value.init; - start = inc(start); - debug(dArrayList) printf("%d %d\n",start,val); - len--; - return val; - } - - /** Removes the head item of the list. */ - void removeHead() { - boundsCheck(len-1); - data[start] = Value.init; - start = inc(start); - len--; - debug(dArrayList) printf("%d\n",start); - } - - /** Insert a list before a sub-list. Increases capacity if needed. */ - void addBefore(ArrayList subv, ArrayList v) { - size_t vlen = v.length; - if (vlen == 0) return; - capacity(length+vlen); - size_t tlen = subv.start >= start ? subv.start-start : data.length-start+subv.start; - size_t newhead = subi(start,vlen); - moveBlockLeft(start,tlen,newhead); - copyBlock(v,data,subi(subv.start,vlen),vlen); - start = newhead; - len += vlen; - } - - /** Insert a list after a sub-list. Increases capacity if needed. */ - void addAfter(ArrayList subv, ArrayList v) { - size_t vlen = v.length; - if (vlen == 0) return; - capacity(length+vlen); - size_t tail = addi(start,len); - size_t stail = addi(subv.start,subv.len); - size_t tlen = stail <= tail ? tail-stail : data.length-stail+tail; - moveBlockRight(stail,tlen,addi(stail,vlen)); - copyBlock(v,data,stail,vlen); - len += vlen; - } - - /** Set the length of list. */ - void length(size_t len) { - capacity(len); - this.len = len; - } - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - if (data.ptr) - Alloc.gcFree(data.ptr); - } - *this = ArrayList.init; - } - - /** Set the nth item in the list from head. Indexing out of bounds - * throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - void opIndexAssign(Value val, size_t n) { - boundsCheck(n); - data[addi(start,n)] = val; - } - - /** Set the value of one-item slice (more generally the head value). */ - void value(Value newValue) { - opIndexAssign(newValue,0); - } - - /** Removes a sub-list from the list. */ - void remove(ArrayList sublist) { - size_t tail = addi(start,len); - size_t slen = sublist.len; - size_t stail = addi(sublist.start,slen); - size_t tlen = stail <= tail ? tail-stail : data.length-stail+tail; - debug(dArrayList) printf("remove %d %d\n",sublist.start, sublist.length); - moveBlockLeft(stail, tlen, sublist.start); - fillBlock(subi(tail,slen),slen,Value.init); - len -= slen; - debug(dArrayList) printf("removed %d %d\n",start, len); - } - - /** Removes an item from the list, if present. */ - void remove(size_t index) { - ArrayList item = opSlice(index, index+1); - remove(item); - } - - /** Removes an item from the list and returns the value, if present. */ - Value take(size_t index) { - ArrayList item = opSlice(index, index+1); - Value val = item[0]; - remove(item); - return val; - } - - } // !ReadOnly - - /** Move a sub-list towards the tail by n items. If n is - * negative the sub-list moves towards the head. A positive end is - * the tail, negative the head and 0 is both. By default moves to - * to the next item. - */ - void next(int n = 1, int end = 0) { - if (end) - len += n<0?-n:n; - if (end <= 0) { - if (n<0) { - start = subi(start,-n); - } else { - start = addi(start,n); - } - } - } - - /** Get the length of list. */ - size_t length() { - return len; - } - - private const double GrowthRate = 1.5; - - /** Ensure the minimum capacity of list. */ - void capacity(size_t cap) { - if (data.length < cap) { - cap = cast(size_t)(cap*GrowthRate)+1; - if (start > data.length - len) { - size_t oldlen = data.length; - size_t oldheadlen = oldlen - start; - resizeData(cap); - moveBlockRight(start,oldheadlen, cap - oldheadlen); - start = cap-oldheadlen; - } else { - resizeData(cap); - } - } - } - - // helper for capacity - private void resizeData(size_t cap) { - static if (is(Alloc == GCAllocator)) { - data.length = cap; - } else { - Value* p = data.ptr; - p = cast(Value*)Alloc.gcRealloc(p,cap*Value.sizeof); - p[data.length .. cap] = Value.init; - data = p[0 .. cap]; - } - } - - /** Get the capacity of list. */ - size_t capacity() { - return data.length; - } - - /** Test if container is empty. */ - bool isEmpty() { - return len == 0; - } - - /** Get the nth item in the list from head. Indexing out of bounds - * throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Value opIndex(size_t n) { - boundsCheck(n); - return data[addi(start,n)]; - } - - /** Get the value of one-item slice (more generally the head value). - * Useful for expressions like x.tail.value or x.head.value. */ - Value value() { - return opIndex(0); - } - - // helper function to check if the index is legal - private void boundsCheck(size_t n) { - version (MinTLNoIndexChecking) { - } else { - if (n >= len) { - throw new IndexOutOfBoundsException(); - } - } - } - - /** Create a one-item slice of the head. */ - ArrayList head() { - return opSlice(0,1); - } - - /** Create a one-item slice of the tail. */ - ArrayList tail() { - size_t len = length; - return opSlice(len-1,len); - } - - /** Reverse a list in-place. */ - ArrayList reverse() { - size_t tlen = len / 2; - size_t a,b; - a = start; - b = dec(addi(start,len)); - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < tlen; k++) { - debug(dArrayList) printf("swapping %d %d\n",data[a],data[b]); - ti.swap(&data[a],&data[b]); - a = inc(a); - b = dec(b); - } - return *this; - } - - /** Get list contents as dynamic array (a slice if possible). */ - Value[] values() { - Value[] buffer; - if (start <= data.length-len) { - buffer = data[start .. start+len]; - } else { - buffer.length = len; - buffer[0 .. data.length-start] = data[start .. data.length]; - buffer[data.length-start .. buffer.length] = - data[0 .. len - data.length - start]; - } - return buffer; - } - - /** Duplicates a list. */ - ArrayList dup() { - ArrayList res; - static if (is(Alloc == GCAllocator)) { - res.data = data.dup; - } else { - Value* p = cast(Value*)Alloc.malloc(data.length * Value.sizeof); - res.data = p[0 .. data.length]; - res.data[] = data[]; - } - res.start = start; - res.len = len; - return res; - } - - /** Test for equality of two lists. */ - int opEquals(ArrayList c) { - if (len !is c.len) - return 0; - size_t a,b; - a = start; - b = c.start; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < len; k++) { - if (!ti.equals(&data[a],&c.data[b])) - return 0; - a = inc(a); - b = inc(b); - } - return 1; - } - - /** Compare two lists. */ - int opCmp(ArrayList c) { - size_t tlen = len; - if (tlen > c.len) - tlen = c.len; - size_t a,b; - a = start; - b = c.start; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < tlen; k++) { - int cmp = ti.compare(&data[a],&c.data[b]); - if (cmp) - return cmp; - a = inc(a); - b = inc(b); - } - return cast(int)len - cast(int)c.len; - } - - /** Create a sub-list from index a to b (exclusive). */ - ArrayList opSlice(size_t a, size_t b) { - ArrayList res; - res.data = data; - res.start = addi(start,a); - res.len = b-a; - debug(dArrayList) printf("slice %d %d\n",res.start,res.len); - return res; - } - - /** Create a sub-list from the head of a to the tail of b (inclusive). */ - ArrayList opSlice(ArrayList a, ArrayList b) { - ArrayList res; - res.data = data; - res.start = a.start; - if (b.start >= a.start) - res.len = b.start - a.start + b.len; - else - res.len = data.length - a.start + b.len + b.start; - return res; - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The value is passed to the delegate. - */ - int opApplyNoKeyStep(int delegate(inout Value x) dg, int step = 1){ - int dg2(inout size_t n, inout Value x) { - return dg(x); - } - return opApplyWithKeyStep(&dg2,step); - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The index from 0 and the value are passed - * to the delegate. - */ - int opApplyWithKeyStep(int delegate(inout size_t n, inout Value x) dg, int step = 1){ - if (len == 0) return 0; - int res = 0; - size_t tail = addi(start,len); - size_t istart = step>0 ? start : dec(tail); - size_t iend = step>0 ? tail : dec(start); - size_t n = step>0 ? 0 : len-1; - for (size_t k = istart; k != iend;) { - res = dg(n,data[k]); - if (res) break; - if (step < 0) - k = subi(k,-step); - else - k = addi(k,step); - n += step; - } - return res; - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. A one-item sub-list is passed to the delegate. - */ - int opApplyIterStep(int delegate(inout ArrayList n) dg, int step = 1){ - ArrayList itr; - itr.data = data; - itr.len = 1; - int dg2(inout size_t n, inout Value x) { - itr.start = addi(start,n); - return dg(itr); - } - return opApplyWithKeyStep(&dg2,step); - } - - /** Iterate backwards over the list (from tail to head). - * This should only be called as the - * iteration parameter in a <tt>foreach</tt> statement - */ - ArrayListReverseIter!(Value,ReadOnly,Alloc) backwards() { - ArrayListReverseIter!(Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** Helper functions for opApply */ - mixin MOpApplyImpl!(ArrayList); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - ArrayList getThis(){return *this;} - mixin MListAlgo!(ArrayList, getThis); - mixin MRandomAccessSort!(ArrayList, getThis); - - /** Get a pointer to the nth item in the list from head. Indexing - * out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Value* lookup(size_t n) { - boundsCheck(n); - return &data[addi(start,n)]; - } - - // Helper functions - - // helper function to copy sections of the backing buffer - private void moveBlockLeft(size_t srchead, size_t len, size_t desthead) { - size_t ns = srchead; - size_t nd = desthead; - while (len > 0) { - debug(dArrayList) printf("move left len %u\n",len); - size_t sz = len; - if (ns > data.length-sz) - sz = data.length-ns; - if (nd > data.length-sz) - sz = data.length-nd; - assert(sz != 0); - memmove(&data[nd],&data[ns],sz*Value.sizeof); - ns = addi(ns,sz); - nd = addi(nd,sz); - len -= sz; - } - } - - // helper function to copy sections of the backing buffer - private void moveBlockRight(size_t srchead, size_t len, size_t desthead) { - debug(dArrayList) printf("len %u\n",len); - size_t ns = addi(srchead,len-1)+1; - size_t nd = addi(desthead,len-1)+1; - while (len > 0) { - int sz = len; - if (ns < sz) - sz = ns; - if (nd < sz) - sz = nd; - assert(sz != 0); - memmove(&data[nd-sz],&data[ns-sz],sz*Value.sizeof); - ns = dec(subi(ns,sz))+1; - nd = dec(subi(nd,sz))+1; - len -= sz; - } - } - - // helper function to copy sections of the backing buffer - private void copyBlock(ArrayList src, - Value[] destdata,int desthead, - int len) { - Value[] srcdata = src.data; - int srchead = src.start; - int ns = srchead; - int nd = desthead; - while (len > 0) { - debug(dArrayList) printf("copy len %u %d %d len %d len %d\n", - len,ns,nd,srcdata.length,destdata.length); - int sz = len; - if (ns > srcdata.length-sz) - sz = srcdata.length-ns; - if (nd > destdata.length-sz) - sz = destdata.length-nd; - assert(sz != 0); - memmove(&destdata[nd],&srcdata[ns],sz*Value.sizeof); - ns = src.addi(ns,sz); - nd = addi(nd,sz); - len -= sz; - } - } - - // helper function to fill a section of the backing array - private void fillBlock(size_t srchead, size_t len, Value val) { - size_t ns = srchead; - while (len > 0) { - size_t sz = len; - if (ns > data.length-sz) - sz = data.length-ns; - assert(sz != 0); - data[ns .. ns+sz] = val; - ns = addi(ns,sz); - len -= sz; - } - } - - // move index n by 1 with wrapping - private size_t inc(size_t n) { - return (n == data.length-1) ? 0 : n+1; - } - - // move index n by -1 with wrapping - private size_t dec(size_t n) { - return (n == 0) ? data.length-1 : n-1; - } - - // move index n by -diff with wrapping - private size_t subi(size_t n, size_t diff) { - size_t res; - if (n < diff) - res = data.length - diff + n; - else - res = n - diff; - debug(dArrayList) printf("subi %d %d len %d got %d\n",n,diff,data.length,res); - return res; - } - - // move index n by diff with wrapping - private size_t addi(size_t n, size_t diff) { - size_t res; - if (data.length - n <= diff) - res = diff - (data.length - n); - else - res = n + diff; - debug(dArrayList) printf("addi %d %d len %d got %d\n",n,diff,data.length,res); - return res; - } - - private size_t start, len; -} - -// helper structure for backwards() -struct ArrayListReverseIter(Value,bit ReadOnly, Alloc=GCAllocator) { - mixin MReverseImpl!(ArrayList!(Value,ReadOnly,Alloc)); -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - private import std.string; - private import std.random; - unittest { - version (MinTLVerboseUnittest) - printf("started mintl.arraylist unittest\n"); - - ArrayList!(int) x,y,z; - x.data = new int[10]; - x.add(5,3,4); - assert( x[0] == 5 ); - assert( x[1] == 3 ); - assert( x[2] == 4 ); - assert( x.length == 3 ); - x.takeTail(); - x ~= 4; - assert( x[2] == 4 ); - - y = x.dup; - - assert( x == y ); - - x.addHead(-1); - x.addHead(-2); - // private bug - // assert( x.start == x.data.length - 2 ); - assert( x.head == x[0 .. 1] ); - assert( x.length == 5 ); - assert( x.tail == x[4 .. 5] ); - assert( x.data[x.data.length-1] == -1); - assert( x.data[x.data.length-2] == -2); - assert( x.takeHead == -2 ); - assert( x.takeHead == -1 ); - assert( x[0] == 5 ); - assert( x[x.length-1] == 4 ); - assert( x.takeHead == 5 ); - assert( x.takeHead == 3 ); - assert( x.takeHead == 4 ); - assert( x.length == 0 ); - - assert( y.length == 3 ); - assert( y[0] == 5 ); - assert( y[2] == 4 ); - y ~= 6; - debug(dArrayList) printf("%d %d %d %d\n",y.start,y.tail_,y[0],y[3]); - y = y.reverse; - debug(dArrayList) printf("%d %d %d %d\n",y.start,y.tail_,y[0],y[3]); - assert( y[0] == 6 ); - assert( y[1] == 4 ); - assert( y[2] == 3 ); - assert( y[3] == 5 ); - - int[10] y2; - int k=0; - foreach(int val; y) { - y2[k++] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - - k=0; - foreach(int val; y.backwards()) { - y2[k++] = val; - } - assert( y2[0] == 5 ); - assert( y2[1] == 3 ); - assert( y2[2] == 4 ); - assert( y2[3] == 6 ); - - k=0; - foreach(size_t n, int val; y) { - y2[n] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - - k=0; - foreach(ArrayList!(int) itr; y) { - y2[k++] = itr[0]; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - - ArrayList!(int) y3 = y[2..4]; - assert( y3.length == 2 ); - assert( y3[0] == 3 ); - assert( y3[1] == 5 ); - y3[0..1].swap(y3[1..2]); - assert( y3[0] == 5 ); - assert( y3[1] == 3 ); - - y3[0] = 10; - assert( y[2] == 10 ); - - y3.next(-1); - assert( y3.length == 2 ); - assert( y3[0] == 4 ); - assert( y3[1] == 10 ); - y3.next(-1,-1); - assert( y3.length == 3 ); - assert( y3[0] == 6 ); - assert( y3[2] == 10 ); - y3.next(1,1); - assert( y3.length == 4 ); - assert( y3[0] == 6 ); - assert( y3[3] == 3 ); - - ArrayList!(char[]) c = ArrayList!(char[]).make("a","a","a","a"); - assert( c.opIn("a") == c.head ); - assert( c.count("a") == 4 ); - for (int kk=0;kk<100;kk++) { - c ~= toString(kk); - c.takeHead(); - } - - // test addAfter, addBefore and remove - ArrayList!(double) w; - w.data = new double[30]; - for (int j=0;j<20;j++) - w ~= j; - w.remove(w[10..15]); - assert( w.length == 15 ); - assert( w[10] == 15 ); - for (int j=0;j<5;j++) - w.addHead(j); - w.remove(w[2..7]); - assert( w.length == 15 ); - ArrayList!(double) w2; - w2.data = new double[30]; - for (k=0;k<20;k++) - w2 ~= k; - w.addBefore(w[5..7],w2[10..15]); - assert( w.length == 20 ); - assert( w[0] == 4 ); - foreach( double d; w) { - version (MinTLVerboseUnittest) - printf(" %g",d); - } - version (MinTLVerboseUnittest) - printf("\n"); - assert( w[5] == 10 ); - - ArrayList!(int) cda = ArrayList!(int).make(20,30); - cda.capacity = 20; - assert( cda.capacity >= 20 ); - assert( cda.length == 2 ); - assert( cda.values == cda.data[0..2] ); - cda.length = 4; - assert( cda.length == 4 ); - assert( cda[cda.length - 1] == 0 ); - cda.capacity = 40; - assert( cda.length == 4 ); - assert( cda.data.length >= 40 ); - cda.addHead(40); - cda.addHead(50); - cda.capacity = 50; - uint ss = cda.capacity; - assert( cda.length >= 6 ); - assert( cda[0] == 50 ); - assert( cda[1] == 40 ); - assert( cda[2] == 20 ); - assert( cda[3] == 30 ); - assert( cda[4] == 0 ); - - ArrayList!(int,false,Malloc) xm = - ArrayList!(int,false,Malloc).make(10,20,30); - assert( xm.takeTail == 30 ); - assert( xm.takeHead == 10 ); - for (int u;u<10000;u++) { - xm ~= u; - } - xm.clear(); - assert( xm.isEmpty ); - - // test simple sorting - ArrayList!(int) s1; - s1.add(40,300,-20,100,400,200); - s1.sort(); - ArrayList!(int) s2 = ArrayList!(int).make(-20,40,100,200,300,400); - assert( s1 == s2 ); - - // test a large sort with default order - ArrayList!(double) s3; - for (k=0;k<1000;k++) { - s3 ~= 1.0*rand()/100000.0 - 500000.0; - } - ArrayList!(double) s4 = s3.dup; - s3.sort(); - for (k=0;k<999;k++) { - assert( s3[k] <= s3[k+1] ); - } - // test a large sort with custom order - int cmp(double*x,double*y){return *x>*y?-1:*x==*y?0:1;} - s4.sort(&cmp); - for (k=0;k<999;k++) { - assert( s4[k] >= s4[k+1] ); - } - - version (MinTLVerboseUnittest) - printf("finished mintl.arraylist unittest\n"); - } -}
--- a/trunk/mintl/deque.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,920 +0,0 @@ -/** \file deque.d - * \brief A resizable double-ended queue stored in blocks with - * constant time insertion at the front and tail. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.deque; - -import mintl.mem; -private import mintl.share; // for ~ and ~= -private import mintl.sorting; - -private extern(C) void *memmove(void *, void *, uint); - -//debug = dDeque; // can also pass at command line - -/** \class Deque - * \brief A resizable double-ended queue stored in blocks with - * constant time insertion at the front and tail. - * - * A Deque!(Value) is a list of data of type Value backed by a - * block-allocated array. The size of the allocation blocks varies - * with the number of elements in the deque. The performance of Deques - * is on the same order as for arrays except adding an element to the - * head of a Deque is constant. - * - * The optional ReadOnly parameter Deque!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter Deque!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct Deque(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias Deque ContainerType; - alias Deque SliceType; - alias Value ValueType; - alias size_t IndexType; - alias ReadOnly isReadOnly; - - alias Value* Block; - const size_t psize = (void*).sizeof; - - invariant { - assert( total() == 0 || start < total() ); - assert( len <= total() ); - } - - /** Get a ReadOnly view of the container */ - .Deque!(Value, true, Alloc) readonly() { - .Deque!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .Deque!(Value, false, Alloc) readwrite() { - .Deque!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (ReadOnly) { - /** Duplicates a deque. */ - /* private bug - Deque dup() { - .Deque!(Value,false,Alloc) res; - size_t cap = block(len)+1; - if (len == 0) return res.readonly; - static if (is(Alloc == GCAllocator)) { - res.data = new Block[cap]; - } else { - Block* p = cast(Block*)Alloc.malloc(cap * psize); - res.data = p[0..cap]; - res.data[] = null; - } - res.addTail(this.readwrite); - return res.readonly; - } - */ - } else { - - /** Appends an item to the tail of the deque. If the target deque is - * a slice call addAfter instead of addTail to insert an item - * after a slice. - */ - void addTail(Value v) { - capacity(len+1); - *plookup(addi(start,len)) = v; - len++; - } - - /** Appends a deque to the tail of the target deque. If the target - * deque is a slice call addAfter instead of addTail to insert - * another deque after a slice. - */ - void addTail(Deque v) { - size_t vlen = v.len; - if (vlen == 0) return; - capacity(len+vlen); - copyBlock(v, data, addi(start,len), vlen); - len += vlen; - } - - /** overload ~ and ~= */ - mixin MListCatOperators!(Deque); - - /** Removes and returns the tail item of the deque. If the target - * deque is empty an IndexOutOfBoundsException is thrown unless - * version=MinTLNoIndexChecking is set. - */ - Value takeTail() { - boundsCheck(len-1); - len--; - Value* pval = plookup(addi(start,len)); - Value val = *pval; - *pval = Value.init; - return val; - } - - /** Removes the tail item of the deque. */ - void removeTail() { - boundsCheck(len-1); - len--; - *plookup(addi(start,len)) = Value.init; - } - - /** Prepends an item to the head of the target deque. If the target - * deque is a slice call addBefore instead of addHead to insert an - * item before a slice. - */ - void addHead(Value v) { - capacity(len+1); - start = dec(start); - *plookup(start) = v; - len++; - } - - /** Prepends a deque to the head of the target deque. If the target - * deque is a slice call addBefore instead of addHead to insert a - * deque before a slice. - */ - void addHead(Deque v) { - size_t vlen = v.len; - if (vlen == 0) return; - capacity(len+vlen); - size_t newhead = subi(start,vlen); - copyBlock(v, data, newhead, vlen); - start = newhead; - len += vlen; - } - - /** Removes and returns the head item of the deque. If the target - * deque is empty an IndexOutOfBoundsException is thrown unless - * version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - boundsCheck(len-1); - Value* pval = plookup(start); - start = inc(start); - Value val = *pval; - *pval = Value.init; - len--; - debug(dDeque) printf("%d %d\n",start,val); - return val; - } - - /** Removes the head item of the deque. */ - void removeHead() { - boundsCheck(len-1); - Value* pval = plookup(start); - start = inc(start); - len--; - *pval = Value.init; - } - - /** Insert a deque before a slice. */ - void addBefore(Deque subv, Deque v) { - size_t vlen = v.length; - if (vlen == 0) return; - capacity(len+vlen); - size_t tlen = subv.start >= start ? subv.start-start : total-start+subv.start; - size_t newhead = subi(start,vlen); - debug(dDeque)printf("about to moveBlockLeft %d\n",tlen); - moveBlockLeft(start,tlen,newhead); - copyBlock(v,data,subi(subv.start,vlen),vlen); - start = newhead; - len += vlen; - } - - /** Insert a deque after a slice. */ - void addAfter(Deque subv, Deque v) { - size_t vlen = v.length; - if (vlen == 0) return; - capacity(len+vlen); - size_t tail = addi(start,len); - size_t subtail = addi(subv.start,subv.len); - size_t tlen = subtail <= tail ? tail-subtail : total-subtail+tail; - moveBlockRight(subtail,tlen,addi(subtail,vlen)); - copyBlock(v,data,subtail,vlen); - len += vlen; - } - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - foreach (Block b; data) { - Alloc.gcFree(b); - } - if (data.ptr) - Alloc.free(data.ptr); - } - *this = Deque.init; - } - - /** Set the nth item in the deque from head. Indexing out of bounds - * throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - void opIndexAssign(Value val, size_t n) { - boundsCheck(n); - *plookup(addi(start,n)) = val; - } - - /** Set the value of one-item slice (more generally the head value). */ - void value(Value newValue) { - opIndexAssign(newValue,0); - } - - /** Removes a slice from the deque. */ - void remove(Deque sublist) { - size_t tail = addi(start,len); - size_t slen = sublist.len; - size_t stail = addi(sublist.start,slen); - size_t tlen = stail <= tail ? tail-stail : data.length-stail+tail; - debug(dArrayList) printf("remove %d %d\n",sublist.start, sublist.length); - moveBlockLeft(stail, tlen, sublist.start); - fillBlock(subi(tail,slen),slen,Value.init); - len -= slen; - } - - /** Removes an item from the list and returns the value, if present. */ - Value take(size_t index) { - Deque item = opSlice(index, index+1); - Value val = item[0]; - remove(item); - return val; - } - - /** Removes an item from the deque if present. */ - void remove(size_t index) { - Deque item = opSlice(index, index+1); - remove(item); - } - - /** Reverse a deque in-place. */ - Deque reverse() { - size_t tlen = len / 2; - size_t a,b; - a = start; - b = dec(addi(start,len)); - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < tlen; k++) { - ti.swap(plookup(a),plookup(b)); - a = inc(a); - b = dec(b); - } - return *this; - } - - /** Duplicates a deque. */ - Deque dup() { - Deque res; - if (len == 0) return res; - size_t cap = block(len)+1; - static if (is(Alloc == GCAllocator)) { - res.data = new Block[cap]; - } else { - Block* p = cast(Block*)Alloc.malloc(cap * psize); - res.data = p[0..cap]; - res.data[] = null; - } - res.addTail(*this); - return res; - } - - } // !ReadOnly - - /** Move a slice towards the tail by n items. If n is - * negative the slice moves towards the head. A positive end is - * the tail, negative the head and 0 is both. By default moves to - * to the next item. - */ - void next(int n = 1, int end = 0) { - if (end) - len += n<0?-n:n; - if (end <= 0) { - if (n<0) { - start = subi(start,-n); - } else { - start = addi(start,n); - } - } - } - - /** Get the length of deque. */ - size_t length() { - return len; - } - - /** Test if container is empty. */ - bool isEmpty() { - return len == 0; - } - - /** Get the nth item in the deque from head. Indexing out of bounds - * throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Value opIndex(size_t n) { - boundsCheck(n); - return *plookup(addi(start,n)); - } - - // lookup an index and return a pointer to the slot - private Value* plookup(size_t n) { - debug(dDeque) printf("plookup for %d block %d offset %d blocklen %d\n", - n,block(n),offset(n),data.length); - debug(dDeque) printf(" plookup got %p\n", data[block(n)]); - size_t bn = block(n); - // if (bn >= data.length) bn -= data.length; - Block b = data[bn]; - if (b is null) - data[bn] = b = newBlock();; - return b+offset(n); - } - - // allocate a new block - private Block newBlock() { - static if (is(Alloc == GCAllocator)) { - return (new Value[BlockSize]).ptr; - } else { - Value* p = cast(Value*)Alloc.gcMalloc(BlockSize * Value.sizeof); - Value[] q = p[0..BlockSize]; - q[] = Value.init; - return p; - } - } - - /** Get the value of one-item slice (more generally the head value). - * Useful for expressions like x.tail.value or x.head.value. */ - Value value() { - return opIndex(0); - } - - // helper function to check if the index is legal - private void boundsCheck(size_t n) { - version (MinTLNoIndexChecking) { - } else { - if (n >= len) { - throw new IndexOutOfBoundsException(); - } - } - } - - /** Get deque contents as dynamic array. */ - Value[] values() { - Value[] res = new Value[len]; - foreach(size_t k, Value val; *this) - res[k] = val; - return res; - } - - /** Test for equality of two deques. */ - int opEquals(Deque c) { - if (len !is c.len) - return 0; - size_t a,b; - a = start; - b = c.start; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < len; k++) { - Value* bn = c.data[block(b)]+offset(b); - if (!ti.equals(plookup(a),bn)) - return 0; - a = inc(a); - b = inc(b); - } - return 1; - } - - /** Compare two lists. */ - int opCmp(Deque c) { - size_t tlen = len; - if (tlen > c.len) - tlen = c.len; - size_t a,b; - a = start; - b = c.start; - TypeInfo ti = typeid(Value); - for (size_t k = 0; k < tlen; k++) { - Value* bn = c.data[block(b)]+offset(b); - int cmp = ti.compare(plookup(a),bn); - if (cmp) - return cmp; - a = inc(a); - b = inc(b); - } - return cast(int)len - cast(int)c.len; - } - - /** Create a slice from index a to b (exclusive). */ - Deque opSlice(size_t a, size_t b) { - Deque res; - res.data = data; - res.start = addi(start,a); - res.len = b-a; - return res; - } - - /** Create a slice from the head of a to the tail of b (inclusive). */ - Deque opSlice(Deque a, Deque b) { - Deque res; - res.data = data; - res.start = a.start; - if (b.start >= a.start) - res.len = b.start - a.start + b.len; - else - res.len = data.length - a.start + b.len + b.start; - return res; - } - - /** Create a one-item slice of the head. */ - Deque head() { - return opSlice(0,1); - } - - /** Create a one-item slice of the tail. */ - Deque tail() { - return opSlice(len-1,len); - } - - /** Iterates over the deque from head to tail calling delegate to - * perform an action. The value is passed to the delegate. - */ - int opApplyNoKeyStep(int delegate(inout Value x) dg,int step=1){ - int dg2(inout size_t n, inout Value x) { - return dg(x); - } - return opApplyWithKeyStep(&dg2,step); - } - - /** Iterates over the deque from head to tail calling delegate to - * perform an action. The index from 0 and the value are passed - * to the delegate. - */ - int opApplyWithKeyStep(int delegate(inout size_t n, inout Value x) dg, - int step = 1){ - if (len == 0) return 0; - int res = 0; - size_t tail = addi(start,len); - size_t istart = step>0 ? start : dec(tail); - size_t iend = step>0 ? tail : dec(start); - size_t n = step>0 ? 0 : len-1; - for (size_t k = istart; k != iend;) { - res = dg(n,data[block(k)][offset(k)]); - if (res) break; - if (step < 0) - k = subi(k,-step); - else - k = addi(k,step); - n += step; - } - return res; - } - - /** Iterates over the deque from head to tail calling delegate to - * perform an action. A one-item slice is passed to the delegate. - */ - int opApplyIterStep(int delegate(inout Deque n) dg, int step = 1){ - Deque itr; - itr.data = data; - itr.len = 1; - int dg2(inout size_t n, inout Value x) { - itr.start = addi(start,n); - return dg(itr); - } - return opApplyWithKeyStep(&dg2,step); - } - - /** Iterate backwards over the deque (from tail to head). - * This should only be called as the - * iteration parameter in a <tt>foreach</tt> statement - */ - DequeReverseIter!(Value,ReadOnly,Alloc) backwards() { - DequeReverseIter!(Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** Helper functions for opApply */ - mixin MOpApplyImpl!(Deque); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - Deque getThis(){return *this;} - mixin MListAlgo!(Deque, getThis); - mixin MRandomAccessSort!(Deque, getThis); - - /** Get a pointer to the nth item in the deque from head. Indexing - * out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Value* lookup(size_t n) { - boundsCheck(n); - return plookup(addi(start,n)); - } - - // Helper functions - - // compute the block number for an index - private size_t block(size_t n) { - return n >> BlockShift; - } - - // compute the offset within a block for an index - private size_t offset(size_t n) { - return n & BlockMask; - } - - /** Ensure the minimum capacity of list. */ - void capacity(size_t cap) { - cap = block(cap)+1; - if (data.length <= cap) { - cap = cap*2; - debug(dDeque) printf("growing capacity from %d to %d\n",data.length, cap); - if (start + len > total) { - size_t oldlen = data.length; - size_t offs = cap-oldlen; - size_t h = block(start); - resizeData(cap); - memmove(&data[h+offs],&data[h],(oldlen-h)*psize); - if (h == block(start+len)%data.length) { - static if (is(Alloc == GCAllocator)) { - data[h+offs] = data[h+offs][0..BlockSize].dup.ptr; - } else { - Block p = newBlock(); - p[0 .. BlockSize] = data[h+offs][0 .. BlockSize]; - data[h+offs] = p; - } - data[h][offset(start) .. BlockSize] = Value.init; - data[h+offs][0 .. offset(start+len)] = Value.init; - data[h+1 .. h+offs] = null; - } else { - data[h .. h+offs] = null; - } - start += offs*BlockSize; - } else { - resizeData(cap); - } - } - } - - // helper for capacity - private void resizeData(size_t cap) { - static if (is(Alloc == GCAllocator)) { - data.length = cap; - } else { - Block* p = data.ptr; - p = cast(Block*)Alloc.realloc(p,cap*psize); - p[data.length .. cap] = null; - data = p[0 .. cap]; - } - } - - /** Get the capacity of list. */ - size_t capacity() { - return total(); - } - - private const size_t BlockShift = Value.sizeof>128 ? 1 : 7; - private const size_t BlockSize = 1 << BlockShift; - private const size_t BlockMask = BlockSize - 1; - - // Helper functions - - // helper function to copy sections of the backing buffer - private void moveBlockLeft(size_t srchead, size_t len, size_t desthead) { - size_t ns = srchead; - size_t nd = desthead; - debug(dDeque)printf("moveBlockLeft %d\n",len); - while (len > 0) { - size_t sz = len; - size_t offs = offset(ns); - size_t offd = offset(nd); - size_t bn = block(ns); - Block srcblock = data[bn]; - if (srcblock == null) - data[bn] = srcblock = newBlock(); - bn = block(nd); - Block destblock = data[bn]; - if (destblock == null) - data[bn] = destblock = newBlock(); - if (offs+sz > BlockSize) - sz = BlockSize-offs; - if (offd+sz > BlockSize) - sz = BlockSize-offd; - assert(sz != 0); - memmove(&destblock[offd],&srcblock[offs],sz*Value.sizeof); - ns = addi(ns,sz); - nd = addi(nd,sz); - len -= sz; - } - } - - // helper function to copy sections of the backing buffer - private void moveBlockRight(size_t srchead, size_t len, size_t desthead) { - size_t ns = addi(srchead,len-1)+1; - size_t nd = addi(desthead,len-1)+1; - while (len > 0) { - size_t sz = len; - size_t bn = block(ns); - size_t offs = offset(ns); - size_t offd = offset(nd); - Block srcblock = data[bn]; - if (srcblock == null) - data[bn] = srcblock = newBlock(); - bn = block(nd); - Block destblock = data[bn]; - if (destblock == null) - data[bn] = destblock = newBlock(); - if (offs < sz) - sz = offs; - if (offd < sz) - sz = offd; - assert(sz != 0); - memmove(&destblock[offd],&srcblock[offs],sz*Value.sizeof); - ns = dec(subi(ns,sz))+1; - nd = dec(subi(nd,sz))+1; - len -= sz; - debug(dDeque)printf("moveBlockRight %d\n",sz); - } - } - - // helper function to copy sections of the backing buffer - private void copyBlock(Deque src, - Block[] destdata, - uint desthead, - uint len) { - Block[] srcdata = src.data; - int srchead = src.start; - int ns = srchead; - int nd = desthead; - while (len > 0) { - int sz = len; - size_t offs = offset(ns); - size_t offd = offset(nd); - size_t bn = block(ns); - Block srcblock = srcdata[bn]; - if (srcblock == null) - srcdata[bn] = srcblock = newBlock(); - if (offs+sz > BlockSize) - sz = BlockSize-offs; - bn = block(nd); - Block destblock = destdata[bn]; - if (destblock == null) - destdata[bn] = destblock = newBlock(); - if (offd+sz > BlockSize) - sz = BlockSize-offd; - assert(sz != 0); - memmove(&destblock[offd],&srcblock[offs],sz*Value.sizeof); - ns = src.addi(ns,sz); - nd = addi(nd,sz); - len -= sz; - debug(dDeque)printf("copyBlock %d\n",sz); - } - } - - // helper function to fill a section of the backing array - private void fillBlock(size_t srchead, size_t len, Value val) { - size_t ns = srchead; - while (len > 0) { - size_t sz = len; - size_t bn = block(ns); - size_t off = offset(ns); - Block block = data[bn]; - if (block == null) - data[bn] = block = newBlock(); - if (off+sz > BlockSize) - sz = BlockSize-off; - assert(sz != 0); - block[off .. off+sz] = val; - ns = addi(ns,sz); - len -= sz; - debug(dDeque)printf("fillBlock %d\n",sz); - } - } - - // move index n by 1 with wrapping - private size_t inc(size_t n) { - return (n == total()-1) ? 0 : n+1; - } - - // move index n by -1 with wrapping - private size_t dec(size_t n) { - return (n == 0) ? total()-1 : n-1; - } - - // move index n by -diff with wrapping - private size_t subi(size_t n, size_t diff) { - size_t res; - if (n < diff) - res = total() - diff + n; - else - res = n - diff; - return res; - } - - // move index n by diff with wrapping - private size_t addi(size_t n, size_t diff) { - size_t res; - if (total() - n <= diff) { - res = diff - (total() - n); - } else - res = n + diff; - return res; - } - - private size_t total(){ return data.length << BlockShift; } - - private Block[] data; // array of blocks of data - private size_t start, len; -} - -// helper structure for backwards() -struct DequeReverseIter(Value,bit ReadOnly,Alloc) { - mixin MReverseImpl!(Deque!(Value,ReadOnly,Alloc)); -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - private import std.string; - private import std.random; - unittest { - version (MinTLVerboseUnittest) - printf("started mintl.deque unittest\n"); - - Deque!(int) x,y,z; - x.addTail(22); - x.addTail(33); - assert( x[0] == 22 ); - assert( x[1] == 33 ); - x.addHead(11); - assert( x[0] == 11 ); - assert( x[2] == 33 ); - - y = x.dup; - - assert( y.length == 3 ); - assert( y[0] == 11 ); - assert( y[2] == 33 ); - z = x.dup; - z.addTail(y); - assert( z.length == 6 ); - assert( z[0] == 11 ); - assert( z[2] == 33 ); - assert( z[3] == 11 ); - assert( z[4] == 22 ); - assert( z[5] == 33 ); - - Deque!(int,false,Malloc) mx; - mx.add(30,40,50); - assert( mx.takeHead == 30 ); - assert( mx.takeTail == 50 ); - for(int u = 0;u<10000;u++) { - mx~=u; - } - mx.clear(); - assert( mx.isEmpty ); - - x = x.init; - x ~= 5; - x ~= 3; - x ~= 4; - assert( x[0] == 5 ); - assert( x[1] == 3 ); - assert( x[2] == 4 ); - assert( x.length == 3 ); - - x.reverse(); - assert( x[2] == 5 ); - assert( x[1] == 3 ); - assert( x[0] == 4 ); - - y = x.dup; - - assert( x == y ); - - y.addHead(6); - - int[10] y2; - int k=0; - foreach(int val; y) { - y2[k++] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - - int[] w2 = y.values; - assert( w2[0] == 6 ); - assert( w2[1] == 4 ); - assert( w2[2] == 3 ); - assert( w2[3] == 5 ); - assert( w2.length == 4 ); - - k=0; - foreach(int val; y.backwards()) { - y2[k++] = val; - } - assert( y2[0] == 5 ); - assert( y2[1] == 3 ); - assert( y2[2] == 4 ); - assert( y2[3] == 6 ); - k=0; - foreach(size_t n, int val; y) { - y2[n] = val; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - k=0; - foreach(Deque!(int) itr; y) { - y2[k++] = itr[0]; - } - assert( y2[0] == 6 ); - assert( y2[1] == 4 ); - assert( y2[2] == 3 ); - assert( y2[3] == 5 ); - - Deque!(int) y3 = y[2..4]; - assert( y3.length == 2 ); - assert( y3[0] == 3 ); - assert( y3[1] == 5 ); - - y3[0] = 10; - assert( y[2] == 10 ); - - Deque!(char[]) c; - c ~= "a"; - c ~= "a"; - c ~= "a"; - c ~= "a"; - assert( c.opIn("a") == c.head ); - assert( c.count("a") == 4 ); - for (int kk=3;kk<6000;kk++) { - c ~= toString(kk); - c ~= toString(kk+1); - char[] res = c.takeHead(); - if (kk > 10) { - assert( res == toString(kk/2) ); - } - } - - // test addAfter, addBefore and remove - Deque!(double) w; - for (k=0;k<20;k++) - w ~= k; - w.remove(w[10..15]); - assert( w.length == 15 ); - assert( w[10] == 15 ); - for (k=0;k<5;k++) - w.addHead(k); - w.remove(w[2..7]); - assert( w.length == 15 ); - Deque!(double) w3; - for (k=0;k<20;k++) - w3 ~= k; - w.addBefore(w[5..7],w3[10..15]); - assert( w.length == 20 ); - assert( w[0] == 4 ); - foreach( double d; w) { - version (MinTLVerboseUnittest) - printf(" %g",d); - } - version (MinTLVerboseUnittest) - printf("\n"); - assert( w[5] == 10 ); - - // test sorting - Deque!(int) s1,s2; - s1.add(40,300,-20,100,400,200); - s1.sort(); - s2.add(-20,40,100,200,300,400); - assert( s1 == s2 ); - - Deque!(double) s3; - for (k=0;k<1000;k++) { - s3 ~= 1.0*rand()/100000.0 - 500000.0; - } - s3.sort(); - for (k=0;k<999;k++) { - assert( s3[k] <= s3[k+1] ); - } - - version (MinTLVerboseUnittest) - printf("finished mintl.deque unittest\n"); - } -}
--- a/trunk/mintl/hashaa.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,752 +0,0 @@ -/** \file hashaa.d - * \brief A hash-based associative array that maintains elements in insertion order - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.hashaa; - -//debug = dHashAA; // can also pass at command line - -private { - import mintl.share; - import mintl.sorting; - import mintl.mem; -} - -/** \class HashAA - * \brief A hash-based associative array traversed in insertion order. - * - * A HashAA!(Key,Value) represents an associative array with keys of - * type Key and values of type Value that maintains the inserted items - * in a linked list sorted by insertion order. If <tt>key1</tt> is - * inserted into the array before <tt>key2</tt> then <tt>key1</tt> - * will appear before <tt>key2</tt> in foreach statements and in - * iterator traversals. - * - * The optional ReadOnly parameter HashAA!(Key,Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter ArrayList!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct HashAA(Key,Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias HashAA ContainerType; - alias HashAA SliceType; - alias Value ValueType; - alias Key IndexType; - alias Key SortType; - alias ReadOnly isReadOnly; - - /** Get the kays in the array. The operation is O(n) where n is the number of - * elements in the array. - */ - Key[] keys() { - Key[] res; - if (head_ is null) return res; - res.length = length; - size_t n = 0; - foreach(Key k,Value v;*this) { - res[n++] = k; - } - return res; - } - - /** Get the values in the array. The operation is O(n) where n is - * the number of elements in the array. - */ - Value[] values() { - Value[] res; - if (head_ is null) return res; - res.length = length; - size_t n = 0; - foreach(Key k,Value v;*this) { - res[n++] = v; - } - return res; - } - - /** Property for the default value of the array when a key is missing. */ - void missing(Value val) { - if (data.length == 0) - initDataArray(); - data[0].val = val; - } - Value missing() { - if (data.length == 0) - return Value.init; - return data[0].val; - } - - /** Length of array. The operation is O(n) where n is the number of - * elements in the array. - */ - size_t length() { - if (head_ is null) return 0; - if (head_.prev is null && tail_.next is null) return dlength(); - Node* t = head_; - int n = 1; - while (t !is null && t !is tail_) { - t = t.next; - ++n; - } - return n; - } - - /** Return true if array is empty. */ - bool isEmpty() { - return head_ is null; - } - - private void initDataArray() { - size_t s = prime_list[0]+1; - static if (is(Alloc == GCAllocator)) { - data.length = s; - } else { - Node** p = cast(Node**)Alloc.malloc((Node*).sizeof*s); - data = p[0 .. s]; - } - data[0] = allocNode; - data[0].len = 0; - } - - private enum {InsertOnMiss, ThrowOnMiss, NullOnMiss} - - // helper functions for indexing. - private Node** getNode(Key key, int failureAction) { - Node* t; - TypeInfo ti = typeid(Key); - uint hash = ti.getHash(&key); - if (data.length == 0) { - switch (failureAction) { - case InsertOnMiss: - initDataArray(); - break; - case ThrowOnMiss: - GetActionThrow: - throw new IndexOutOfBoundsException("Key not in container"); - case NullOnMiss: - return null; - } - } - uint i = (hash % (data.length-1))+1; - Node**p = &data[i]; - while (*p !is null) { - if ((*p).hash == hash && ti.equals(&(*p).key,&key)) { - // found key - return p; - } - p = &(*p).nextHash; - } - if (failureAction == ThrowOnMiss) { - goto GetActionThrow; - } else if (failureAction == NullOnMiss) { - return null; - } - // lookup Node - *p = t = allocNode(); - t.hash = hash; - t.key = key; - if (head_ is null) { - head_ = t; - tail_ = t; - } else { - link(tail_,t); - tail_ = t; - } - data[0].len++; - static if (!ReadOnly) { - if (data[0].len > .75*data.length) { - this.rehash(); - p = getNode(key,NullOnMiss); - } - } - return p; - } - - /** Find the element with a given key and return a pointer to the - * value. If the key is not in the array null is returned or if - * throwOnMiss is true an exception is thrown. The target array can - * be a sub-array though the key may fall outside of the sub-array - * range. - */ - Value* get(Key key, bool throwOnMiss = false) { - Node** t = getNode(key,throwOnMiss ? ThrowOnMiss : NullOnMiss); - if (t) - return &(*t).val; - else - return null; - } - - /** Create a sub-array from key a to b (exclusive). */ - HashAA opSlice(Key a, Key b) { - HashAA res; - res.head_ = *getNode(a,ThrowOnMiss); - res.tail_ = (*getNode(b,ThrowOnMiss)).prev; // will at least have a in there - res.data = data; - return res; - } - - /** Create a sub-array from the first key in a to the last key in b (inclusive). */ - HashAA opSlice(HashAA a, HashAA b) { - HashAA res; - res.head_ = a.head_; - res.tail_ = b.tail_; - res.data = data; - return res; - } - - /** Get a ReadOnly view of the container */ - .HashAA!(Key,Value,true,Alloc) readonly() { - .HashAA!(Key,Value,true,Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .HashAA!(Key,Value,false,Alloc) readwrite() { - .HashAA!(Key,Value,false,Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (ReadOnly) { - /** Duplicates the array. The operation is O(n) where n is length. */ - /* private bug - HashAA dup() { - .HashAA!(Key,Value,false) res; - res.data.length = data.length; - res.data[0] = cast(res.Node*)allocNode; - res.data[0].len = 0; - res.missing = missing; - foreach(Key k,Value v;*this) - res[k] = v; - return res.readonly; - } - */ - } else { - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - foreach ( Node* t; data) { - while (t) { - Node* next = t.nextHash; - Alloc.gcFree(t); - t = next; - } - } - Alloc.free(data.ptr); - } - *this = HashAA.init; - } - - /** Duplicates the array. The operation is O(n) where n is length. */ - HashAA dup() { - HashAA res; - res.data.length = data.length; - res.data[0] = allocNode; - res.data[0].len = 0; - res.missing = missing; - foreach(Key k,Value v;*this) { - res[k] = v; - } - return res; - } - - /** Rehash the array. */ - HashAA rehash() { - uint k; - uint len = data.length; - if (len == 0) return *this; - for (k=0;k<prime_list.length;k++) { - if (prime_list[k] > len) - break; - } - Node* n = data[0]; - size_t s = prime_list[k]+1; - static if (is(Alloc == GCAllocator)) { - data = new Node*[s]; - } else { - Node** p = cast(Node**)Alloc.malloc((Node*).sizeof * s); - data = p[0 .. s]; - } - data[0] = n; - Node* t = head_; - while (t) { - uint i = (t.hash %(data.length-1))+1; - t.nextHash = data[i]; - data[i] = t; - t = t.next; - } - return *this; - } - - /** Find a key in the array and return a pointer to the associated value. - * Insert the key and initialize with Value.init if the key is not - * in the array. - */ - Value* put(Key key) { - debug (dHashAA) printf("put %d\n",key); - Node* t = *getNode(key, InsertOnMiss); - return &t.val; - } - - /** Store a value with a key, overwriting any previous value. The - * target array can be a sub-array though the key may fall outside of the - * sub-array range. - */ - void opIndexAssign(Value val, Key key) { - Node* t = *getNode(key, InsertOnMiss); - t.val = val; - } - - // helper for remove/take - private Node* takeHelper(Key key) { - Node** p = getNode(key,NullOnMiss); - if (!p) return null; - Node* n = *p; - if (n is head_) - head_ = n.next; - if (n is tail_) - tail_ = n.prev; - link(n.prev, n.next); - *p = n.nextHash; - return n; - } - - /** Remove a key from the array. The target array can be a sub-array though - * the key may fall outside of the sub-array range. - */ - void remove(Key key) { - Node* n = takeHelper(key); - if (n) { - static if (is(Alloc == GCAllocator)) { - static if (Node.sizeof < AllocBlockCutoff) { - n.next = data[0].next; - data[0].next = n; - n.prev = null; - n.val = Value.init; - n.key = Key.init; - } - } else { - Alloc.gcFree(n); - } - data[0].len--; - } - } - - /** Remove the value stored with the given key and return it, if present. - * If not present return the missing default. - */ - Value take(Key key) { - Node* n = takeHelper(key); - if (!n) return missing; - Value val = n.val; - static if (is(Alloc == GCAllocator)) { - static if (Node.sizeof <= AllocBlockCutoff) { - n.next = data[0].next; - data[0].next = n; - n.val = Value.init; - n.key = Key.init; - n.prev = null; - } - } else { - Alloc.gcFree(n); - } - data[0].len--; - return val; - } - - /** Remove a sub-array from the array. The operation is O(max(log(m),n)) - * where m is the size of the target array and n is the number of - * elements in the sub-array. - */ - void remove(HashAA subarray) { - if (subarray.head_ is subarray.tail_) { - remove(subarray.key); - } else { - Key[] keylist = subarray.keys; - foreach(Key key;keylist) - remove(key); - } - } - - mixin MAddAA!(HashAA); // mixin add function - - } // !ReadOnly - - private void link(Node* a, Node* b) { - if (a) a.next = b; - if (b) b.prev = a; - } - - // remove extra capacity - void trim() { - if (data.length > 0 && data[0]) - data[0].next = null; - } - - // Parameters for controlling block allocations - private const int AllocBlockSize = 10; // number of nodes in block - private const int AllocBlockCutoff = 96; // max node size to allow blocks - - private Node* allocNode() { - Node* p; - static if (is(Alloc == GCAllocator)) { - static if (Node.sizeof > AllocBlockCutoff) { - return new Node; - } else { - if (data[0] is null) return new Node; - p = data[0].next; - if (p) { - data[0].next = p.next; - p.next = null; - return p; - } - p = (new Node[AllocBlockSize]).ptr; - for (int k=1;k<AllocBlockSize-1;k++) - p[k].next = &p[k+1]; - data[0].next = &p[1]; - return &p[0]; - } - } else { - p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - } - return p; - } - - /** Find the element with a given key and return the value. If the - * key is not in the map the default for the array is returned. The - * target array can be a sub-array though the key may fall outside - * of the sub-array range. - */ - Value opIndex(Key key) { - Value* t = get(key); - if (t) - return *t; - else - return missing; - } - - /** Returns the value of a one-item array. */ - Value value() { - if (head_ is null && tail_ is null) - return Value.init; - return head_.val; - } - - /** Returns the key of a one-item array. */ - Key key() { - if (head_ is null && tail_ is null) - return Key.init; - return head_.key; - } - - /** Return a one-item slice of the head (oldest insertion). */ - HashAA head() { - HashAA res = *this; - res.tail_ = res.head_; - return res; - } - - /** Return a one-item slice of the tail (more recent insertion). */ - HashAA tail() { - HashAA res = *this; - res.head_ = res.tail_; - return res; - } - - /** Move a slice by n. By default moves to the next item. */ - void next(int n = 1, int end = 0) { - void doNext(inout Node* node, int m) { - while (m--) - node = node.next; - } - void doPrev(inout Node* node, int m) { - while (m--) - node = node.prev; - } - if (n > 0) { - if (end >= 0) - doNext(tail_,n); - if (end <= 0) - doNext(head_,n); - } else { - n = -n; - if (end >= 0) - doPrev(tail_,n); - if (end <= 0) - doPrev(head_,n); - } - } - - /** Test for equality of two arrays. The operation is O(n) where n - * is length of the array. - */ - int opEquals(HashAA c) { - Node* i = head_; - Node* j = c.head_; - Node* end = tail_; - Node* cend = c.tail_; - TypeInfo ti_k = typeid(Key); - TypeInfo ti_v = typeid(Value); - int do_test(Node*p1,Node*p2) { - if (!ti_k.equals(&p1.key,&p2.key)) - return 0; - if (!ti_v.equals(&p1.val,&p2.val)) - return 0; - return 1; - } - while (i !is null && j !is null) { - if (!do_test(i,j)) - return 0; - if (i is end || j is cend) { - return (i is end && j is cend); - } - i = i.next; - j = j.next; - } - return (i is null && j is null); - } - - /** Test if a key is in the array. The target array can be a sub-array - * but the key may fall outside of the sub-array range. - */ - bool contains(Key key) { - return get(key) !is null; - } - - /** Test if a key is in the array and set value if it is. */ - bool contains(Key key,out Value value) { - Value* node = get(key); - if (node) - value = *node; - return node !is null; - } - - /** Iterate over the array calling delegate to perform an action. A - * one-element sub-array is passed to the delegate. - */ - int opApplyNoKeyStep(int delegate(inout Value val) dg, int step = 1) { - int dg2(inout HashAA itr) { - Value value = itr.value; - return dg(value); - } - return opApplyIterStep(&dg2,step); - } - - /** Iterate over the array calling delegate to perform an action. A - * one-element sub-array is passed to the delegate. - */ - int opApplyWithKeyStep(int delegate(inout Key key, inout Value val) dg, - int step = 1) { - int dg2(inout HashAA itr) { - Key key = itr.key; - Value value = itr.value; - return dg(key,value); - } - return opApplyIterStep(&dg2,step); - } - - /** Iterate over the array calling delegate to perform an action. A - * one-element sub-array is passed to the delegate. - */ - int opApplyIterStep(int delegate(inout HashAA itr) dg,int step=1) { - int res = 0; - HashAA itr; - Node* x = step>0?head_:tail_; - Node* end = step>0?tail_:head_; - while (x !is null) { - itr.head_ = itr.tail_ = x; - res = dg(itr); - if (res || x is end) return res; - x = step>0?x.next:x.prev; - } - return res; - } - - /** Iterate backwards over the array (from last to first key). The target - * array can be a sub-array. This should only be called as the - * iteration parameter in a <tt>foreach</tt> statement - */ - LAReverseIter!(Key,Value,ReadOnly,Alloc) backwards() { - LAReverseIter!(Key,Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** Helper functions for opApply */ - mixin MOpApplyImpl!(HashAA); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - Node* getHead(){return head_;} - Node* getTail(){return tail_;} - mixin MSequentialSort!(HashAA, getHead,getTail); - void sort(int delegate(Key*a, Key*b) cmp = null) { - Node* newhead, newtail; - dosort(newhead,newtail,cmp); - head_ = newhead; - tail_ = newtail; - } - - private { - struct Node { - Node* next, prev, nextHash; - union { - uint len; - uint hash; - } - Key key; - Value val; - Key* sortLookup(){return &key;} - } - Node*[] data; - Node* head_, tail_; - } - - private uint dlength() { return data[0].len; } - - // size primes from aaA.d and planetmath.org - private static uint[] prime_list = - [97u, 389u, 1543u, 6151u, - 24593u, 98317u, 393241u, 1572869u, - 6291469u, 25165843u, 100663319u, 402653189u, - 1610612741u, 4294967291u - ]; -} - -// internal helper struct for backwards iteration -struct LAReverseIter(Key,Value,bit ReadOnly,Alloc) { - mixin MReverseImpl!(HashAA!(Key,Value,ReadOnly,Alloc)); -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - private import std.random; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.hashaa unittest\n"); - - HashAA!(int,int) m; - m[4] = 100; - m[-10] = 200; - m[17] = 300; - assert( m.length == 3 ); - assert( m[-10] == 200 ); - - HashAA!(int,int) mm; - mm.add(4,100, -10,200, 17,300); - assert( m == mm ); - - // test foreach - int[] res; - res.length = 3; - int n=0; - foreach(int val; m) { - res[n++] = val; - } - assert( res[0] == 100 ); - assert( res[1] == 200 ); - assert( res[2] == 300 ); - - // test removing an item - m.remove(-10); - n = 0; - foreach(int val; m) { - res[n++] = val; - } - assert( res[0] == 100 ); - assert( res[1] == 300 ); - - // test assigning to an item already in array - m[22] = 400; - m[17] = 500; - n = 0; - foreach(int val; m) { - res[n++] = val; - } - assert( res[0] == 100 ); - assert( res[1] == 500 ); - assert( res[2] == 400 ); - - // test backwards foreach - n = 0; - foreach(int k,int val; m.backwards()) { - res[n++] = val; - } - assert( res[0] == 400 ); - assert( res[1] == 500 ); - assert( res[2] == 100 ); - - // test slicing - HashAA!(int, int) m2 = - HashAA!(int,int).make(400,4,100,1,500,5,300,3, - 200,2,600,6); - HashAA!(int, int) m3; - m3 = m2[500 .. 600]; - assert( m3.length == 3 ); - n = 0; - foreach(int k,int val; m3) { - res[n++] = val; - } - assert( res[0] == 5 ); - assert( res[1] == 3 ); - assert( res[2] == 2 ); - - // test keys - int[] keys = m3.keys; - assert( keys[0] == 500 ); - assert( keys[1] == 300 ); - assert( keys[2] == 200 ); - - // test rehash - for (int k=0; k<1000; k++) - m3[k] = k; - HashAA!(int,int) m4 = m3.rehash; - assert( m4 == m3 ); - - // test simple sorting - HashAA!(int,int) s1,s12; - s1.add(40,1,300,2,-20,3,100,4,400,5,200,6); - s12 = s1.dup; - s1.sort(); - assert( s1 == HashAA!(int,int).make(-20,3,40,1,100,4,200,6,300,2,400,5) ); - // sort a slice in-place - HashAA!(int,int) slice1 = s12[300 .. 200]; - slice1.sort(); - assert( s12 == HashAA!(int,int).make(40,1,-20,3,100,4,300,2,400,5,200,6)); - - // test a large sort with default order - HashAA!(double,int) s3; - for (int k=0;k<1000;k++) { - s3[1.0*rand()/100000.0 - 500000.0] = k; - } - HashAA!(double,int) s4 = s3.dup; - s3.sort(); - double[] keys2 = s3.keys; - for (int k=0;k<999;k++) { - assert( keys2[k] <= keys2[k+1] ); - } - // test a large sort with custom order - int cmp(double*x,double*y){return *x>*y?-1:*x==*y?0:1;} - s4.sort(&cmp); - keys2 = s4.keys; - for (int k=0;k<999;k++) { - assert( keys2[k] >= keys2[k+1] ); - } - - version (MinTLVerboseUnittest) - printf("finished mintl.hashaa unittest\n"); - } -}
--- a/trunk/mintl/index.html Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1781 +0,0 @@ -<HTML> <head> <TITLE>Minimal Template Library for D</TITLE> </head> -<body> -<h1>MinTL</h1> -MinTL is a "minimal template library" of containers for the D -programming language. For more info about D see <a -href="http://www.digitalmars.com/d/">DigitalMars D home page</a>. The -downloads are the <a href="mintl.zip">Core Library</a> and -the <a href="mintlc.zip">MinTL Concurrent Library</a> -(<a href="conc.html">mintlc web page</a>), which includes -a dependent <a href="locks.html">Synchronization Library</a>. -The current version is 2.7.1. -<p> -This library is in the public domain. -Written by <a href="http://home.comcast.net/~benhinkle"> -Ben Hinkle</a>, 2004. -Email comments and bug reports to ben.hinkle@gmail.com -<p> -<h3> Contents </h3> -<a href="#Overview">Overview</a></br> -<a href="#Lists">List Containers</a></br> -<a href="#Assoc">Associative Containers</a></br> -<a href="#Slicing">Slicing</a></br> -<a href="#Foreach">Foreach traversals</a></br> -<a href="#Sorting">Sorting</a></br> -<a href="#Allocators">Allocators</a></br> -<a href="#unmod">Unmodifiable Containers</a></br> -<a href="#Examples">Examples</a></br> -<a href="#API">API Reference by module</a></br> - -<a name="Overview"></a> -<h3> Overview </h3> - -The philosophy of the library is to be as simple and minimal as -possible: -<list> - -<li> The design is simple by keeping the number of classes to a -minimum and reusing concepts from builtin dynamic and associative -arrays. For example a slice of a container has the same type as the -container, just as the slice of a dynamic array is another dynamic -array. - -<li> -The memory footprint and the garbage generation is kept to a minimum -by relying on structs instead of classes and by implementing slicing -and traversals without allocating dynamic memory. Some containers -also recycle nodes. For example when the head or tail of a list is removed -the node is retained and reused the next time an item is added -to the head or tail. Optional Allocator parameters allow custom memory -management. - -<li> Closely related data structures share common naming conventions -and adapters reuse fundamental data structures like arrays, linked-lists -and sorted associative arrays for stacks, queues and sets. -Performance can be tuned for different uses by either choose -between several variations (eg. a linked list, a circular array or a -deque) or by supplying optional constructor arguments. - -</list> -<p> - -MinTL has the following containers -<p> -<table border="1"> -<caption>List containers</caption> -<tr> -<th>container <th> implementation <th> file <th> brief</th> -</tr> -<tr> -<td> <a href="#list">List</a> -<td> doubly linked list -<td> list.d -<td> sortable linked list with "previous" and "next" pointers -</td> -</tr> -<tr> -<td> <a href="#clist">CircularList</a> -<td> circular doubly linked list -<td> list.d -<td> doubly linked list where the head and tail are linked -</td> -</tr> -<tr> -<td> <a href="#slist">SList</a> -<td> singly linked list -<td> slist.d -<td> linked list with only "next" pointers -</td> -</tr> -<tr> -<td> <a href="#cslist">CircularSList</a> -<td> circular singly linked list -<td> slist.d -<td> singly linked list where the tail points to the head -</td> -</tr> -<tr> -<td> <a href="#arraylist">ArrayList</a> -<td> circular array -<td> arraylist.d -<td> sortable list backed by a resizable circular array -</td> -<tr> -<td> <a href="#deque">Deque</a> -<td> circular block-allocated array -<td> deque.d -<td> list backed by a resizable block-allocated circular array -</td> -<tr> -<td> <a href="#arrayheap">ArrayHeap</a> -<td> heap -<td> arrayheap.d -<td> complete binary tree backed by an array -</td> -<tr> -<td> <a href="#stack">Stack</a> -<td> adapter -<td> stack.d -<td> adapts a list container to be a stack -</td> -<tr> -<td> <a href="#arraystack">ArrayStack</a> -<td> ArrayList -<td> stack.d -<td> wraps an ArrayList with the stack adapter -</td> -<tr> -<td> <a href="#queue">Queue</a> -<td> adapter -<td> queue.d -<td> adapts a list container to be a queue -</td> -<tr> -<td> <a href="#arrayqueue">ArrayQueue</a> -<td> ArrayList -<td> queue.d -<td> wraps an ArrayList with the queue adapter -</td> -<tr> -<td> <a href="#pqueue">PriorityQueue</a> -<td> ArrayHeap -<td> queue.d -<td> wraps an ArrayHeap with the queue adapter -</td> -</table> -<p> -<table border="1"> -<caption>Associative containers</caption> -<tr> -<th>container <th> implementation <th> file <th> brief</th> -<tr> -<td> <a href="#hashaa">HashAA</a> -<td> linked hash table -<td> hashaa.d -<td> sortable associative array with nodes ordered by insertion order -</td> -<tr> -<td> <a href="#sortedaa">SortedAA </a> -<td> red-black tree -<td> sortedaa.d -<td> sorted associative array </td> -</tr> -<tr> -<td> <a href="#set">Set</a> -<td> adapter -<td> set.d -<td> adapts an associative container to be a set -</td> -<tr> -<td> <a href="#sortedset">SortedSet</a> -<td> SortedAA -<td> set.d -<td> wraps a SortedAA with the set adapter -</td> -<tr> -<td> <a href="#multiset">MultiSet</a> -<td> adapter -<td> set.d -<td> adapts an associative container to be a set with repeats -</td> -<tr> -<td> <a href="#sortedmultiset">SortedMultiSet</a> -<td> SortedAA -<td> set.d -<td> wraps a SortedAA with the multi-set adapter -</td> -<tr> -<td> <a href="#multiaa">MultiAA</a> -<td> adapter -<td> multiaa.d -<td> adapts an associative container to hold repeated keys -</td> -<tr> -<td> <a href="#sortedmultiaa">SortedMultiAA</a> -<td> SortedAA -<td> multiaa.d -<td> wraps a SortedAA with the multi-aa adapter -</td> -</table> -<p> - -The module mintl.array defines helper functions for builtin dynamic -and associative arrays. - -<a name="BuildInstall"> -<h3> Build and Install</h3> -To use MinTL first unpack the library in a directory on the D compiler -search path. There are pre-built debug and non-debug versions of the library. -To enable flexible <tt>add()</tt> datatype support uncomment the -<tt>version=WithBox</tt> statement in mintl.share and recompile MinTL. -To use std.boxer in a debug build you must also rebuild phobos with -debugging. -If you wish to rebuild MinTL enter the mintl directory and type -<tt>make -f win32.mak</tt> or <tt>make -f linux.mak</tt>. -In your source code <tt>import</tt> the desired modules and compile each -container used and the mintl static library into the application. -If a concurrent container is needed download the <tt>mintlc</tt> -sub-package and link that library and -the <a href="locks.html">Locks</a> library into the -application. For example on Linux to compile the program <tt>app.d</tt> -<pre> -import mintl.list; - -int main() { - List!(int) list = List!(int).make(10,20,30); - return 0; -} -</pre> -run in the directory above mintl the command -<pre> - dmd app.d mintl/libmintl_debug.a -</pre> -to build with asserts or -<pre> - dmd app.d -release mintl/libmintl.a -</pre> -to build without asserts. -On Windows run -<pre> - dmd app.d mintl\mintl_debug.lib -</pre> -or -<pre> - dmd app.d -release mintl\mintl.lib -</pre> -If the mintl directory is not in the current directory then use the -I flag -to add it to the search path -<pre> - dmd app.d -Ipath_to_mintl path_to_mintl/mintl/libmintl.a -</pre> -or modify the dmd\bin\sc.ini file (on Windows) or dmd.conf (on Linux) -to include the paths to mintl. For example if MinTL is unpacked in the -directory C:\d on Windows then sc.ini should be modified to include C:\d -in the include path and C:\d\mintl on the library search path: -<pre> -LIB="%@P%\..\lib";\dm\lib;C:\d\mintl -DFLAGS="-I%@P%\..\src\phobos";C:\d -</pre> -On Linux the static library can be put in a standard location like -/usr/lib if desired. - -<a name="Lists"> -<h3> List Containers </h3> - -The list containers <tt>List</tt>, <tt>SList</tt>, -<tt>CircularList</tt>, <tt>CircularSList</tt>, <tt>ArrayList</tt>, -<tt>Deque</tt>, <tt>ArrayHeap</tt> and the concurrent queues -and stacks share a naming convention -for adding and removing items. The <i>head</i> is the -first item in the container and the <i>tail</i> is the last item. -All list containers support constant-time access to the head -and tail. -The speed of accessing the <tt>length</tt> property depends on the -container. Array-based containers have constant-time access to length, -the linked-list containers have constant-time unless an operation -modifies the list to have unknown length, in which case the next -time the length is computed it is cached again. The singly-linked -lists have linear-time length access and it is not cached. -<p> -Some containers maintain nodes past the head and tail -of the list as extra capacity. To trim off any extra capacity -most containers support a <tt>trim</tt> function. -<p> -The circular lists -<tt>CircularList</tt> and <tt>CircularSList</tt> are the same as the non-circular -versions except that slicing a circular list returns a non-circular -list and node are not reused when adding or removing items. However -circular lists are useful when the objects being modeled do not have a -natural unique definition of a head or tail. -<p> -An <tt>ArrayList</tt> can also be used as a dynamic array with -managed capacity. Set the <tt>capacity</tt> property or allocate an array -with the desired capacity -and leave the head of the arraylist at 0. The arraylist will -automatically grow the capacity as required. - -<p> To add items to a container call <tt>add</tt> with any number of -items. For example -<pre> - List!(int) x,y,z; - y.add(10,20,30); - z.add(50,60,70); - x = y; x ~= 40; x ~= z; x ~= 80; -</pre> -results in the following linked list -<pre> - x[0],y[0] y[2] z[0] z[2] x[7] - 10 <-> 20 <-> 30 <-> 40 <-> 50 <-> 60 <-> 70 <-> 80 -</pre> -To add a single item or list call <tt>addTail</tt> or use -one of the concatenation operators. Some containers also support adding -items or lists at the head using <tt>addHead</tt> or at a position -in the interior of the list using <tt>addBefore</tt> or <tt>addAfter</tt>. -To create a list in an expression use the static <tt>make</tt> function -For example, -<pre> - List!(int) x; - x = List!(int).make(10,20,30) ~ List!(int).make(50,60,70); -</pre> - -<p> To remove items call one of the <tt>take</tt> or -<tt>remove</tt> functions. -All list containers support <tt>removeHead</tt> to remove -the head of the list and <tt>takeHead</tt> to remove and return -the stored value, if any. -Some containers also support <tt>takeTail</tt> and -<tt>removeTail</tt> to remove the tail and <tt>remove</tt> -to remove a slice. - -<p> -Stacks and queues are implemented as adapters of a list -container. By default they use a Deque as the backing container. -Stacks define aliases <tt>push</tt> for <tt>add</tt> -and <tt>pop</tt> for <tt>takeTail</tt>. Queues define an alias -<tt>take</tt> for <tt>takeHead</tt> (the function <tt>add</tt> is used -to add to the end of a queue). For example, -<pre> - Stack!(char[]) x; - x.push("first","second"); - assert( x.pop == "second" ); - assert( x.pop == "first" ); - - Queue!(char[]) x; - x.add("first","second"); - assert( x.take == "first" ); - assert( x.take == "second" ); -</pre> -A <tt>PriorityQueue</tt> is an ArrayHeap wrapped with the Queue adapter. To -set a custom comparison function access the <tt>impl</tt> property of the -adapter: -<pre> - PriorityQueue!(char[]) x; - x.impl.compareFcn = &fcn; - x.add("first","second"); -</pre> -<p> -The following table outlines the advantages and disadvantages of -each list container -<table border="1"> -<tr> -<th>container <th> advantages <th> disadvantages </th> -</tr> -<tr> -<td> List -<td> O(1) insertion at head/tail or before/after slices -<td> O(n) access to middle of list -</td> -</tr> -<tr> -<td> SList -<td> O(1) insertion at head/tail or after slices; less overhead -than <tt>List</tt> -<td> O(n) access to middle or near end of list -</td> -</tr> -<tr> -<td> ArrayList -<td> O(1) insertion at head/tail. O(1) access to any index -<td> O(n) insertion in middle -</td> -</tr> -<tr> -<td> Deque -<td> O(1) insertion at head/tail. O(1) access to any index. -Block allocated. -<td> O(n) insertion in middle; non-contiguous storage -</td> -</tr> -<tr> -<td> ArrayHeap -<td> maintains items in semi-sorted order; O(log(n)) add/remove. -<td> only allows <tt>addTail</tt> and <tt>takeHead</tt> -</td> -</tr> -</table> - -<a name="Assoc"> -<h3> Associative Containers </h3> - -The associative containers <tt>SortedAA</tt>,<tt>HashAA</tt>, and -<tt>ConcurrentAA</tt> are similar to builtin associative arrays but -with extra capabilities. The <tt>SortedAA</tt> maintains the keys in -some specific order as determined by a comparison function. By -default the keys are ordered by the type's default comparison -function. To specify a custom comparison function assign to the -<tt>compareFcn</tt> property. The <tt>HashAA</tt> maintains the keys -in insertion order, meaning if an indexing expression using key -<tt>x</tt> is evaluated before an indexing expression using key -<tt>y</tt> then <tt>x</tt> is traversed before <tt>y</tt> in -<tt>foreach</tt> traversals. Assigning to a key already in the array -does not change the insertion order. The other associative array -properties <tt>dup</tt>, <tt>length</tt>, <tt>keys</tt> and -<tt>values</tt> are also implemented. - -<p> -Elements are inserted or modified using the <tt>add</tt> function or -using indexing lvalue expressions -and retrieved using indexing rvalue expressions. To test if a key is in -the array use the overloaded <tt>contains</tt> functions. -An indexing expression that is not an assignment will return a -default missing value. The missing value defaults to Value.init -but can be set by assigning to the <tt>missing</tt> property. -The functions <tt>get</tt> and <tt>put</tt> allow more flexibility in handling -missing keys by allowing the user to either return null, throw or -insert. -To remove an item call the <tt>remove</tt> function. Both <tt>HashAA</tt> -and <tt>SortedAA</tt> maintain a freelist of removed nodes for future -reuse. To release the freelist for garbage collection call <tt>trim</tt>. -<p> -For example to define a sorted associative -array with three entries associating "first" with 10, "second" with -20 and "third" with 30 type -<pre> - SortedAA!(int,char[]) x; - x.add(10,"first", 20,"second", 30,"third"); -</pre> -or equivalently, -<pre> - SortedAA!(int,char[]) x; - x[10] = "first"; - x[20] = "second"; - x[30] = "third"; -</pre> -To create an associative array in an expression use the static <tt>make</tt> function -For example, -<pre> - foo(SortedAA!(int,char[]).make(10,"first",20,"second",30,"third")); -</pre> - -<p> -The number of elements in an associative container is computed by -the <tt>length</tt> property. - -<p> -Sets and multi-associative-arrays are implemented as adapters of an -associative container. -By default sets use a HashAA as the backing container. -Use <tt>add</tt> -to add items to a set and use an indexing expression -to check if an item is in the set. For example, -<pre> - Set!(char[]) x; - x.add("first","second","third"); - assert( x["first"] ); - assert( x["second"] ); - assert( x["third"] ); - assert( !x["fourth"] ); - - MultiSet!(char[]) mx; - xm.add("first","second","first","third","second"); - xm.remove("first"); - assert( x["first"] ); - - MultiAA!(int,char[]) y; - y.add(10,"first",20,"second",10,"third"); - assert( y[10].length == 2 ); -</pre> - -<a name="Slicing"> -<h3> Slicing </h3> - -In general slicing a container behaves like slicing a dynamic -array. For example, slicing between two indices in a List creates -another List with the head at the first index and the tail at the -element before the second index. The contents of the slice is shared -with the original list so assigning new values to elements in the list -will be visible in the oringal list. The resulting slice, or -sub-list, can be traversed using "foreach", duplicated, indexed into, -etc just like a slice of a dynamic array can be treated as a -"first-class" dyamic array. The following diagram illustrates the -relationships for <tt>x</tt> and <tt>y</tt> if -<tt>x</tt> is a list with 6 items and -<tt>y</tt> is the slice <tt>x[2..4]</tt>.<br> - -<pre> - x[0] y[0] y[1] x[5] - 0 <-> 1 <-> 2 <-> 3 <-> 4 <-> 5 -</pre> -Executing <tt>z = y.dup</tt> would result in -<pre> - z[0] z[1] - 2 <-> 3 -</pre> -<p> -One should be careful when resizing or writing to a slice. For example -do not (in general) append or prepend item to a sub-list using the addTail or addHead -functions or remove items using removeTail and removeHead unless the -original list is no longer needed. To insert an item or list at a -certain location create a slice with the head at the desired location -and call <tt>addBefore</tt> or create a slice with the tail at the desired -location and call <tt>addAfter</tt>. To remove a portion of a list create a -slice and call <tt>remove</tt>. Again one should always insert and remove from -the original list otherwise any variable referring to the original list -will become out of sync. -<p> -A sub-list can be moved towards the head or tail -of the original list by calling the <tt>next</tt> function. -This allows a sub-list to traverse up and down the original list efficiently. -Continuing the example from above, executing <tt>y.next(-1)</tt> would result -in -<pre> - x[0] y[0] y[1] x[5] - 0 <-> 1 <-> 2 <-> 3 <-> 4 <-> 5 -</pre> -and then executing <tt>x.remove(y)</tt> would result in -<pre> - x[0] x[3] - 0 <-> 3 <-> 4 <-> 5 - - y[0] y[1] - 1 <-> 2 -</pre> -The performance of inserting and removing from the interior -of an ArrayList or Deque can be significantly worse than that of a List -if the slices are near the middle of the container. - -<p> -The SortedAA slicing behavior is designed to chose slices without modifying -the underlying container. The functions <tt>from</tt> and <tt>to</tt> -can find a one-item slice starting from or up to a given key. -For example if <tt>words</tt> is a sorted associative array indexed by -<tt>char[]</tt> then -<pre> - words["a" .. "b"] -</pre> -or, equivalently, -<pre> - words[words.from("a") .. words.to("b")] -</pre> -is a slice containing all the items with keys that start with the character "a" -even if the strings "a" and "b" aren't in the container. - -<a name="Foreach"> -<h3> Foreach </h3> -Containers and slices of containers can be traversal in -<tt>foreach</tt> statements -by value, key-value pairs and one-element slices. Some containers -support moving a slice up and down the container. For these containers -a slice can be used for the same purposes as an iterator in C++ or -Java. -<p> -Each container also supports backwards traversals by calling -<tt>backwards</tt> in a foreach statement. For example, -<pre> - List!(int) x; - ... - foreach( int val; x.backwards() ) - printf("%d ",val); -</pre> -will print out the contents of x from tail to head. -Backwards traversals do not allocate any dynamic memory. - -<a name="Sorting"> -<h3> Sorting </h3> -MinTL supports sorting containers in two forms. The <tt>SortedAA</tt> -is a sorted associative container that maintains its elements in a -given sorted order at all times. The comparison delegate -used to determine the element order must be specified -before the first element is insert or the key's default comparison -function will be used and it cannot be changed during the lifetime -of the container. The <tt>SortedSet</tt> -and <tt>SortedMultiAA</tt> are derived from <tt>SortedAA</tt> and -have the same sorting semantics. -<p> -The other form of sorting is through calling the <tt>sort</tt> -methods of the containers <tt>ArrayList</tt>, <tt>Deque</tt>, <tt>List</tt>, -and <tt>HashAA</tt> or by using the <tt>sort</tt> template in -<tt>mintl.array</tt> to sort a dynamic array. These sort methods -take an optional comparison delegate. The default comparison -delegate is the sorting type's default comparison function. For -the list-like containers the sorting type is the value type of -the container. For <tt>HashAA</tt> the sorting type is the key -type. Sorting is done in-place and slices are preserved relative -to their surrounding container. For example, the following code -creates a short linked list, sorts and slice and compares it -with the expected end result: -<pre> - List!(int) list; - list.add(40,300,-20,100,400,200); - list[1 .. 5].sort(); // sort a slice in-place - assert( list == List!(int).make(40,-20,100,300,400,200)); -</pre> -<p> -Sorting a container does not change the behavior of adding new elements. -The sorting operation is performed once and the comparison function -is not remembered by the container or used in any other way. For example -sorting a <tt>HashAA</tt> which was previously maintained in insertion -order will sort the elements but adding any new elements will add them -to the end of the traversal order in insertion order again. - -<a name="Allocators"> -<h3> Allocators </h3> -Most containers accept an optional <tt>Allocator</tt> parameter to -customize memory management. The default allocator is the -<tt>GCAllocator</tt> which indicates to the container that the garbage -collector should be used for all allocations. If a custom allocator -is supplied the container will call the memory management functions in -the allocator to allocate and free memory. Users who supply a -non-garbage-collecting allocator need to call <tt>clear</tt> when done -with a container so that the memory can be released. -<p> - -An allocator is a type containing 8 symbols malloc, calloc, realloc, -free and the corresponding GC-aware versions gcMalloc, gcCalloc, -gcRealloc and gcFree. Containers will call the GC-aware functions on -blocks that may hold roots and otherwise will call the regular -functions. Allocators are expected to throw an <tt>OutOfMemory</tt> -exception if the allocation fails. -<p> - -The two predefined allocators <tt>Malloc</tt> and <tt>MallocNoRoots</tt> use -std.c.stdlib.malloc to perform allocations. The MallocNoRoots ignores -any requests by the container to register roots with the GC. The -MallocNoRoots allocator should only be used with containers that the -user knows will never contain any roots. For example, -<pre> - ArrayList!(int,MallocNoRoots) x; - x.add(10,20,30); - ... - x.clear(); -</pre> - -<a name="unmod"></a> -<h3> Unmodifiable Containers </h3> -The <tt>ReadOnly</tt> template parameter makes a container -unmodifiable. A read-only container does not have operations that add or -remove or change elements. However the underlying data is shared with -the original modifiable container so a read-only container only -guarantees that the elements will not be modified by that particular -view of the container. -A slice of a read-only container is also read-only. -The <tt>readonly</tt> property creates a read-only view of a container. -The <tt>readwrite</tt> property creates a read-write view. -For example -<pre> - void foo(List!(int,ReadOnly) y) { ... } - List!(int) x; - x.add(10,20,30); - foo(x.readonly); -</pre> - -<a name="Examples"> -<h3> Examples </h3> -The source files have examples and unittests -that one can use to get a feel for the behavior. The following example -walks through some uses of MinTL: -Create a list of the integers 0 through 10 -<pre> - List!(int) x; - x.add(0,1,2,3,4,5,6,7,8,9,10); -</pre> -and print out the items 5 though 8 -<pre> - foreach(int val; x[5..9]) - printf("%d ",val); -</pre> -to output -<pre> - 5 6 7 8 -</pre> -Assigning <tt>x</tt> to another variable <tt>y</tt> shares -the underlying list contents, so assigning through <tt>y</tt> -is reflected in <tt>x</tt>: -<pre> - List!(int) y = x; - y[0] = 100; - assert( x[0] == 100 ); -</pre> -When passing a container to a function that could add or remove -elements from the container be sure to use "inout" parameters -to be sure the original variable in the calling frame is -properly updated. -<p> - -<a name="API"> -<h3> API Reference</h3> -This section lists the public structs and functions in MinTL without -detailed explanation. For more information see the documentation before -the function or struct in the source file. Template functions are -written as -<pre> return-type fcn-name!(tmpl-param,...)(arg1, arg2,...); -</pre> -to mimic how it would appear in user code. The API is organized by -module:<br> -<dl> -<dt><a href="#array">mintl.array</a> -<dt><a href="#arrayheap">mintl.arrayheap</a> -<dt><a href="#arraylist">mintl.arraylist</a> -<dt><a href="#deque">mintl.deque</a> -<dt><a href="#hashaa">mintl.hashaa</a> -<dt><a href="#list">mintl.list</a> -<dt><a href="#mem">mintl.mem</a> -<dt><a href="#multiaa">mintl.multiaa</a> -<dt><a href="#queue">mintl.queue</a> -<dt><a href="#set">mintl.set</a> -<dt><a href="#share">mintl.share</a> -<dt><a href="#slist">mintl.slist</a> -<dt><a href="#sortedaa">mintl.sortedaa</a> -<dt><a href="#stack">mintl.stack</a> -</dl> - -<a name="array"></a> -<h4>mintl.array</h4> -<dl> -<dt>void <b>reserve</b>!(Value[])(inout Value[] x, size_t n); -<dd>Reserve capacity for a dynamic array -<dt>DArrayReverseIter <b>backwards</b>!(Value[])(Value[] x); -<dd>Reverse dynamic array "foreach" traversal -<dt>void <b>sort</b>!(Value[])(Value[] data, int delegate(Value* x, Value* y) cmp = null); -<dd>Sort the array in increasing order as defined by the given comparison -delegate. If no delegate is supplied the default comparison function of the -Value type is used. -</dl> - -<a name="arrayheap"></a> -<h4>mintl.arrayheap</h4> -<dl> -<dt>struct <b>ArrayHeap</b>(Value, Alloc = GCAllocator) -<dd>A heap (complete binary tree) backed by an array. x[n] is greater than -or equal to x[2*n+1] and x[2*n+2]. x[0] is the greatest item. -An optional allocator can customize memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>Value[] <b>data</b>; -<dd>Backing array -<dt>size_t <b>length</b>; -<dd>Return length of heap -<dt>alias int delegate(Value* a, Value* b) <b>CompareFcn</b>; -<dd>Signature of comparison functions -<dt>void <b>compareFcn</b>(CompareFcn cmp); -<dd>Set the comparison function -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>Value[] <b>values</b>; -<dd>Get heap contents as dynamic array slice of backing array -<dt>void <b>add</b>(...); -<dd>Add to heap -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add to heap using va_arg inpurs -<dt>void <b>addTail</b>(Value v); -<dd>Add to heap -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item (greatest item) -<dt>void <b>removeHead</b>(); -<dd>Remove first item (greatest item) -<dt>Value* <b>lookup</b>(size_t n); -<dd>Return a pointer to the nth item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>ArrayHeap <b>dup</b>; -<dd>Duplicate array heap by duplicating backing array -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(ArrayHeap c); -<dd>Test heap equality -<dt>alias ArrayHeap <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="arraylist"></a> -<h4>mintl.arraylist</h4> -<dl> -<dt>struct <b>ArrayList</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A list backed by an array. An ArrayList can also be used as -a dynamic array with managed capacity. The backing array is resized -when more space is required. -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>Value[] <b>data</b>; -<dd>Backing array -<dt>mixin <b>MListCat</b>(ArrayList) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>mixin <b>MListAlgo</b>(this,ArrayList) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt><b>MListCommon</b>(ArrayList) -<dd>Implement common <a href="#listcomm">list members</a>. -<dt>size_t <b>length</b> -<dd>Read/write property to return or set the length of the list. -<dt>size_t <b>capacity</b> -<dd>Read/write property for the minimum capacity of the backing array. The -capacity is the maximum number of elements the array can hold without -requiring a reallocation of the backing array. -<dt>Value[] <b>array</b>; -<dd>Get list contents as dynamic array slice of the backing array assuming -the list is contiguous. -<dt>ArrayListReverseIter!(Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>ArrayList!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>ArrayList!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>void <b>sort</b>(int delegate(Value* x, Value* y) cmp = null); -<dd>Sort the list in increasing order as defined by the given comparison -delegate. If no delegate is supplied the default comparison function of the -Value type is used. -<dt>alias ArrayList <b>ContainerType</b>; -<dt>alias ArrayList <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="deque"></a> -<h4>mintl.deque</h4> -<dl> -<dt>struct <b>Deque</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A double-ended queue backed by a circular block-allocated array -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>mixin <b>MListCat</b>(Deque) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>mixin <b>MListAlgo</b>(this,Deque) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt><b>MListCommon</b>(Deque) -<dd>Implement common <a href="#listcomm">list members</a>. -<dt>size_t <b>length</b>; -<dd>Return length of deque. -<dt>DequeReverseIter!(Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>Deque!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>Deque!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>void <b>sort</b>(int delegate(Value* x, Value* y) cmp = null); -<dd>Sort the list in increasing order as defined by the given comparison -delegate. If no delegate is supplied the default comparison function of the -Value type is used. -<dt>alias Deque <b>ContainerType</b>; -<dt>alias Deque <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="hashaa"></a> -<h4>mintl.hashaa</h4> -<dl> -<dt>struct <b>HashAA</b>(Key,Value,bit ReadOnly = false, Alloc = GCAllocator) -<dd>An associative array linked by insertion order. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>void <b>add</b>(...); -<dd>Add key-value pairs to array -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static HashAA <b>make</b>(...) -<dd>Consruct a HashAA using add(...) -<dt>size_t <b>length</b>; -<dd>Return number of items in the array. -<dt>bool <b>isEmpty</b> -<dd>Return true if array is empty -<dt>Value* <b>get</b>(Key key, bit throwOnMiss = false); -<dd>Return a pointer to the value stored at the key. If the key is not -in the array then null is returned or if throwOnMiss is true an -exception is thrown. -<dt>Value* <b>put</b>(Key key) -<dd>Return a pointer to the value stored at the key and insert the -key with value Value.init if the key is not in the array. -<dt>bool <b>contains</b>(Key key) -<dd>Returns true if the array contains the key -<dt>bool <b>contains</b>(Key key, out Value value) -<dd>Returns true if the array contains the key and sets the out value if -present. -<dt>Value <b>opIndex</b>(Key key); -<dd>Return item with given key. Returns the default missing value if not present. -<dt>void <b>opIndexAssign</b>(Value val, Key key); -<dd>Assign a value to the given key -<dt>Value <b>missing</b> -<dd>Read/write property for the value to use on indexing a key not in -the array. Defaults to Value.init -<dt>HashAA <b>opSlice</b>(Key a, Key b); -<dd>Slice from item a to b (exclusive) -<dt>HashAA <b>opSlice</b>(HashAA a, HashAA b); -<dd>Slice from first key in a to last key in b -<dt>HashAA <b>head</b> -<dd>Return one-item slice of the head -<dt>HashAA <b>tail</b> -<dd>Return one-item slice of the tail -<dt>void <b>next</b>(int n = 1, int end = 0); -<dd>Move the head and tail to the next item. If n is negative move to -the previous item. If end <= 0 move the head of the slice and if -end >= 0 move the tail of the slice. -<dt>void <b>remove</b>(Key key); -<dd>Remove a key from array if present. The node used for key is reused in -future insert actions. -<dt>Value <b>take</b>(Key key); -<dd>Remove a key from array if present and return value. Returns the -default missing value if the key was not present. -<dt>void <b>remove</b>(HashAA subarray); -<dd>Remove a slice from array -<dt>Value[] <b>values</b>; -<dd>Get values as a dynamic array. The values are in insertion order. -<dt>Key[] <b>keys</b>; -<dd>Get keys as a dynamic array. The keys are in insertion order. -<dt>void <b>reserve</b>(size_t n); -<dd>Reserve a capacity for the array -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout Key key, inout Value x) dg); -<dd>Foreach traversal by key-value pairs -<dt>int <b>opApply</b>(int delegate(inout HashAA n) dg); -<dd>Foreach traversal by one-item slices -<dt>HashAA <b>dup</b>; -<dd>Duplicate array -<dt>void <b>clear</b>; -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>void <b>trim</b>; -<dd>Remove references to extra nodes kept for reuse -<dt>int <b>opEquals</b>(HashAA c); -<dd>Test array equality -<dt>HashAAReverseIter!(Key,Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>HashAA <b>rehash</b>; -<dd>Rehash array to be more efficient -<dt>Value <b>value</b> -<dd>Return value of a one-item slices -<dt>Key <b>key</b>; -<dd>Return key of a one-item slices -<dt>HashAA!(Key,Value,true) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>HashAA!(Key,Value,false) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>void <b>sort</b>(int delegate(Key* x, Key* y) cmp = null); -<dd>Sort the HashAA in increasing order as defined by the given comparison -delegate. If no delegate is supplied the default comparison function of the -Key type is used. Future insertions are added in insertion order at -the end of the traversal order. -<dt>alias HashAA <b>ContainerType</b>; -<dt>alias HashAA <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias Key <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> - -</dl> -<a name="list"></a> -<h4>mintl.list</h4> -<dl> -<dt>struct <b>List</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A doubly-linked list. -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>mixin <b>MListCat</b>(List) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>mixin <b>MListAlgo</b>(this,List) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt><b>MListCommon</b>(List) -<dd>Implement common <a href="#listcomm">list members</a>. -<dt>size_t <b>length</b>; -<dd>Return length of list. -<dt>void <b>trim</b>; -<dd>Remove references to extra nodes kept for reuse -<dt>ListReverseIter!(Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>List!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>List!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>void <b>sort</b>(int delegate(Value* x, Value* y) cmp = null); -<dd>Sort the list in increasing order as defined by the given comparison -delegate. If no delegate is supplied the default comparison function of the -Value type is used. -<dt>alias List <b>ContainerType</b>; -<dt>alias List <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> -<p> - -<a name="clist"></a> -<dl> -<dt>struct <b>CircularList</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A circular doubly-linked list. -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>mixin <b>MListCat</b>(CircularList) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>mixin <b>MListAlgo</b>(this,CircularList) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt><b>MListCommon</b>(CircularList) -<dd>Implement common <a href="#listcomm">list members</a>. -<dt>size_t <b>length</b>; -<dd>Return length of list. -<dt>List <b>toList</b>; -<dd>Return the list as a non-circular List -<dt>void <b>rotate</b>(int n = 1); -<dd>Rotate the list by n steps (backwards if n is negative) -<dt>CircularListReverseIter!(Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>CircularList!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>CircularList!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>alias CircularList <b>ContainerType</b>; -<dt>alias List!(Value,Alloc) <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="mem"></a> -<h4>mintl.mem</h4> -<dl> -<dt>void* <b>mallocWithCheck</b>(size_t s) -<dd>Call std.c.stdlib.malloc and throw OutOfMemory if fails. -<dt>void* <b>callocWithCheck</b>(size_t n, size_t s) -<dd>Call std.c.stdlib.calloc and throw OutOfMemory if fails. -<dt>void* <b>reallocWithCheck</b>(void* p, size_t s) -<dd>Call std.c.stdlib.realloc and throw OutOfMemory if fails. -<dt>void <b>dfree</b>(void* p) -<dd>Call free. -<dt>void* <b>gcMalloc</b>(size_t s) -<dd>Call mallocWithCheck and register range with GC. -<dt>void* <b>gcCalloc</b>(size_t n, size_t s) -<dd>Call callocWithCheck and register range with GC. -<dt>void* <b>gcRealloc</b>(void* p, size_t s) -<dd>Call reallocWithCheck and register range with GC. -<dt>void <b>gcFree</b>(void* p) -<dd>Remove range and call free. -<p> - -<a name="GCAlloc"> -<dt>struct <b>GCAllocator</b></a> -<dd>The default allocator that indicates the garbage collector -should be used for memory management. -<dt>struct <b>Malloc</b> -<dd>An allocator that uses malloc for memory requests and registers -blocks with the GC when requested by the container. -<dt>struct <b>MallocNoRoots</b> -<dd>An allocator that uses malloc for memory requests and ignores requests -to register blocks with the GC. Use this allocator only when you know the -container will not contain any roots. -</dl> -</dl> - -<a name="multiaa"></a> -<h4>mintl.multiaa</h4> -<dl> -<dt>struct <b>MultiAA</b>!(Key,Value, ImplType = HashAA!(Key,Value[])) -<dd>An associative array which allows keys to be repeated. -Adapted from a customizable container type mapping keys to Value[]. -<p> -<dl> -<dt>ImplType <b>impl</b> -<dd>Read-write property holding the backing container -<dt>void <b>add</b>(...); -<dd>Add key-value pairs to the container -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static MultiAA <b>make</b>(...) -<dd>Consruct a MultiAA using add(...) -<dt>void <b>addItem</b>(Key key, Value item); -<dd>Add item to container. -<dt>size_t <b>length</b>; -<dd>Return number of items in the container. -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty. -<dt>Value[] <b>opIndex</b>(Key key); -<dd>Return the values for a given key. -<dt>void <b>remove</b>(Key key, Value value); -<dd>Remove an item from the container if present. -<dt>void <b>remove</b>(Key key); -<dd>Remove all the values with a given key if present. -<dt>Key[] <b>keys</b>; -<dd>Get keys as a dynamic array. Duplicates are removed. -<dt>Value[][] <b>values</b>; -<dd>Get values as a dynamic array. -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal of items in the container. If an item is repeated it -is passed multiple times consecutively to the delegate. -<dt>int <b>opApply</b>(int delegate(inout Key key, inout Value x) dg); -<dd>Foreach traversal of items in the container. If an item is repeated it -is passed multiple times consecutively to the delegate. -<dt>MultiAA <b>dup</b>; -<dd>Duplicate container -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(MultiAA c); -<dd>Test container equality -<dt>alias MultiAA <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias Key <b>IndexType</b>; -<dt>alias ImplType <b>AdaptType</b>; -<dt>const bit <b>isReadOnly</b> = ImplType.isReadOnly; -<dd>Aliases for container types -</dl> -<p> -<a name="sortedmultiaa"></a> -<dt>alias <b>SortedMultiAA</b>!(Key,Value) -<dd>An alias for MultiAA!(Key,Value,SortedAA!(Key,Value[])) to implement a -sorted multi-aa. -</dl> - -<a name="queue"></a> -<h4>mintl.queue</h4> -<dl> -<dt>struct <b>Queue</b>!(Value, ImplType = Deque!(Value)) -<dd>A queue of items adapted from a customizable list container type. The -default backing container is a Deque. -<p> -<dl> -<dt>ImplType <b>impl</b> -<dd>Read-write property holding the backing container. -<dt>alias addTail <b>put</b>; -<dd>Alias to add items to the tail of the queue. -<dt>alias takeHead <b>take</b>; -<dd>Alias to take items to the head of the queue. -<dt>Value <b>peek</b> -<dd>Return the head of the queue or Value.init if empty. -<dt>mixin <b>MListCat</b>(Queue) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>size_t <b>length</b>; -<dd>Return length of queue. -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>void <b>addTail</b>(Value v); -<dd>Add to tail of queue -<dt>void <b>addTail</b>(Queue v); -<dd>Append v to tail of queue -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item -<dt>void <b>removeHead</b>(); -<dd>Remove first item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>Queue <b>dup</b>; -<dd>Duplicate queue. -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(Queue c); -<dd>Test queue equality -<dt>int <b>opCmp</b>(Queue c); -<dd>Compare queues -<dt>alias Queue <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ImplType <b>AdaptType</b>; -<dt>const bit <b>isReadOnly</b> = ImplType.isReadOnly; -<dd>Aliases for container types -</dl> -<p> -<a name="arrayqueue"></a> -<dt>alias <b>ArrayQueue</b>!(Value) -<dd>An alias for Queue!(Value,ArrayList!(Value)) to adapt an ArrayList -to the queue interface. -<p> -<a name="pqueue"></a> -<dt>alias <b>PriorityQueue</b>!(Value) -<dd>An alias for Queue!(Value,ArrayHeap!(Value)) to adapt an ArrayHeap -to the queue interface. - -</dl> - -<a name="set"></a> -<h4>mintl.set</h4> -<dl> -<dt>struct <b>Set</b>!(Value, ImplType = HashAA!(Value,uint)) -<dd>A set of unique items adapted from a customizable container type -mapping items to 0 or 1. The default backing container type is a -builtin associative array. -<p> -<dl> -<dt>ImplType <b>impl</b> -<dd>Read-write property holding the backing container -<dt>void <b>add</b>(...); -<dd>Add items to set -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static Set <b>make</b>(...) -<dd>Consruct a Set using add(...) -<dt>void <b>addItem</b>(Value item); -<dd>Add item to set -<dt>size_t <b>length</b>; -<dd>Return number of items in the set. -<dt>bool <b>isEmpty</b> -<dd>Return true if set is empty -<dt>bool <b>opIndex</b>(Value item); -<dd>Return true if the item is in the set -<dt>void <b>remove</b>(Value item); -<dd>Remove an item from the set if present -<dt>Value[] <b>values</b>; -<dd>Get items as a dynamic set. -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal of items in the set -<dt>Set <b>dup</b>; -<dd>Duplicate set -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(Set c); -<dd>Test set equality -<dt>alias Set <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias ImplType <b>AdaptType</b>; -<dt>const bit <b>isReadOnly</b> = ImplType.isReadOnly; -<dd>Aliases for container types -</dl> -<p> -<a name="sortedset"></a> -<dt>alias <b>SortedSet</b>!(Value) -<dd>An alias for Set!(Value,SortedAA!(Value,uint)) to implement a sorted set. -<p> -<a name="multiset"></a> -<dt>struct <b>MultiSet</b>!(Value, ImplType = HashAA!(uint,Value)) -<dd>A set which allows items to be repeated. Adapted from a customizable -container type mapping items to repeat counts. -<p> -<dl> -<dt>ImplType <b>impl</b> -<dd>Read-write property holding the backing container -<dt>void <b>add</b>(...); -<dd>Add items to set -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static MultiSet <b>make</b>(...) -<dd>Consruct a MultiSet using add(...) -<dt>void <b>addItem</b>(Value item); -<dd>Add item to set -<dt>size_t <b>length</b>; -<dd>Return number of items in the set. -<dt>bool <b>isEmpty</b> -<dd>Return true if set is empty -<dt>bool <b>opIndex</b>(Value item); -<dd>Return true if the item is in the set -<dt>void <b>remove</b>(Value item); -<dd>Remove an item from the set if present -<dt>Value[] <b>values</b>; -<dd>Get items as a dynamic set. Duplicates are removed. -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal of items in the set. If an item is repeated it -is passed multiple times consecutively to the delegate. -<dt>MultiSet <b>dup</b>; -<dd>Duplicate set -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(MultiSet c); -<dd>Test set equality -<dt>alias MultiSet <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias ImplType <b>AdaptType</b>; -<dt>const bit <b>isReadOnly</b> = ImplType.isReadOnly; -<dd>Aliases for container types -</dl> -<p> -<a name="sortedmultiset"></a> -<dt>alias <b>SortedMultiSet</b>!(Value) -<dd>An alias for MultiSet!(Value,SortedAA!(Value,uint)) to implement a -sorted multi-set. -</dl> - -<a name="share"></a> -<h4>mintl.share</h4> -The mintl.share module is publically imported into all container modules -and stores shared defintions. -<dl> -<dt>const bit <b>ReadOnly</b> = true; -<dd>A named constant to improve the readability of code involving read-only -containers. See the section on <a href="#unmod">unmodifiable containers</a> for examples. -<dt>class <b>IndexOutOfBoundsException</b> : Exception -<dd>Exception thrown when attempting to access an invalid index or key. Checks for invalid indices can be disabled using version=MinTLNoIndexChecking. - -<a name="listcat"> -<dt>template <b>MListCatOperators</b>(List)</a> -<dd>Concatenation routines to be mixed into the list-like containers -<dl> -<dt>void <b>add</b>(...); -<dd>Add to list -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static List <b>make</b>(...) -<dd>Consruct a List using add(...) -<dt>void <b>addN</b>(uint n, Value v) -<dd>Add the value n times to the list -<dt>void <b>addBefore</b>(List.SliceType sublist, Value[] v) -<dd>Insert the values in the dynamic array v before sublist -<dt>void <b>addAfter</b>(List.SliceType sublist, Value[] v) -<dd>Insert the values in the dynamic array v after sublist -<dt>List <b>opCatAssign</b>(Value v); -<dd>Concatenation operator this ~= v -<dt>List <b>opCat</b>(Value v); -<dd>Concatenation operator this ~ v. copies this -<dt>List <b>opCat_r</b>(Value v); -<dd>Concatenation operator v ~ this. copies this -<dt>List <b>opCatAssign</b>(List v); -<dd>Concatenation operator this ~= v. copies v -<dt>List <b>opCat</b>(List v); -<dd>Concatenation operator this ~ v. copies both arguments -</dl> -<a name="listalgo"> -<dt>template <b>MListAlgo</b>(Container, alias list)</a> -<dd>List algorithms to be mixed into the list-like containers -<dl> -<dt>Container.SliceType <b>opIn</b>(Value v); -<dd>Return a one-item slice of the first occurrence of v in the list. -<dt>Container.SliceType <b>find</b>(int delegate(inout Value v) dg); -<dd>Return a one-item slice of the first occurrence where dg is true. -<dt>uint <b>count</b>(Value v); -<dd>Return the number of time v appears in the list. -<dt>void <b>swap</b>(Container v); -<dd>Swap the contents of the list with v (assumes non-overlapping). Extra -elements are ignored. -<dt>void <b>fill</b>(Value v); -<dd>Fill the container with v -<dt>void <b>copy</b>(Container v); -<dd>Copy the contents of v to this container. Extra elements are ignored. -</dl> -<a name="listcomm"> -<dt><b>MListCommon</b>(Container)</a> -<dd>Common list routines -<dl> -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>Container.SliceType <b>opSlice</b>(size_t a, size_t b); -<dd>Slice from item a to b (exclusive) -<dt>Container.SliceType <b>opSlice</b>(Container.SliceType a, Container.SliceType b); -<dd>Slice from head of a to tail of b -<dt>Container.SliceType <b>head</b> -<dd>Read-only property to get a one-item slice of the head. -<dt>Container.SliceType <b>tail</b> -<dd>Read-only property to get a one-item slice of the tail. -<dt>Value[] <b>values</b>; -<dd>Get list contents as dynamic array. -<dt>Value <b>value</b>; -<dd>Read/write property for the value of a one-item slice. -<dt>void <b>addTail</b>(Value v); -<dd>Add to tail of list -<dt>void <b>addTail</b>(Container v); -<dd>Copy v to tail of list -<dt>void <b>addHead</b>(Value v); -<dd>Add to head of list -<dt>void <b>addHead</b>(Container v); -<dd>Copy v to head of list -<dt>Value <b>takeTail</b>(); -<dd>Remove and return last item -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item -<dt>void <b>removeTail</b>(); -<dd>Remove last item -<dt>void <b>removeHead</b>(); -<dd>Remove first item -<dt>void <b>remove</b>(Container.SliceType sublist); -<dd>Remove sublist from list -<dt>void <b>addBefore</b>(Container.SliceType subv, Container.SliceType v); -<dd>Insert v before subv. -<dt>void <b>addAfter</b>(Container.SliceType subv, Container.SliceType v); -<dd>Insert v after subv. -<dt>void <b>next</b>(int n = 1, int end = 0); -<dd>Move the head and tail to the next item. If n is negative move to -the previous item. If end <= 0 move the head of the slice and if -end >= 0 move the tail of the slice. -<dt>Value* <b>lookup</b>(size_t n); -<dd>Return a pointer to the nth item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>int <b>opApply</b>(int delegate(inout Container.SliceType n) dg); -<dd>Foreach traversal by one-item slices -<dt>Container <b>reverse</b>; -<dd>Reverse list in-place. -<dt>Container <b>dup</b>; -<dd>Duplicate array list by duplicating backing array -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(Container c); -<dd>Test list equality -<dt>int <b>opCmp</b>(Container c); -<dd>Compare lists -</dl> -</dl> - -<a name="slist"></a> -<h4>mintl.slist</h4> -<dl> -<dt>struct <b>SList</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A singly-linked list. -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>mixin <b>MListCat</b>(SList) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>size_t <b>length</b>; -<dd>Return length of list. -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>SList <b>tailList</b>; -<dd>Return the tail of the list as a slice -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>SList <b>opSlice</b>(size_t a, size_t b); -<dd>Slice from item a to b (exclusive) -<dt>SList <b>opSlice</b>(SList a, SList b); -<dd>Slice from head of a to tail of b -<dt>SList <b>head</b> -<dd>Read-only property to get a one-item slice of the head. -<dt>SList <b>tail</b> -<dd>Read-only property to get a one-item slice of the tail. -<dt>Value <b>value</b> -<dd>Read/write property for the value of a one-item slice. -<dt>Value[] <b>values</b>; -<dd>Get list contents as dynamic array. -<dt>void <b>addTail</b>(Value v); -<dd>Add to tail of list -<dt>void <b>addTail</b>(SList v); -<dd>Append v to tail of list -<dt>void <b>addHead</b>(Value v); -<dd>Add to head of list -<dt>void <b>addHead</b>(SList v); -<dd>Prepend v to head of list -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item -<dt>void <b>removeHead</b>(); -<dd>Remove first item -<dt>void <b>addAfter</b>(SList subv, SList v); -<dd>Insert v after subv. -<dt>void <b>removeAfter</b>(SList sublist, size_t n=1); -<dd>Remove n items following sublist -<dt>void <b>removeBetween</b>(SList a, SList b); -<dd>Remove items after the tail of a to the head of b (exclusive) -<dt>void <b>next</b>(int n = 1, int end = 0); -<dd>Move the head and tail to the next item. If n is negative move to -the previous item. If end <= 0 move the head of the slice and if -end >= 0 move the tail of the slice. -<dt>Value* <b>lookup</b>(size_t n); -<dd>Return a pointer to the nth item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>int <b>opApply</b>(int delegate(inout SList n) dg); -<dd>Foreach traversal by one-item slices -<dt>SList <b>dup</b>; -<dd>Duplicate list -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>void <b>trim</b>; -<dd>Remove references to extra nodes kept for reuse -<dt>int <b>opEquals</b>(SList c); -<dd>Test list equality -<dt>int <b>opCmp</b>(SList c); -<dd>Compare lists -<dt>mixin <b>MListAlgo</b>(this,SList) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt>SList!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>SList!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>alias SList <b>ContainerType</b>; -<dt>alias SList <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> -<p> -<a name="cslist"></a> -<dl> -<dt>struct <b>CircularSList</b>(Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A circular singly-linked list. -Compile with version=MinTLNoIndexChecking to disable bounds checking. -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>mixin <b>MListCat</b>(CircularSList) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>size_t <b>length</b>; -<dd>Return length of list. -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>SList <b>toSList</b>; -<dd>Return the list as a non-circular SList -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>SList <b>opSlice</b>(size_t a, size_t b); -<dd>Slice from item a to b (exclusive) -<dt>SList <b>opSlice</b>(SList a, SList b); -<dd>Slice from head of a to tail of b -<dt>SList <b>head</b> -<dd>Read-only property to get a one-item slice of the head. -<dt>SList <b>tail</b> -<dd>Read-only property to get a one-item slice of the tail. -<dt>Value <b>value</b> -<dd>Read/write property for the value of a one-item slice. -<dt>void <b>addTail</b>(Value v); -<dd>Add to tail of list -<dt>void <b>addTail</b>(CircularSList v); -<dd>Append v to tail of list -<dt>void <b>addHead</b>(Value v); -<dd>Add to head of list -<dt>void <b>addHead</b>(CircularSList v); -<dd>Prepend v to head of list -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item -<dt>void <b>removeHead</b>(); -<dd>Remove first item -<dt>void <b>addAfter</b>(SList subv, SList v); -<dd>Insert v after subv. -<dt>void <b>removeAfter</b>(SList sublist, size_t n=1); -<dd>Remove n items following sublist -<dt>void <b>removeBetween</b>(SList a, SList b); -<dd>Remove items after the tail of a to the head of b (exclusive) -<dt>void <b>rotate</b>(int n = 1); -<dd>Rotate the list by n steps -<dt>Value* <b>lookup</b>(size_t n); -<dd>Return a pointer to the nth item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>int <b>opApply</b>(int delegate(inout SList n) dg); -<dd>Foreach traversal by one-item slices -<dt>CircularSList <b>dup</b>; -<dd>Duplicate list -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(CircularSList c); -<dd>Test list equality -<dt>int <b>opCmp</b>(CircularSList c); -<dd>Compare lists -<dt>mixin <b>MListAlgo</b>(this,CircularSList) -<dd>Mixin <a href="#listalgo">list algorithms</a>. -<dt>CircularSList!(Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>CircularSList!(Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>alias CircularAList <b>ContainerType</b>; -<dt>alias SList!(Value,Alloc) <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ReadOnly <b>isReadOnly</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="sortedaa"></a> -<h4>mintl.sortedaa</h4> -<dl> -<dt>class <b>CompareFcnSetException</b>: Exception; -<dd>Exception thrown when trying to set the comparison function of -a non-empty array or an array that already had the comparison function -set. -</dl> -<p> -<dl> -<dt>struct <b>SortedAA</b>(Key, Value, bit ReadOnly = false, Alloc = GCAllocator) -<dd>A sorted associative array -The optional ReadOnly parameter disallows container modifications. -The optional allocator customizes memory management. The default allocator -is <a href="#GCAlloc">GCAllocator</a>. -<p> -<dl> -<dt>alias int delegate(Key* a, Key* b) <b>CompareFcn</b>; -<dd>Signature of comparison functions -<dt>void <b>compareFcn</b>(CompareFcn cmp); -<dd>Set the comparison function -<dt>void <b>add</b>(...); -<dd>Add key-value pairs to array -<dt>void <b>vadd</b>(TypeInfo[] ti, void* argptr); -<dd>Add using va_arg inpurs -<dt>static SortedAA <b>make</b>(...) -<dd>Consruct a SortedAA using add(...) -<dt>size_t <b>length</b>; -<dd>Return number of items in the array. -<dt>bool <b>isEmpty</b> -<dd>Return true if array is empty -<dt>Value* <b>get</b>(Key key, bit throwOnMiss = false); -<dd>Return a pointer to the value stored at the key. If the key is not -in the array then null is returned or if throwOnMiss is true an -exception is thrown. -<dt>Value* <b>put</b>(Key key) -<dd>Return a pointer to the value stored at the key and insert the -key with value Value.init if the key is not in the array. -<dt>bool <b>contains</b>(Key key) -<dd>Returns true if the array contains the key -<dt>bool <b>contains</b>(Key key, out Value value) -<dd>Returns true if the array contains the key and sets the out value if -present. -<dt>Value <b>opIndex</b>(Key key); -<dd>Return item with given key. Returns the default missing value if not present. -<dt>void <b>opIndexAssign</b>(Value val, Key key); -<dd>Assign a value to the given key -<dt>Value <b>missing</b> -<dd>Read/write property for the value to use on indexing a key not in -the array. Defaults to Value.init -<dt>SortedAA <b>head</b>() -<dd>Return one-item slice of the smallest item -<dt>SortedAA <b>tail</b>() -<dd>Return one-item slice of the greatest item -<dt>void <b>next</b>(int n = 1, int end = 0); -<dd>Move the head and tail to the next item. If n is negative move to -the previous item. If end <= 0 move the head of the slice and if -end >= 0 move the tail of the slice. -<dt>SortedAA <b>from</b>(Key a); -<dd>Return a one-item slice of the smallest item greater than or equal to a. -<dt>SortedAA <b>to</b>(Key b); -<dd>Return a one-item slice of the greatest item smaller than b. -<dt>SortedAA <b>opSlice</b>(Key a, Key b); -<dd>Slice from item a to b (exclusive). -<dt>SortedAA <b>opSlice</b>(SortedAA a, SortedAA b); -<dd>Slice from first key in a to last key in b. -<dt>Value <b>take</b>(Key key); -<dd>Remove a key from array if present and return value. Returns the -default missing value if the key was not present. -<dt>void <b>remove</b>(Key key); -<dd>Remove a key from array if present. -<dt>void <b>remove</b>(SortedAA subarray); -<dd>Remove a slice from array. -<dt>void <b>trim</b>; -<dd>Remove references to extra nodes kept for reuse -<dt>Value[] <b>values</b>; -<dd>Get values as a dynamic array. The values are in order. -<dt>Key[] <b>keys</b>; -<dd>Get keys as a dynamic array. The keys are in order. -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout Key key, inout Value x) dg); -<dd>Foreach traversal by key-value pairs -<dt>int <b>opApply</b>(int delegate(inout SortedAA n) dg); -<dd>Foreach traversal by one-item slices -<dt>SortedAA <b>dup</b>; -<dd>Duplicate array -<dt>void <b>clear</b>() -<dd>Clear contents. Only needed if a non-GCAllocator is used. -<dt>int <b>opEquals</b>(SortedAA c); -<dd>Test array equality -<dt>SortedAAReverseIter!(Key,Value) <b>backwards</b>(); -<dd>Backwards traversal for "foreach" -<dt>Value <b>value</b>; -<dd>Return value of a one-item slices -<dt>Key <b>key</b>; -<dd>Return key of a one-item slices -<dt>SortedAA!(Key,Value,true,Alloc) <b>readonly</b>; -<dd>Property that returns a read-only view of the container. -<dt>SortedAA!(Key,Value,false,Alloc) <b>readwrite</b>; -<dd>Property that returns a read-write view of the container. -<dt>alias SortedAA <b>ContainerType</b>; -<dt>alias SortedAA <b>SliceType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias Key <b>IndexType</b>; -<dd>Aliases for container types -</dl> -</dl> - -<a name="stack"></a> -<h4>mintl.stack</h4> -<dl> -<dt>struct <b>Stack</b>!(Value, ImplType = Deque!(Value)) -<dd>A stack of items adapted from a customizable list container type. The -default backing container is a Deque. -<p> -<dl> -<dt>ImplType <b>impl</b> -<dd>Read-write property holding the backing container. -<dt>alias addTail <b>push</b>; -<dd>Alias to add items to the tail of the stack. -<dt>alias takeTail <b>pop</b>; -<dd>Alias to take items from the tail of the stack. -<dt>Value <b>peek</b> -<dd>Return the top of the stack or Value.init if empty. -<dt>mixin <b>MListCat</b>(Stack) -<dd>Mixin <a href="#listcat">list catenation</a>. -<dt>size_t <b>length</b>; -<dd>Return length of stack. -<dt>bool <b>isEmpty</b> -<dd>Return true if container is empty -<dt>Value <b>opIndex</b>(size_t n); -<dd>Return nth item where the head is item 0. -<dt>void <b>opIndexAssign</b>(Value val, size_t n); -<dd>Assign to the nth item -<dt>void <b>addTail</b>(Value v); -<dd>Add to tail of stack -<dt>void <b>addTail</b>(Stack v); -<dd>Append v to tail of stack -<dt>Value <b>takeHead</b>(); -<dd>Remove and return first item -<dt>void <b>removeHead</b>(); -<dd>Remove first item -<dt>int <b>opApply</b>(int delegate(inout Value x) dg); -<dd>Foreach traversal by values -<dt>int <b>opApply</b>(int delegate(inout size_t n, inout Value x) dg); -<dd>Foreach traversal by index-value pairs -<dt>Stack <b>dup</b>; -<dd>Duplicate stack. -<dt>int <b>opEquals</b>(Stack c); -<dd>Test stack equality -<dt>int <b>opCmp</b>(Stack c); -<dd>Compare stacks -<dt>alias Stack <b>ContainerType</b>; -<dt>alias Value <b>ValueType</b>; -<dt>alias size_t <b>IndexType</b>; -<dt>alias ImplType <b>AdaptType</b>; -<dt>const bit <b>isReadOnly</b> = ImplType.isReadOnly; -<dd>Aliases for container types -</dl> -<p> -<a name="arraystack"></a> -<dt>alias <b>ArrayStack</b>!(Value) -<dd>An alias for Stack!(Value,ArrayList!(Value)) to adapt an ArrayList -to the stack interface. -</dl> - -</BODY> -</HTML>
--- a/trunk/mintl/linux.mak Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ - -# To build libmintl.a type -# make -f linux.mak DFLAGS=-g LIBNAME=libmintl_debug.a -# or -# make -f linux.mak DFLAGS=-release LIBNAME=libmintl.a -# The libmintl.a and object files will be created in the source directory. - -# flags to use building unittest.exe -DUNITFLAGS=-g -unittest -I.. -version=MinTLUnittest -version=MinTLVerboseUnittest - -# flags to use when building the mintl.lib library -DLIBFLAGS=$(DFLAGS) -I.. -#DLIBFLAGS=-g -I.. - -DMD=dmd - -#LIBNAME = libmintl.a - -targets : unittest - -mintl : $(LIBNAME) - -SRC = all.d \ - array.d \ - arraylist.d \ - arrayheap.d \ - deque.d \ - hashaa.d \ - list.d \ - slist.d \ - share.d \ - adapter.d \ - stack.d \ - queue.d \ - set.d \ - multiaa.d \ - mem.d \ - sorting.d \ - sortedaa.d - -OBJS = all.o \ - array.o \ - arraylist.o \ - arrayheap.o \ - deque.o \ - hashaa.o \ - list.o \ - slist.o \ - share.o \ - adapter.o \ - stack.o \ - queue.o \ - set.o \ - multiaa.o \ - mem.o \ - sorting.o \ - sortedaa.o - -$(LIBNAME) : $(OBJS) $(SRC) - ar -r $@ $(OBJS) - -clean: - rm *.o - rm $(LIBNAME) - rm unittest - -%.o : %.d - $(DMD) -c $(DLIBFLAGS) $< -of$@ - -unittest : $(LIBNAME) $(OBJS) $(SRC) - $(DMD) $(DUNITFLAGS) unittest.d -ofunittest $(SRC) -
--- a/trunk/mintl/list.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1420 +0,0 @@ -/** \file list.d - * \brief A doubly-linked list and a circular doubly-linked list. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.list; - -private import mintl.share; // for ~ and ~= -private import mintl.sorting; -import mintl.mem; - -// shared data structure between List and CircularList -private struct DNode(Value) { - DNode* next, prev; - Value data; - Value* sortLookup(){return &data;} -} - -/** Template for member functions common to List and CircularList */ -template MCommonList(alias tail_, Container ) { - - /** Test if a container is empty. */ - bool isEmpty() { - return head_ is null; - } - - /** Get the length of list. The computation can be O(n) but the - * result is cached and the actively updated until another list - * of unknown length is concatenated or removed. - */ - size_t length() { - if (length_ == 0 && head_) { - Container.Node* n = head_; - length_ = 1; - Container.Node* end = tail_; - while (n !is end) { - length_++; - n = n.next; - } - } - return length_; - } - - // helper function to check if the index is legal - void boundsCheck(size_t n) { - version (MinTLNoIndexChecking) { - } else { - if (!(n == 0 && this.head_) && - (n >= length_ && n >= this.length)) { - throw new IndexOutOfBoundsException(); - } - } - } - - // Internal function to get the nth item of the list. - package Container.Node* getNode(size_t n) { - boundsCheck(n); - Container.Node* v; - if (n <= length_/2) { - v = head_; - while (n--) { - v = v.next; - } - } else { - n = length_-n-1; - v = tail_; - while (n--) { - v = v.prev; - } - } - return v; - } - - /** Get the nth item in the list from head. The operation is O(N(n)) - * where N(x) is the distance from x to either end of list. - * Indexing out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Container.ValueType opIndex(size_t n) { - return getNode(n).data; - } - - static if (!Container.isReadOnly) { - - /** Get a pointer to the nth item in the list from head. The - * operation is O(N(n)) where N(x) is the distance from x to either - * end of list. Indexing out of bounds throws an - * IndexOutOfBoundsException unless version=MinTLNoIndexChecking is - * set. - */ - Container.ValueType* lookup(size_t n) { - return &getNode(n).data; - } - - /** Set the nth item in the list from head. The operation is O(N(n)) - * where N(x) is the distance from x to either end of list. - * Indexing out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - void opIndexAssign(Container.ValueType val, size_t n) { - getNode(n).data = val; - } - - /** Reverse a list in-place. The operation is O(n) where n is - * length of the list. - */ - Container reverse() { - if (this.isEmpty) - return *this; - Node* i = head_; - Node* j = tail_; - TypeInfo ti = typeid(Container.ValueType); - while (i !is j && i.next !is j) { - ti.swap(&i.data,&j.data); - i = i.next; - j = j.prev; - } - ti.swap(&i.data,&j.data); - return *this; - } - - } // !isReadOnly - - /** Copies the list contents to an array */ - Container.ValueType[] values() { - Container.ValueType[] buffer = new Container.ValueType[this.length]; - foreach(size_t n, Container.ValueType val; *this) { - buffer[n] = val; - } - return buffer; - } - - /** Test for equality of two lists. The operation is O(n) where n - * is length of the list. - */ - int opEquals(Container c) { - if (length_ && c.length_ && length_ != c.length_) - return 0; - Container.Node* i = head_; - Container.Node* j = c.head_; - Container.Node* t = tail_; - Container.Node* ct = c.tail_; - TypeInfo ti = typeid(Container.ValueType); - while (i !is null && j !is null) { - if (!ti.equals(&i.data,&j.data)) - return 0; - if (i !is t && j !is ct) - return 1; - i = i.next; - j = j.next; - } - return (i is null && j is null); - } - - /** Compare two lists. */ - int opCmp(Container c) { - Container.Node* i = head_; - Container.Node* j = c.head_; - Container.Node* t = tail_; - Container.Node* ct = c.tail_; - TypeInfo ti = typeid(Container.ValueType); - while (i !is null && j !is null) { - int cmp = ti.compare(&i.data,&j.data); - if (cmp) - return cmp; - if (i !is t && j !is ct) - return 0; - i = i.next; - j = j.next; - } - if (i is null && j is null) - return 0; - else - return (i is null) ? -1 : 1; - } - - /** Create a sub-list from index a to b (exclusive). The operation is - * O(max(N(a),N(b))) where N(x) is distance from x to either end of - * the target list. - */ - Container.SliceType opSlice(size_t a, size_t b) { - Container.SliceType res; - res.length_ = b-a; - if (res.length_ > 0) { - res.head_ = getNode(a); - if (this.length_ - b > b-a){ - Container.Node* v = res.head_; - b = b-a-1; - while (b--) - v = v.next; - res.tail_ = v; - } else { - res.tail_ = getNode(b-1); - } - } - return res; - } - - /** Create a sub-list from the head of a to the tail of b (inclusive). */ - Container.SliceType opSlice(Container.SliceType a, Container.SliceType b) { - if (a.isEmpty) - return b; - if (b.isEmpty) - return a; - Container.SliceType res; - Container.Node* i = a.head_; - res.head_ = i; - res.tail_ = b.tail_; - res.length_ = 0; // flag indicating unknown length - return res; - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The value is passed to the delegate. - */ - int opApplyNoKeyStep(int delegate(inout Container.ValueType x) dg, int step = 1){ - int dg2(inout size_t count, inout Container.ValueType val) { - return dg(val); - } - return opApplyWithKeyStep(&dg2,step); - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The index from 0 and the value are passed - * to the delegate. - */ - int opApplyWithKeyStep(int delegate(inout size_t n, inout Container.ValueType x) dg, - int step = 1){ - Container.Node* i = step>0 ? head_ : tail_; - Container.Node* end = step>0 ? tail_ : head_; - int res = 0; - size_t n = step>0 ? 0 : this.length-1; - while (i !is null) { - res = dg(n, i.data); - if (res || i is end) break; - n += step; - i = step>0 ? i.next : i.prev; - } - return res; - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. A one-item sub-list is passed to the delegate. - */ - int opApplyIterStep(int delegate(inout Container.SliceType n) dg, int step = 1){ - Container.Node* i = step>0 ? head_ : tail_; - Container.Node* end = step>0 ? tail_ : head_; - int res = 0; - Container.SliceType n; - n.length_ = 1; - while (i !is null) { - n.head_ = n.tail_ = i; - res = dg(n); - if (res || i is end) break; - i = step>0 ? i.next : i.prev; - } - return res; - } - -} - -/** \class List - * \brief A doubly-linked list. - * - * A List!(Value) is a linked list of data of type Value. A list is - * similar to a dynamic array except accessing an element in the - * middle of the list is O(n) and appending to the front or back is - * O(1). Any operation that is not constant-time will explicitly have - * the performance behavior documented. - * - * The optional ReadOnly parameter List!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter List!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct List(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias List ContainerType; - alias List SliceType; - alias Value ValueType; - alias size_t IndexType; - alias Value SortType; - alias DNode!(Value) Node; - alias ReadOnly isReadOnly; - - const int NodeAllocationBlockSize = 10; // allocate 10 nodes at a time - - /* length 0 means length is unknown. An empty list is indicated by - * a null head. The tail can be non-null in order to maintain the - * cached nodes. - */ - invariant { - assert( length_ == 0 || head_ !is null ); - } - - // private bug private { - size_t length_; - Node* head_; - Node* tail_; - // } - - /** Get a ReadOnly view of the container */ - .List!(Value, true, Alloc) readonly() { - .List!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .List!(Value, false, Alloc) readwrite() { - .List!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (!ReadOnly) { - - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. - */ - void addTail(Value v) { - if (head_ is null && tail_ !is null) { - // empty list but with cache available - head_ = tail_; - tail_.data = v; - length_ = 1; - } else if (tail_ is null || tail_.next is null) { - if (head_ is null || head_.prev is null) { - // no available nodes so allocate a new one - List val; - val.head_ = val.tail_ = newNode(); - val.length_ = 1; - val.head_.data = v; - addTail(val); - } else { - // grab available node from front - Node* t = head_.prev; - if (t.prev !is null) t.prev.next = head_; - head_.prev = t.prev; - t.prev = tail_; - t.next = null; - tail_.next = t; - tail_ = t; - tail_.data = v; - if (length_) length_++; - } - } else { - // grab available node from end - tail_.next.prev = tail_; - tail_ = tail_.next; - tail_.data = v; - if (length_) length_++; - } - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. - */ - void addTail(List v) { - if (v.isEmpty) - return; - if (tail_ !is null) - tail_.next = v.head_; - v.head_.prev = tail_; - if (this.isEmpty) - length_ = v.length_; - else - length_ = increaseLength(length_, v.length_); - tail_ = v.tail_; - if (head_ is null) - head_ = v.head_; - } - - mixin MListCatOperators!(List); - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - trim(); - Node* i = head_; - while (i !is null) { - Node* next = i.next; - Alloc.gcFree(i); - i = next; - } - } - *this = List.init; - } - - /** Set the value of one-item slice (more generally the head value). */ - void value(Value newValue) { - head_.data = newValue; - } - - // Helper function for take and remove - private Node* takeTailHelper() { - if (this.isEmpty) - throw new IndexOutOfBoundsException(); - Node* v = tail_; - if (head_ && head_ is tail_) { - head_ = null; - } else { - tail_ = tail_.prev; - } - return v; - } - - /** Removes and returns the tail item of the list. The node that - * contained the item may be reused in future additions to the - * list. To prevent the node from being reused call <tt>trim</tt> or - * call <tt>remove</tt> with a sublist containing the last item. If - * the target list is empty an IndexOutOfBoundsException is thrown - * unless version=MinTLNoIndexChecking is set. - */ - Value takeTail() { - Node* v = takeTailHelper(); - Value data = v.data; - v.data = Value.init; - if (length_) length_--; - return data; - } - - /** Removes the tail item of the list. */ - void removeTail() { - Node* v = takeTailHelper(); - v.data = Value.init; - if (length_) length_--; - } - - /** Prepends an item to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert an - * item before a sub-list. - */ - void addHead(Value v) { - if (head_ is null && tail_ !is null) { - // empty list but with cache available - head_ = tail_; - tail_.data = v; - length_ = 1; - } else if (head_ is null || head_.prev is null) { - if (tail_ is null || tail_.next is null) { - // no available nodes so allocate a new one - List val; - val.head_ = val.tail_ = newNode(); - val.length_ = 1; - val.head_.data = v; - addHead(val); - } else { - // grab available node from end - Node* t = tail_.next; - if (t.next !is null) t.next.prev = tail_; - tail_.next = t.next; - t.next = head_; - t.prev = null; - head_.prev = t; - head_ = t; - head_.data = v; - if (length_) length_++; - } - } else { - // grab available node from front - head_.prev.next = head_; - head_ = head_.prev; - head_.data = v; - if (length_) length_++; - } - } - - /** Prepends a list to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert a - * list before a sub-list. - */ - void addHead(List v) { - if (v.isEmpty) - return; - if (head_ !is null) - head_.prev = v.tail_; - v.tail_.next = head_; - if (this.isEmpty) - length_ = v.length_; - else - length_ = increaseLength(length_, v.length_); - head_ = v.head_; - if (tail_ is null) - tail_ = v.tail_; - } - - // Helper function for take and remove - private Node* takeHeadHelper() { - if (this.isEmpty) - throw new IndexOutOfBoundsException(); - Node* v = head_; - if (head_ && head_ is tail_) { - head_ = null; - } else { - head_ = head_.next; - } - return v; - } - - /** Removes and returns the head item of the list. The node that - * contained the item may be reused in future additions to the - * list. If the target list is empty an IndexOutOfBoundsException is - * thrown unless version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - Node* v = takeHeadHelper(); - Value data = v.data; - v.data = Value.init; - if (length_) length_--; - return data; - } - - /** Removes the head item of the list. */ - void removeHead() { - Node* v = takeHeadHelper(); - v.data = Value.init; - if (length_) length_--; - } - - /** Insert a list before a sub-list. */ - void addBefore(List subv, List v) { - if (v.isEmpty) - return; - if (subv.isEmpty) - throw new IndexOutOfBoundsException(); - Node* t = subv.head_; - if (t.prev !is null) { - t.prev.next = v.head_; - } - v.head_.prev = t.prev; - v.tail_.next = t; - t.prev = v.tail_; - if (t is head_) - head_ = v.head_; - length_ = increaseLength(length_, v.length_); - } - - /** Insert a list after a sub-list. */ - void addAfter(List subv, List v) { - if (v.isEmpty) - return; - if (subv.isEmpty) - throw new IndexOutOfBoundsException(); - Node* t = subv.tail_; - if (t.next !is null) { - t.next.prev = v.tail_; - } - v.tail_.next = t.next; - v.head_.prev = t; - t.next = v.head_; - if (t is tail_) - tail_ = v.tail_; - length_ = increaseLength(length_, v.length_); - } - - - /** Removes a sub-list from the list entirely. */ - void remove(List sublist) { - if (sublist.isEmpty) - return; - Node* h = sublist.head_; - Node* t = sublist.tail_; - if (h is head_ && t is tail_) { - head_ = tail_ = null; - length_ = 0; - return; - } - Node* hp = h.prev; - Node* tn = t.next; - if (hp !is null) - hp.next = tn; - if (tn !is null) - tn.prev = hp; - if (h is head_) - head_ = tn; - if (t is tail_) - tail_ = hp; - length_ = decreaseLength(length_, sublist.length_); - } - - /** Removes an item from the list if present. */ - void remove(size_t index) { - List item = opSlice(index, index+1); - remove(item); - } - - /** Removes an item and return the value if any. */ - Value take(size_t index) { - List item = opSlice(index, index+1); - remove(item); - Value val = item[0]; - item.clear(); - return val; - } - - /** Trims off extra nodes that are not actively being used by the - * list but are available for recyling for future add operations. - * This function should be called after calling <tt>remove</tt> and - * there are other list or pointer references to the removed item. - */ - void trim() { - if (!this.isEmpty) { - Node* i; - if (tail_.next) { - i = tail_.next; - i.prev = null; - tail_.next = null; - static if (is(Alloc == GCAllocator)) { - } else { - while (i !is null) { - Node* next = i.next; - Alloc.gcFree(i); - i = next; - } - } - } - if (head_.prev) { - i = head_.prev; - i.next = null; - head_.prev = null; - static if (is(Alloc == GCAllocator)) { - } else { - while (i !is null) { - Node* prev = i.prev; - Alloc.gcFree(i); - i = prev; - } - } - } - } - } - - } // !ReadOnly - - /** Duplicates a list. The operation is O(n) where n is length of - * the list. - */ - List dup() { - .List!(Value,false,Alloc) res; - foreach(ValueType val; *this) { - res ~= val; - } - static if (ReadOnly) { - return res.readonly; - } else { - return res; - } - } - - /** Move a sub-list towards the head or tail by n items. If n is - * negative the sub-list moves towards the head. A positive end is - * the tail, negative the head and 0 is both. By default moves to - * the next item. - */ - void next(int n = 1, int end = 0) { - if (length_) - length_ -= n*end; - while (n-- > 0) { - if (end <= 0) - head_ = head_.next; - if (end >= 0) - tail_ = tail_.next; - } - while (++n < 0) { - if (end <= 0) - head_ = head_.prev; - if (end >= 0) - tail_ = tail_.prev; - } - } - - /** Get the length of list. The computation can be O(n) but the - * result is cached and the actively updated until another list - * of unknown length is concatenated. - */ - size_t length() { - if (length_ == 0 && !this.isEmpty) { - Node* n = head_; - length_ = 1; - while (n !is tail_) { - length_++; - n = n.next; - } - } - return length_; - } - - /** Create a one-item slice of the head. */ - List head() { - List res; - res.length_ = head_? 1 : 0; - res.head_ = res.tail_ = head_; - return res; - } - - /** Create a one-item slice of the tail. */ - List tail() { - List res; - res.length_ = tail_? 1 : 0; - res.head_ = res.tail_ = tail_; - return res; - } - - /** Get the value of one-item slice (more generally the head value). - * Useful for expressions like x.tail.value or x.head.value. */ - Value value() { - return head_.data; - } - - /** Iterate backwards over the list (from tail to head). This - * should be called as the iteration parameter in a - * <tt>foreach</tt> statement - */ - ListReverseIter!(Value,ReadOnly,Alloc) backwards() { - ListReverseIter!(Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** Helper functions for opApply */ - mixin MOpApplyImpl!(ContainerType); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - private Node* newNode() { - static if (is(Alloc == GCAllocator)) { - // allocate a block of nodes and return pointer to first one - Node[] block = new Node[NodeAllocationBlockSize]; - for (int k=1; k<NodeAllocationBlockSize; k++) { - block[k-1].next = &block[k]; - } - return &block[0]; - } else { - // can only allocate one at a time because we have to track each - Node* p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - *p = Node.init; - return p; - } - } - - List getThis(){return *this;} - mixin MListAlgo!(List, getThis); - Node* getHead(){return head_;} - Node* getTail(){return tail_;} - mixin MSequentialSort!(List, getHead,getTail); - void sort(int delegate(Value*a, Value*b) cmp = null) { - Node* newhead, newtail; - dosort(newhead,newtail,cmp); - head_ = newhead; - tail_ = newtail; - } - mixin MCommonList!(tail_, List ); - void privateMake(Node* h, Node* t, size_t len) { - head_ = h; - tail_ = t; - length_ = len; - } -} - -// helper structure for backwards() -struct ListReverseIter(Value,bit ReadOnly,Alloc) { - mixin MReverseImpl!(List!(Value,ReadOnly,Alloc)); -} - -/** \class CircularList - * \brief A circular doubly-linked list. - * - * A CircularList!(Value) is a circular doubly linked list of data of type - * Value. A CircularList differs from a List in that the tail of the list - * is linked to the head. As a consequence no nodes are saved and - * reused between <tt>add</tt> and <rr>remove</tt> functions and - * slices can be moved forward around the list indefinitely. A CircularList - * also has a smaller memory footprint since it requires only one - * pointer for the head instead of two pointers for a tail and head. - * - * The optional ReadOnly parameter CircularList!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter CircularList!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct CircularList(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias CircularList ContainerType; - alias List!(Value,ReadOnly,Alloc) SliceType; - alias Value ValueType; - alias size_t IndexType; - alias DNode!(Value) Node; - alias ReadOnly isReadOnly; - - private { - size_t length_; - Node* head_; - } - - /* length 0 means length is unknown. */ - invariant { - assert( length_ == 0 || head_ !is null ); - } - - /** Return the circular list as a non-circular List. - * \return the list as a List - */ - SliceType toList() { - SliceType res; - if (this.isEmpty) - return res; - res.privateMake(head_,head_.prev,length_); - // res.tail_ = - // res.head_ = head_; - // res.length_ = length_; - return res; - } - - /** Get a ReadOnly view of the container */ - .CircularList!(Value, true, Alloc) readonly() { - .CircularList!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .CircularList!(Value, false, Alloc) readwrite() { - .CircularList!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - private Node* tail_() { - if (this.isEmpty) return null; - return head_.prev; - } - - static if (!ReadOnly) { - - /** Rotate the list by n items. If n is negative the rotation is - * reversed. - */ - void rotate(int n = 1) { - if (n >= 0) { - while (n-- > 0) - head_ = head_.next; - } else { - while (++n < 0) - head_ = head_.prev; - } - } - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - Node* i = head_; - if (i !is null) - i.prev.next = null; - while (i !is null) { - Node* next = i.next; - Alloc.gcFree(i); - i = next; - } - } - *this = CircularList.init; - } - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. - */ - void addTail(Value v) { - Node* n = newNode(); - n.data = v; - addNode(n); - } - - private void link(Node* a, Node* b) { - a.next = b; - b.prev = a; - } - - /** Adds a node before head. */ - private void addNode(Node* n) { - if (this.isEmpty) { - link(n,n); - head_ = n; - length_ = 1; - } else { - link(tail_,n); - link(n,head_); - if (length_) length_++; - } - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. - */ - void addTail(CircularList v) { - addHead(v); - } - - mixin MListCatOperators!(CircularList); - - // Helper function for take and remove - private Node* takeTailHelper() { - if (this.isEmpty) - throw new IndexOutOfBoundsException(); - Node* v = tail_; - if (head_ && head_ is tail_) { - head_ = null; - } else { - link(v.prev,v.next); - } - return v; - } - - /** Removes and returns the tail item of the list. The node that - * contained the item may be reused in future additions to the - * list. To prevent the node from being reused call <tt>trim</tt> or - * call <tt>remove</tt> with a sublist containing the last item. If - * the target list is empty an IndexOutOfBoundsException is thrown - * unless version=MinTLNoIndexChecking is set. - */ - Value takeTail() { - Node* v = takeTailHelper(); - Value data = v.data; - freeNode(v); - if (length_) length_--; - return data; - } - - /** Removes the tail item of the list. */ - void removeTail() { - Node* v = takeTailHelper(); - if (length_) length_--; - freeNode(v); - } - - /** Prepends an item to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert an - * item before a sub-list. - */ - void addHead(Value v) { - Node* n = new Node; - n.data = v; - addNode(n); - head_ = n; - } - - /** Prepends a list to the head of the target list. If the target - * list is a sub-list call addBefore instead of addHead to insert a - * list before a sub-list. - */ - void addHead(CircularList v) { - if (v.isEmpty) - return; - if (this.isEmpty) { - *this = v; - return; - } - Node* vt = v.tail_; - link(tail_,v.head_); - link(vt,head_); - head_ = v.head_; - length_ = increaseLength(length_, v.length_); - } - - // Helper function for take and remove - private Node* takeHeadHelper() { - if (this.isEmpty) - throw new IndexOutOfBoundsException(); - Node* v = head_; - if (head_ && head_ is tail_) { - head_ = null; - } else { - link(v.prev,v.next); - } - return v; - } - - /** Removes and returns the head item of the list. The node that - * contained the item may be reused in future additions to the - * list. To prevent the node from being reused call <tt>trim</tt> or - * call <tt>remove</tt> with a sublist containing the last item. If - * the target list is empty an IndexOutOfBoundsException is thrown - * unless version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - Node* v = takeHeadHelper(); - Value data = v.data; - if (length_) length_--; - freeNode(v); - return data; - } - - /** Removes the head item of the list. */ - void removeHead() { - Node* v = takeHeadHelper(); - if (length_) length_--; - freeNode(v); - } - - /** Insert a list before a sub-list. */ - void addBefore(SliceType subv, SliceType v) { - if (v.isEmpty) - return; - if (subv.isEmpty) - throw new IndexOutOfBoundsException(); - Node* t = subv.head_; - link(t.prev,v.head_); - link(v.tail_,t); - if (t is head_) - head_ = v.head_; - length_ = increaseLength(length_, v.length_); - } - - /** Insert a list after a sub-list. */ - void addAfter(SliceType subv, SliceType v) { - if (v.isEmpty) - return; - if (subv.isEmpty) - throw new IndexOutOfBoundsException(); - Node* t = subv.tail_; - link(v.tail_,t.next); - link(t,v.head_); - length_ = increaseLength(length_, v.length_); - } - - - /** Removes a sub-list from the list entirely. */ - void remove(SliceType sublist) { - if (sublist.isEmpty) - return; - Node* h = sublist.head_; - Node* t = sublist.tail_; - if (h is head_ && t is tail_) { - head_ = null; - length_ = 0; - return; - } - if (h is head_) - head_ = t.next; - link(h.prev,t.next); - h.prev = null; - t.next = null; - length_ = decreaseLength(length_, sublist.length_); - } - - /** Removes an item if present. */ - void remove(size_t index) { - remove(opSlice(index, index+1)); - } - - /** Removes an item from the list and return its value, if present. */ - Value take(size_t index) { - SliceType item = opSlice(index, index+1); - remove(item); - Value val = item[0]; - item.clear(); - return val; - } - - } // !ReadOnly - - /** Duplicates a list. The operation is O(n) where n is length of - * the list. - */ - CircularList dup() { - .CircularList!(Value,false,Alloc) res; - foreach(ValueType val; *this) { - res ~= val; - } - static if (ReadOnly) { - return res.readonly; - } else { - return res; - } - } - - /** Create a one-item slice of the head. */ - SliceType head() { - SliceType res; - if (this.isEmpty) return res; - res.head_ = res.tail_ = head_; - res.length_ = 1; - return res; - } - - /** Create a one-item slice of the tail. */ - SliceType tail() { - SliceType res; - if (this.isEmpty) return res; - res.head_ = res.tail_ = head_.prev; - res.length_ = 1; - return res; - } - - /** Move a sub-list towards the tail by n items. */ - void next(int n = 1, int end = 0) { - if (length_) - length_ -= n*end; - while (n-- > 0) { - if (end <= 0) - head_ = head_.next; - } - } - - /** Iterate backwards over the list (from tail to head). This - * should be called as the iteration parameter in a - * <tt>foreach</tt> statement - */ - CircularListReverseIter!(Value,ReadOnly,Alloc) backwards() { - CircularListReverseIter!(Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** - * Helper functions for opApply with/without keys and - * forward/backward order - */ - mixin MOpApplyImpl!(ContainerType); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - private Node* newNode() { - static if (is(Alloc == GCAllocator)) { - return new Node; - } else { - Node* p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - *p = Node.init; - return p; - } - } - - private void freeNode(Node* n) { - static if (is(Alloc == GCAllocator)) { - } else { - Alloc.gcFree(n); - } - } - - CircularList getThis(){return *this;} - mixin MListAlgo!(CircularList, getThis); - - mixin MCommonList!(tail_, CircularList ); -} - -// helper functions for adjusting length cache -private size_t increaseLength(size_t len, size_t x) { - return x ? (len? len+x : 0) : 0; -} -private size_t decreaseLength(size_t len, size_t x) { - return x ? (len? len-x : 0) : 0; -} - -// helper structure for backwards() -struct CircularListReverseIter(Value,bit ReadOnly,Alloc) { - mixin MReverseImpl!(List!(Value,ReadOnly,Alloc), - CircularList!(Value,ReadOnly,Alloc)); -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; - -version (MinTLUnittest) { - private import std.random; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.list unittest\n"); - - List!(int) x; - x ~= 3; - x ~= 4; - assert( x[0] == 3 ); - assert( x[1] == 4 ); - assert( x.length == 2 ); - List!(int) x2 = List!(int).make(3,4); - assert( x == x2 ); - - List!(int) catt; - catt = List!(int).make(1,2,3) ~ List!(int).make(4,5,6); - assert( catt == List!(int).make(1,2,3,4,5,6) ); - - List!(int,false,MallocNoRoots) xm; - xm ~= 3; - xm ~= 4; - assert( xm[0] == 3 ); - assert( xm[1] == 4 ); - assert( xm.length == 2 ); - xm.clear(); - assert( xm.isEmpty ); - - List!(real) x2s; - x2s.add(cast(real)3,cast(real)4); - assert( x2s[0] == 3 ); - assert( x2s[1] == 4 ); - - // test addHead - List!(int) y; - y.addHead(4); - y.addHead(3); - - // test == - assert( x == y ); - List!(int) w = x.dup; - w ~= 5; - assert( x != w); - - // test remove/take - assert( w.takeTail() == 5 ); - size_t wlen = w.length; - w.addTail(6); - w.removeTail(); - assert( w.length() == wlen ); - assert( w == x ); - w.trim(); - w ~= 5; - - // test reverse lists - List!(int) z = y.dup; - z.reverse(); - assert( z[0] == 4 ); - assert( z[1] == 3 ); - - // test foreach iteration - foreach(size_t n, inout int val; z) { - val = n*10; - } - assert( z[0] == 0 ); - assert( z[1] == 10 ); - foreach(size_t n, int val; y.backwards()) { - assert(x[n] == val); - } - int n = 0; - foreach(List!(int) itr; y) { - assert(itr[0] == y[n++]); - } - - // test slicing - List!(int) v = w[1..3]; - assert( v.length == 2 ); - assert( v[0] == 4 ); - assert( v[1] == 5 ); - - // test readonly - List!(int,ReadOnly) rv = v.readonly; - assert( rv.length == 2 ); - assert( rv[0] == 4 ); - assert( rv[1] == 5 ); - assert( rv.head == rv[0 .. 1] ); - assert( rv.tail == rv[1 .. 2] ); - - // test algorithms - assert( v.opIn(5) == v.tail ); - assert( v.count(5) == 1 ); - assert( v.find(delegate int(inout int v){return v == 5;}) == v.tail ); - v[0 .. 1].swap(v[1..2]); - assert( v[0] == 5 ); - assert( v[1] == 4 ); - v.fill(10); - assert( v[0] == 10 ); - assert( v[1] == 10 ); - List!(int) vsub; - vsub.add(4,5); - v.copy(vsub); - assert( v[0] == 4 ); - assert( v[1] == 5 ); - - // test another node type - List!(char[]) str; - str.add("hello","world"); - assert( str[str.length-1] == "world" ); - - // test sub-list spanning - List!(int) tmp; - int[10] tmp2; - tmp2[3] = 100; - tmp2[8] = 200; - foreach(int xx;tmp2) - tmp ~= xx; - List!(int) a,b,c; - a = tmp[3..5]; - b = tmp[7..9]; - c = tmp[a..b]; - assert( c.length == 6 ); - assert( c[0] == 100 ); - assert( c[5] == 200 ); - - // CircularList testing - - CircularList!(int) cx; - cx ~= 3; - cx ~= 4; - assert( cx[0] == 3 ); - assert( cx[1] == 4 ); - assert( cx.length == 2 ); - - CircularList!(int) cx2; - cx2.add(3,4); - assert( cx == cx2 ); - - // test addHead - CircularList!(int) cy; - cy.addHead(4); - cy.addHead(3); - - // test == - assert( cx == cy ); - CircularList!(int) cw = cx.dup; - cw ~= 5; - assert( cx != cw); - - // test remove - assert( cw.takeTail() == 5 ); - wlen = cw.length; - cw.addTail(6); - cw.removeTail(); - assert( cw.length() == wlen ); - assert( cw == cx ); - cw ~= 5; - - // test reverse lists - CircularList!(int) cz = cy.dup; - cz.reverse(); - assert( cz[0] == 4 ); - assert( cz[1] == 3 ); - - // test foreach iteration - foreach(size_t n, inout int val; cz) { - val = n*10; - } - assert( cz[0] == 0 ); - assert( cz[1] == 10 ); - foreach(size_t n, int val; cy.backwards()) { - assert(cx[n] == val); - } - n = 0; - foreach(List!(int) itr; cy) { - assert(itr[0] == cy[n++]); - } - - // test slicing - List!(int) cv = w[1..3]; - assert( cv.length == 2 ); - assert( cv[0] == 4 ); - assert( cv[1] == 5 ); - - // test algorithms - assert( cv.opIn(5) == v.tail ); - assert( cv.count(5) == 1 ); - - // test another node type - CircularList!(char[]) cstr; - cstr.add("hello","world"); - assert( cstr[cstr.length-1] == "world" ); - - // test sub-list spanning - CircularList!(int,false,MallocNoRoots) ctmp; - tmp2[3] = 100; - tmp2[8] = 200; - foreach(int xx;tmp2) - ctmp ~= xx; - List!(int,false,MallocNoRoots) ca,cb,cc; - ca = ctmp[3..5]; - cb = ctmp[7..9]; - cc = ctmp[ca..cb]; - assert( cc.length == 6 ); - assert( cc[0] == 100 ); - assert( cc[5] == 200 ); - ctmp.clear(); - assert( ctmp.isEmpty ); - - // test simple sorting - List!(int) s1,s12; - s1.add(40,300,-20,100,400,200); - s12 = s1.dup; - s1.sort(); - List!(int) s2 = List!(int).make(-20,40,100,200,300,400); - //List!(int) s2 = s2.make(-20,40,100,200,300,400); - assert( s1 == s2 ); - // sort a slice in-place - s12[1..4].sort(); - s2.clear(); - s2.add(40,-20,100,300,400,200); - assert( s12 == s2 ); - - // test a large sort with default order - List!(double) s3; - for (int k=0;k<1000;k++) { - s3 ~= 1.0*rand()/100000.0 - 500000.0; - } - List!(double) s4 = s3.dup; - s3.sort(); - for (int k=0;k<999;k++) { - assert( s3[k] <= s3[k+1] ); - } - // test a large sort with custom order - int cmp(double*x,double*y){return *x>*y?-1:*x==*y?0:1;} - s4.sort(&cmp); - for (int k=0;k<999;k++) { - assert( s4[k] >= s4[k+1] ); - } - - version (MinTLVerboseUnittest) - printf("finished mintl.list unittest\n"); - } -}
--- a/trunk/mintl/locks.html Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,490 +0,0 @@ -<HTML> <head> <TITLE>Synchronization Locks Library for D</TITLE> </head> -<body> -<h1>Synchronization Locks for D</h1> -Locks is a library of synchronization constructs for the D -programming language based on the concurrent locks library -by Doug Lea. -For more info about D see <a -href="http://www.digitalmars.com/d/">DigitalMars D home page</a>. The -library can be downloaded -<a href="http://home.comcast.net/~benhinkle/locks/locks.zip">here</a> -or as part of -<a href="http://home.comcast.net/~benhinkle/mintl">MinTL</a>. -For more information about the Java library see -<a href="http://gee.cs.oswego.edu/dl/concurrency-interest/index.html"> -JSR-166</a>. For an initial port see -<a href="http://www.dsource.org/projects/concurrent"> dsource</a>. - -<p> -This library is in the public domain. -Portions written by Ben Hinkle, 2004, portions ported from code -written by Doug Lea. -Email comments and bug reports to ben.hinkle@gmail.com -<p> - -<h3> Overview</h3> - -The D language has builtin support for defining critical sections -using the <tt>synchronized</tt> statement but does not include -POSIX synchronization constructs like locks and condition variables. -The purpose of the Locks library is to extend the builtin D -capabilities to support not only POSIX constructs but also support -latches, barriers and exchangers. Concurrent containers like queues, -stacks and associative arrays are in the MinTL library in the -package <tt>mintl.concurrent</tt>. When using concurrent algorithms -be careful to use the <tt>volatile</tt> statement to ensure data -is properly updated in all the threads. - -<p> -The primary interface of the Locks library is the Lock interface. It -defines two methods, <tt>lock</tt> and <tt>unlock</tt>, that aquire -and release the lock. In general the Lock interface makes no -guarentee that a thread can <tt>lock</tt> a lock that it already -owns. The <tt>ReentrantLock</tt> class, which implements -<tt>Lock</tt>, does guarantee that the thread that hold the lock can -call <tt>lock</tt> without blocking. If a thread calls <tt>lock</tt> -and the lock is held by another thread then the calling thread is -parked until the lock is released. The <tt>tryLock</tt> functions -attempts to acquire the lock immediately or within a specified time interval. -For example a typical -class <tt>X</tt> that uses a <tt>ReentrantLock</tt> to control access -to function <tt>m</tt> uses try-finally blocks to insure the lock is -released before the function returns: - -<pre> - class X { - private ReentrantLock lock; - // ... - this() { - lock = new ReentrantLock; - } - void m() { - lock.lock(); // block until lock is available - try { - // ... method body - } finally { - lock.unlock() - } - } - } -</pre> -A <tt>ScopedLock</tt> can simplify the code around managing locks. -The class <tt>X</tt> could instead use a <tt>ScopedLock</tt> -in <tt>m</tt>: -<pre> - class X { - private ReentrantLock lock; - // ... - this() { - lock = new ReentrantLock; - } - void m() { - auto ScopedLock slock = new ScopedLock(lock); - // ... method body - } - } -</pre> - -The only difference between the two implementations is that the -<tt>ScopedLock</tt>, as written, will allocate memory from the GC each -time it is called. - -<p> -The Condition interface defines a condition variable for a given lock. -A condition variable allows two or more threads to hand-off ownership -of the lock atomically by calling <tt>wait</tt> and <tt>notify</tt>. -If a thread owns the lock and calls <tt>wait</tt> -on a condition variable then the thread releases the lock and -blocks until notified by the condition variable. -Once notified the thread attempts to acquire the lock and once successful -continues execution. The wait function accepts timeout values to stop -blocking after a certain amount of time. A thread that fails the timeout -still must reacquire the lock before proceeding. A typical use of condition -variables is to signal when an event has happened. -The function <tt>Lock.newCondition</tt> creates and returns a Condition -instance. -For example, the -condition below signals when the <tt>data</tt> variable has been set: -<pre> - int data; - Thread getter, setter; - ReentrantLock lock = new ReentrantLock; - Condition is_ready = lock.newCondition; - setter = new Thread( - delegate int() { - lock.lock(); - try { - data = 10; - is_ready.notify(); - } finally { - lock.unlock(); - } - return 0; - }); - getter = new Thread( - delegate int() { - lock.lock(); - try { - is_ready.wait(); - printf("%d\n",data); - } finally { - lock.unlock(); - } - return 0; - }); - getter.start(); - setter.start(); -</pre> - -<p> -To start several threads and have them wait until a signal from a -coordinating thread use a <tt>CountDownLatch</tt> with a count of -1. For example, -<pre> - CountDownLatch go = new CountDownLatch(1); - Thread[4] t; - for (int i=0; i < 4; i++) { - t[i] = new Thread( - delegate int() { - go.wait(); // wait for signal from main thread - // ... do something interesting ... - return 0; - }); - t[i].start(); - } - go.countDown(); // let worker threads go -</pre> -Conversely to signal a coordinating thread that the worker threads -are finished have each worker thread decrement another -<tt>CountDownLatch</tt>: -<pre> - CountDownLatch go = new CountDownLatch(1); - CountDownLatch allDone = new CountDownLatch(4); - Thread[4] t; - for (int i=0; i < 4; i++) { - t[i] = new Thread( - delegate int() { - go.wait(); // wait for signal from main thread - // ... do something interesting ... - allDone.countDown(); - return 0; - }); - t[i].start(); - } - go.countDown(); // let worker threads go - allDone.wait(); // wait for all workers to finish -</pre> - -<p> -A <tt>CyclicBarrier</tt> is similar to a <tt>CountDownLatch</tt> -except the cyclic barrier is used without a controlling thread. -A thread that reaches the barrier waits until the barrier count -is exhausted before continuing. Once the barrier is tripped it -optionally runs a function and resets to zero. Continuing the -example from the previous paragraph the worker threads might need -to rendezvous at a certain point mid-way through their task: -<pre> - CountDownLatch go = new CountDownLatch(1); - CountDownLatch allDone = new CountDownLatch(4); - CyclicBarrier barrier = new CyclicBarrier(4); - Thread[4] t; - for (int i=0; i < 4; i++) { - t[i] = new Thread( - delegate int() { - go.wait(); // wait for signal from main thread - // ... do something interesting ... - barrier.wait(); // wait for all workers to get to barrier - // ... do something else interesting ... - allDone.countDown(); - return 0; - }); - t[i].start(); - } - go.countDown(); // let worker threads go - allDone.wait(); // wait for all workers to finish -</pre> - -<p> -A <tt>Semaphore</tt> maintains a given number of permits. When a -thread acquires a permit the semaphore decremements the number of -available permits and when a thread releases the permit (any thread -can release the permit) the semaphore increments the number of -available permits. Semaphores don't have a concept of threads -owning permits - it only gives out and recieves permits atomically. -A typical use case for semaphores is to manage access by multiple -threads to a fixed collection of objects. - -<h3> API Reference</h3> -This section lists the public structs and functions in the library without -detailed explanation. For more information see the documentation before -the function or class in the source file. -The API is organized by module:<br> -<dl> -<dt><a href="#condition">locks.condition</a> -<dt><a href="#countdown">locks.countdown</a> -<dt><a href="#exchanger">locks.exchanger</a> -<dt><a href="#lock">locks.lock</a> -<dt><a href="#platformutils">locks.platformutils</a> -<dt><a href="#readwritelock">locks.readwritelock</a> -<dt><a href="#reentrantlock">locks.reentrantlock</a> -<dt><a href="#semaphore">locks.semaphore</a> -<dt><a href="#timeunit">locks.timeunit</a> -</dl> - - -<a name="condition"> -<h4>locks.condition</h4> -<dl> -<dt>interface <b>Condition</b> -<dd>A condition variable -<p> -<dl> -<dt>void <b>wait</b>() -<dd>Cause current thread to wait until notified -<dt>long <b>waitNanos</b>(long nanosTimeout) -<dd>Cause current thread to wait until notified or time expires -<dt>bool <b>wait</b>(long time, TimeUnit unit) -<dd>Cause current thread to wait until notified or time expires -<dt>void <b>notify</b>() -<dd>Wake up one waiting thread -<dt>void <b>notifyAll</b>() -<dd>Wake up all waiting threads -</dl> -</dl> - -<a name="countdown"> -<h4>locks.countdown</h4> -<dl> -<dt>class <b>CountDownLatch</b> -<dd>Allow one or more threads to wait for a set of other threads. -<p> -<dl> -<dt><b>this</b>(int count) -<dd>Construct the latch with the given count before releasing -<dt>void <b>wait</b>() -<dd>Causes the current thread to wait until the count reaches zero -<dt>void <b>wait</b>(long timeout, TimeUnit unit) -<dd>Causes the current thread to wait until the count reaches zero or time expires -<dt>void <b>countDown</b>() -<dd>Decrement count -<dt>long <b>count</b> -<dd>Get the current count -<dt>char[] <b>toString</b> -<dd>Return a string summary of the latch -</dl> -</dl> - -<a name="cyclicbarrier"> -<h4>locks.cyclicbarrier</h4> -<dl> -<dt>class <b>CyclicBarrier</b> -<dd>Allow a fixed group of threads to wait for each other -<p> -<dl> -<dt><b>this</b>(int parties, int delegate() barrierAction = null) -<dd>Construct the barrier with given number of parties and concluding action -<dt>int <b>parties</b> -<dd>Return number of parties for this barrier -<dt>int <b>wait</b>() -<dd>Causes the current thread to wait for all parties to reach the barrier -<dt>int <b>wait</b>(long timeout, TimeUnit unit) -<dd>Causes the current thread to wait only for the specified time -<dt>bool <b>isBroken</b>() -<dd>Returns true if the barrier has been broken -<dt>void <b>reset</b>() -<dd>Break the barrier for waiting parties and reset to initial state -<dt>int <b>getNumberWaiting</b> -<dd>Get the current number of waiting parties -</dl> -</dl> - -<a name="exchanger"> -<h4>locks.exchanger</h4> -<dl> -<dt>class <b>Exchanger</b>(Value) -<dd>Allow two threads to safely exchange values. -<p> -<dl> -<dt><b>this</b>() -<dd>Construct the exchanger -<dt>Value <b>exchange</b>(Value v) -<dd>Offer v for exchange and wait for response -<dt>Value <b>exchange</b>(Value v, long timeout, TimeUnit unit) -<dd>Offer v for exchange and wait for response with possible timeout -</dl> -</dl> - -<a name="lock"> -<h4>locks.lock</h4> -<dl> -<dt>interface <b>Lock</b> -<dd>The interface for all lock implementations. -<p> -<dl> -<dt>void <b>lock</b>() -<dd>Acquires the lock -<dt>bool <b>tryLock</b>() -<dd>Acquires the lock only if it is free at the time of invocation -<dt>bool <b>tryLock</b>(long time, TimeUnit unit) -<dd>Acquires the lock if it is free within the given waiting time -<dt>void <b>unlock</b>() -<dd>Releases the lock -<dt>Condition <b>newCondition</b> -<dd>Returns a new Condition instance that is bound to this lock instance -</dl> -</dl> -<dl> -<dt>auto final class <b>ScopedLock</b> -<dd>An auto class for aquiring and releasing a lock in a scope -<p> -<dl> -<dt><b>this</b>(Lock lock) -<dd>Initializes the ScopedLock and acquires the supplied lock -<dt><b>~this</b>() -<dd>Release the lock -</dl> -</dl> - -<a name="platformutils"> -<h4>locks.platformutils</h4> -<dl> -<dt>bit <b>compareAndSet32</b>(void* mem, void* expect, void* update) -<dd>Compare the 32 bit value expect with the value at *mem and if equal -set to update and return true. This assumes a pointer is 32 bits. -<dt>bit <b>compareAndSet32</b>(void* mem, int expect, int update) -<dd>Convenience overload for compareAndSet32 when the data are integers -instead of pointers -<dt>bit <b>compareAndSet64</b>(void* mem, void* expect, void* update) -<dd>Compare the 64 bit value at *expect with the value at *mem and if equal -set to *update and return true. -<dt>int <b>atomicAdd32</b>(int* val, int x); -<dd>Atomically add x to *val and return previous value of *val -<dt>int <b>atomicExchange32</b>(int* val, int x); -<dd>Atomically store x to *val and return previous value of *val -<dt>void <b>atomicInc32</b>(int* val); -<dd>Atomically increment *val -<dt>void <b>atomicDec32</b>(int* val); -<dd>Atomically decrement *val -<dt>long <b>currentTimeMillis</b>() -<dd>Return the current system time in milliseconds -<dt>long <b>currentTimeNanos</b>() -<dd>Return the current system time in nanoseconds -<dt>void <b>sleepNanos</b>(long duration) -<dd>Sleep the current thread for the specified duration in nanoseconds -</dl> - -<a name="readwritelock"> -<h4>locks.readwritelock</h4> -<dl> -<dt>interface <b>ReadWriteLock</b> -<dd>A pair of read-write locks -<p> -<dl> -<dt>Lock <b>readLock</b>() -<dd>Return the read lock -<dt>Lock <b>writeLock</b>() -<dd>Return the write lock -</dl> -</dl> -<p> -<dl> -<dt>class <b>ReentrantReadWriteLock</b> : ReadWriteLock -<dd>A pair of reentrant read-write locks -<p> -<dl> -<dt><b>this</b>(bool fair = false) -<dd>Construct the lock with specified fairness policy -<dt>Lock <b>readLock</b>() -<dd>Return the read lock -<dt>Lock <b>writeLock</b>() -<dd>Return the write lock -</dl> - -</dl> - -<a name="reentrantlock"> -<h4>locks.reentrantlock</h4> -<dl> -<dt>class <b>ReentrantLock</b> : Lock -<dd>A reentrant mutual exclusive lock with condition variables -<p> -<dl> -<dt><b>this</b>(bool fair = false) -<dd>Construct the lock with specified fairness policy -<dt>void <b>lock</b>() -<dd>Acquires the lock -<dt>bool <b>tryLock</b>() -<dd>Acquires the lock only if it is free at the time of invocation -<dt>bool <b>tryLock</b>(long time, TimeUnit unit) -<dd>Acquires the lock if it is free within the given waiting time -<dt>void <b>unlock</b>() -<dd>Releases the lock -<dt>Condition <b>newCondition</b> -<dd>Returns a new Condition instance that is bound to this lock instance -<dt>int <b>getHoldCount</b>() -<dd>Get the number of holds on this lock by the current thread -<dt>bool <b>isHeldByCurrentThread</b>() -<dd>Query if the lock is held by the current thread -<dt>bool <b>isLocked</b>() -<dd>Query if the lock is held by any thread -<dt>bool <b>isFair</b>() -<dd>Query if the lock is fair -<dt>char[] <b>toString</b>() -<dd>return a string representation of the lock -</dl> - -</dl> - -<a name="semaphore"> -<h4>locks.semaphore</h4> -<dl> -<dt>class <b>Semaphore</b> -<dd>A counting semaphore for maintaining a set of permits -<p> -<dl> -<dt><b>this</b>(int permits, bool fair = false) -<dd>Construct the semaphore with the given number of permits and fairness policy -<dt>void <b>acquire</b>(int permits = 1) -<dd>Acquires n permits, blocking until all are available -<dt>bool <b>tryAcquire</b>(int permits = 1) -<dd>Acquires n permit from this semaphore only if they are immediately available -<dt>bool <b>tryAcquire</b>(long timeout, TimeUnit unit, int permits = 1) -<dd>Attempt acquiring n permits within the specified time interval -<dt>void <b>release</b>(int permits = 1) -<dd>Release n permits -<dt>int <b>availablePermits</b> -<dd>Get the current number of available permits -<dt>bool <b>isFair</b>() -<dd>return true if the semaphore is fair -<dt>char[] <b>toString</b> -<dd>Return a string summary of the semaphore -</dl> - -</dl> - -<a name="timeunit"> -<h4>locks.timeunit</h4> -<dl> - <dt>enum <b>TimeUnit</b> - <dd>Time units common in synchronization - <dl> - <dt><b>NanoSeconds = 0</b> - <dt><b>MicroSeconds</b> - <dt><b>MilliSeconds</b> - <dt><b>Seconds</b> - </dl> - <p> -<dt>long <b>convert</b>(long duration, TimeUnit fromUnit, TimeUnit toUnit); -<dd>Convert the given time duration in the given unit to this unit. -<dt>long <b>toNanos</b>(long duration, TimeUnit fromUnit); -<dd>Convert to nanoseconds. -<dt>long <b>toMicros</b>(long duration, TimeUnit fromUnit); -<dd>Convert to microseconds. -<dt>long <b>toMillis</b>(long duration, TimeUnit fromUnit); -<dd>Convert to milliseconds. -<dt>long <b>toSeconds</b>(long duration, TimeUnit fromUnit); -<dd>Convert to seconds. -</dl> - -</BODY> -</HTML>
--- a/trunk/mintl/mem.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/** \file mem.d - * \brief Allocators for custom container memory management - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * version 1.0 - */ - -module mintl.mem; - -private { - import tango.stdc.stdlib; - import tango.core.Memory : GC; - import tango.core.Exception : onOutOfMemoryError; -} - -/** An Allocator is a type containing 8 symbols malloc, calloc, - * realloc, free and the corresponding GC-aware versions gcMalloc, - * gcCalloc, gcRealloc and gcFree. Containers will call the GC-aware - * functions on blocks that may hold roots and otherwise will call the - * regular functions. Allocators are expected to throw OutOfMemory if - * the allocation fails. Be aware than when using an allocator with - * a container one must call the container <tt>clear()</tt> function - * to free the memory. - * - * The two predefined allocators Malloc and MallocNoRoots use - * std.c.stdlib.malloc to perform allocations. The MallocNoRoots - * ignores any requests by the container to register roots with the - * GC. The MallocNoRoots allocator should only be used with containers - * that the user knows will never contain any roots (e.g. ArrayList!(int)) - */ - -/** Malloc and throw OutOfMemory if fails. */ -void* mallocWithCheck(size_t s) { - void* p = malloc(s); - if (!p) - onOutOfMemoryError(); - return p; -} - -/** Calloc and throw OutOfMemory if fails. */ -void* callocWithCheck(size_t n, size_t s) { - void* p = calloc(n,s); - if (!p) - onOutOfMemoryError(); - return p; -} - -/** Realloc and throw OutOfMemory if fails. */ -void* reallocWithCheck(void*p, size_t s) { - p = realloc(p,s); - if (!p) - onOutOfMemoryError(); - return p; -} - -/** Free pointer. */ -void dfree(void*p) { - free(p); -} - -/** Malloc and register the range with GC. */ -void* gcMalloc(size_t s) { - void* p = mallocWithCheck(s); - GC.addRange(p,s); - return p; -} - -/** Calloc and register the range with GC. */ -void* gcCalloc(size_t n, size_t s) { - void* p = callocWithCheck(n,s); - GC.addRange(p,n*s); - return p; -} - -/** Realloc and register the range with GC. */ -void* gcRealloc(void* p, size_t s) { - if (p) - GC.removeRange(p); - p = reallocWithCheck(p,s); - GC.addRange(p,s); - return p; -} - -/** Deregister the range with GC and free. */ -void gcFree(void* p) { - if (p) - GC.removeRange(p); - free(p); -} - -// Default Allocator -struct GCAllocator{ - alias void malloc; - alias void calloc; - alias void realloc; - alias void free; - alias void gcMalloc; - alias void gcCalloc; - alias void gcRealloc; - alias void gcFree; -} - -// An allocator that uses malloc -struct Malloc { - alias mallocWithCheck malloc; - alias callocWithCheck calloc; - alias reallocWithCheck realloc; - alias dfree free; - alias .gcMalloc gcMalloc; - alias .gcCalloc gcCalloc; - alias .gcRealloc gcRealloc; - alias .gcFree gcFree; -} - -// An allocator that uses malloc and assumes allocations have no roots -struct MallocNoRoots { - alias mallocWithCheck malloc; - alias callocWithCheck calloc; - alias reallocWithCheck realloc; - alias dfree free; - alias mallocWithCheck gcMalloc; - alias callocWithCheck gcCalloc; - alias reallocWithCheck gcRealloc; - alias dfree gcFree; -} -
--- a/trunk/mintl/multiaa.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/** \file multiaa.d - * \brief An associative array that allows multiple values per key. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * The red-black tree code is by Thomas Niemann. - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 1.2 - */ - -module mintl.multiaa; - -private import mintl.share; -private import mintl.adapter; -private import mintl.sortedaa; -private import mintl.hashaa; -private import std.stdarg; -private import std.boxer; - -//version = WithBox; - -/** An associative array of items with duplicate keys. - * By default the backing container is a builtin associative array. - */ -struct MultiAA(Key, Value, ImplType = HashAA!(Key,Value[])) { - - alias MultiAA ContainerType; - alias Value ValueType; - alias Key IndexType; - alias ImplType AdaptType; - const bit isReadOnly = ImplType.isReadOnly; - - ImplType impl; - - size_t length() { - size_t total = 0; - foreach(Value[] val; impl) { - total += val.length; - } - return total; - } - int opEquals(MultiAA c) { return impl == c.impl; } - static if (!ImplType.isReadOnly) { - void remove(Key key) { - impl.remove(key); - } - void remove(Key key, Value val) { - Value[]* vals = impl.get(key); - if (vals) { - size_t k; - Value[] x = *vals; - for(k = 0; k<x.length;k++) { - if (x[k] == val) - break; - } - for(; k < x.length-1; k++) { - x[k] = x[k+1]; - } - *vals = x[0 .. k]; - } - } - void addItem(Key key, Value item) { - Value[]* vals = impl.put(key); - (*vals) ~= item; - } - void clear(){ impl.clear(); } - } // !isReadOnly - Value[] opIndex(Key key) {return impl[key];} - MultiAA dup() { - MultiAA res; - res.impl = impl.dup; - return res; - } - bool isEmpty() { return impl.isEmpty(); } - // mixin MMAASpecial!(impl,MultiAA,Key,Value,ImplType) mAA; - static if (!ImplType.isReadOnly) { - /** Inserts the specified items into the target AA by calling - * x[key]=value repeatedly. - */ - void add(...) { - vadd(_arguments,_argptr); - } - void vadd(TypeInfo[] arguments, void* argptr) { - for (int k=0;k<arguments.length;k++) { - TypeInfo tik = typeid(Key); - if (arguments[k] == tik) { - Key key = va_arg!(Key)(argptr); - k++; - addItem(key,va_arg!(Value)(argptr)); - } else { - version(WithBox) { - Box b = box(tik,argptr); - Key key = unbox!(Key)(b); - k++; - TypeInfo tiv = arguments[k]; - b = box(tiv,argptr); - addItem(key,unbox!(Value)(b)); - argptr += va_argumentLength(tiv.tsize()); - } - } - } - } - /** Construct a container with specified contents */ - static MultiAA make(...) { - MultiAA res; - res.vadd(_arguments,_argptr); - return res; - } - } - - Key[] keys() { return impl.keys; } - Value[][] values() { return impl.values; } - int opApply(int delegate(inout Value x) dg){ - int res; -L0: foreach(inout Value[] item; impl) { - foreach(inout Value val; item) { - res = dg(val); - if (res) break L0; - } - } - return res; - } - int opApply(int delegate(inout Key key, inout Value x) dg){ - int res; -L1: foreach(Key key, inout Value[] item; impl) { - foreach(inout Value val; item) { - res = dg(key,val); - if (res) break L1; - } - } - return res; - } -} - -// Adapter for a sorted MultiAA -template SortedMultiAA(Key,Value) { - alias MultiAA!(Key,Value,SortedAA!(Key,Value[])) SortedMultiAA; -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.multiaa unittest\n"); - - // test MultiSet - MultiAA!(int,char[]) ma2; - ma2.add(22,"hello",-100,"there",22,"world"); - static char[][2] res = ["hello","world"]; - static char[][1] res2 = ["there"]; - char[][] vv = ma2[22]; - assert( ma2[22].length == 2); - assert( ma2[22] == res); - assert( ma2[-100] == res2); - int count22; - int count; - foreach( int key, char[] item; ma2 ) { - if (key == 22) { - count22++; - } else { - count++; - } - } - assert( count22 == 2 ); - assert( count == 1 ); - ma2.remove(-100); - assert( ma2.length == 2 ); - ma2.remove(22,"hello"); - static char[][1] res3 = ["world"]; - assert( ma2[22] == res3); - assert( ma2.length == 1 ); - ma2.remove(22); - assert( ma2.length == 0 ); - assert( ma2.isEmpty ); - - // test SortedMultiSet - SortedMultiAA!(char[],int) s3; - s3.add("hello",10,"world",20); - s3.addItem("hello",40); - int[] vals = s3["hello"]; - assert( s3["hello"].length == 2); - assert( vals[0] == 10 && vals[1] == 40 ); - vals = s3["world"]; - assert( vals.length == 1 && vals[0] == 20 ); - - version (MinTLVerboseUnittest) - printf("finished mintl.multiaa unittest\n"); - } -}
--- a/trunk/mintl/queue.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/** \file queue.d - * \brief A queue container - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 1.1 - */ - -module mintl.queue; - -private import mintl.deque; -private import mintl.arraylist; -private import mintl.arrayheap; -import mintl.adapter; -import mintl.share; - -/** A queue of items of stype Value backed by a container of type ImplType. - * Aliases put and take allow queue operations. By default the queue is - * backed by a Deque. - */ -struct Queue(Value, ImplType = Deque!(Value)) { - - alias Queue ContainerType; - alias Value ValueType; - alias size_t IndexType; - alias ImplType AdaptType; - const bit isReadOnly = ImplType.isReadOnly; - - ImplType impl; - - mixin MAdaptBuiltin!(impl,Queue); - mixin MAdaptBasic!(impl,Queue); - mixin MAdaptList!(impl,Queue); - mixin MListCatOperators!(Queue); - - // Queue specific - static if (!ImplType.isReadOnly) { - alias addTail put; - alias takeHead take; - } - Value peek() { - return impl.isEmpty ? Value.init : impl[0]; - } -} - -/** Convenience alias for a queue backed by an array */ -template ArrayQueue(Value) { - alias Queue!(Value,ArrayList!(Value)) ArrayQueue; -} - -/** Convenience alias for a queue backed by a heap */ -template PriorityQueue(Value) { - alias Queue!(Value,ArrayHeap!(Value)) PriorityQueue; -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; - -version (MinTLUnittest) { - import mintl.list; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.queue unittest\n"); - - Queue!(int) q; - q ~= 10; - q ~= 20; - assert( q.peek == 10 ); - assert( q.take == 10 ); - assert( q[0] == 20 ); - assert( q.take == 20 ); - assert( q.length == 0 ); - - ArrayQueue!(int) st2; - st2.put(10); - st2 ~= 20; - assert( st2.peek == 10 ); - assert( st2.take == 10 ); - assert( st2[0] == 20 ); - assert( st2.take == 20 ); - assert( st2.length == 0 ); - - Queue!(int,List!(int)) st3; - st3.put(10); - st3 ~= 20; - assert( st3.peek == 10 ); - assert( st3.take == 10 ); - assert( st3[0] == 20 ); - assert( st3.take == 20 ); - assert( st3.length == 0 ); - - version (MinTLVerboseUnittest) - printf("finished mintl.queue unittest\n"); - } -}
--- a/trunk/mintl/set.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/** \file set.d - * \brief Set, sorted set and multi-set containers. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.set; - -private import mintl.share; -private import mintl.adapter; -private import mintl.sortedaa; -private import mintl.hashaa; -private import std.stdarg; -private import std.boxer; - -//version = WithBox; - -template MAddSet(Container,Value) { - /** Inserts the specified items into the set. */ - void add(...) { - vadd(_arguments,_argptr); - } - void vadd(TypeInfo[] arguments, void* argptr) { - for (int k=0;k<arguments.length;k++) { - TypeInfo tik = typeid(Value); - if (arguments[k] == tik) { - addItem(va_arg!(Value)(argptr)); - } else { - version(WithBox) { - Box b = box(tik,argptr); - addItem(unbox!(Value)(b)); - argptr += va_argumentLength(tik.tsize()); - } - } - } - } - /** Construct a container with specified contents */ - static Container make(...) { - Container res; - res.vadd(_arguments,_argptr); - return res; - } -} - -/** A set of items. By default the backing container is a HashAA - * associative array. - */ -struct Set(Value, ImplType = HashAA!(Value,uint)) { - - alias Set ContainerType; - alias Value ValueType; - alias ImplType AdaptType; - const bit isReadOnly = ImplType.isReadOnly; - - ImplType impl; - - mixin MAdaptBuiltin!(impl,Set); - static if (!ImplType.isReadOnly) { - void remove(Value item) { impl.remove(item); } - } - bool opIndex(Value item) {return impl.contains(item); } - Set dup() { - Set res; - res.impl = impl.dup; - return res; - } - void clear(){ impl.clear(); } - bool isEmpty() { return impl.isEmpty(); } - static if (!ImplType.isReadOnly) { - mixin MAddSet!(Set,Value) mAdd; - } - - Value[] values() { return impl.keys; } - void addItem(Value item) { impl[item] = 1; } - int opApply(int delegate(inout Value x) dg){ - int res; - foreach(Value item, uint ignore; impl) { - res = dg(item); - if (res) break; - } - return res; - } -} - -/** Adapter for sorted set of items. */ -template SortedSet(Value) { - alias Set!(Value,SortedAA!(Value,uint)) SortedSet; -} - -/** A set of items with repeats. By default the backing container is a - * HashAA associative array. - */ -struct MultiSet(Value, ImplType = HashAA!(Value,uint)) { - - alias Set ContainerType; - alias Value ValueType; - alias ImplType AdaptType; - static if (is(ImplType:uint[Value])) { - const bit isReadOnly = false; - } else { - const bit isReadOnly = ImplType.isReadOnly; - } - - ImplType impl; - - size_t length() { - size_t total = 0; - foreach(uint val; impl) { - total += val; - } - return total; - } - int opEquals(MultiSet c) { return impl == c.impl; } - static if (!ImplType.isReadOnly) { - void remove(Value item) { - uint* val = impl.get(item); - if (val && (--(*val) == 0)) - impl.remove(item); - } - void addItem(Value item) { - (*impl.put(item))++; - } - } - bool opIndex(Value item) {return impl.get(item) !is null; } - MultiSet dup() { - MultiSet res; - res.impl = impl.dup; - return res; - } - void clear(){ impl.clear(); } - bool isEmpty() { return impl.isEmpty(); } - static if (!ImplType.isReadOnly) { - mixin MAddSet!(MultiSet, Value) mAdd; - } - - Value[] values() { return impl.keys; } - int opApply(int delegate(inout Value x) dg){ - int res; - foreach(Value item, uint val; impl) { - while (val--) { - res = dg(item); - if (res) break; - } - } - return res; - } -} - -/** Adapter for sorted multi-set. */ -template SortedMultiSet(Value) { - alias MultiSet!(Value,SortedAA!(Value,uint)) SortedMultiSet; -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; -version (MinTLUnittest) { - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.set unittest\n"); - - // test Set - Set!(char[]) s; - s.add("hello","world"); - assert( s["world"] ); - assert( s["hello"] ); - assert( !s["worldfoo"] ); - foreach(char[] val ; s) { - version (MinTLVerboseUnittest) - printf("%.*s\n",val); - } - - // test SortedSet - SortedSet!(char[]) s2; - s2.add("hello","world"); - assert( s2["world"] ); - assert( s2["hello"] ); - assert( !s2["worldfoo"] ); - foreach(char[] val ; s2) { - version (MinTLVerboseUnittest) - printf("%.*s\n",val); - } - assert( !s2.isEmpty ); - - // test MultiSet - MultiSet!(int) ma2; - ma2.add(22,-100,22); - assert( ma2[22] ); - assert( ma2[-100] ); - int count22; - int count; - foreach( int item; ma2 ) { - if (item == 22) { - count22++; - } else { - count++; - } - } - assert( count22 == 2 ); - assert( count == 1 ); - ma2.remove(-100); - assert( ma2.length == 2 ); - ma2.remove(22); - assert( ma2[22] ); - assert( ma2.length == 1 ); - ma2.remove(22); - assert( ma2.length == 0 ); - assert( ma2.isEmpty ); - - // test SortedMultiSet - SortedMultiSet!(char[]) s3; - s3.add("hello","world"); - assert( s3["world"] ); - assert( s3["hello"] ); - assert( !s3["worldfoo"] ); - - version (MinTLVerboseUnittest) - printf("finished mintl.set unittest\n"); - } -}
--- a/trunk/mintl/share.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -/** \file share.d - * \brief Mixin templates and exceptions shared between modules. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - */ - -module mintl.share; - -public import tango.core.Vararg; -import tango.core.Traits : ParameterTupleOf; -//public import std.boxer; - -alias bool bit; -const bit ReadOnly = true; - -//version = WithBox; - -/** Return the length of an argument in bytes. */ -size_t va_argumentLength(size_t baseLength) -{ - return (baseLength + int.sizeof - 1) & ~(int.sizeof - 1); -} - -/** A mixin for overloading ~, ~=, and add - * Assumes List class implements dup, addTail, addHead - */ -template MListCatOperators(List) { - - /** Appends the specified items to the tail of the target list by - * calling <tt>addTail</tt> repeatedly. - */ - void add(...) { - vadd(_arguments,_argptr); - } - void vadd(TypeInfo[] arguments, void* argptr) { - for (int k=0;k<arguments.length;k++) { - TypeInfo tiv = typeid(List.ValueType); - TypeInfo tik = arguments[k]; - if (tik is tiv) { - addTail(va_arg!(List.ValueType)(argptr)); - } else { - version (WithBox) { - Box b = box(tik,argptr); - addTail(unbox!(List.ValueType)(b)); - argptr += va_argumentLength(tik.tsize()); - } else { - throw new Exception("illegal add argument"); - } - } - } - } - - /** Construct a list with specified contents */ - static List make(...) { - List res; - res.vadd(_arguments,_argptr); - return res; - } - - /** Add a value N times */ - void addN(uint n, List.ValueType v) { - while (n--) - addTail(v); - } - - /** Appends an item to the tail of the target list. If the target - * list is a sub-list call addAfter instead of ~= to insert an item - * after a sub-list. - */ - List opCatAssign(List.ValueType v) { - addTail(v); - return *this; - } - - /** Appends an item to the tail of a duplicate of the target list. */ - List opCat(List.ValueType v) { - List res = this.dup; - res.addTail(v); - return res; - } - - /** Appends a list to the tail of the target list. */ - List opCatAssign(List v) { - addTail(v.dup); - return *this; - } - - /** Appends a duplicate of the input list to the tail of a duplicate - * of the target list. - */ - List opCat(List v) { - List res = this.dup; - res.addTail(v.dup); - return res; - } - - /** Appends an item to the tail of a duplicate of the target list. */ - List opCat_r(List.ValueType v) { - List res = this.dup; - res.addHead(v); - return res; - } -} - -/** \class IndexOutOfBoundsException - * \brief An exception thrown when attempting to index past the head - * or tail of a list or when attempting to remove an element from an - * empty list. - */ -class IndexOutOfBoundsException: Exception { - this(char[] str) { super(str); } - this() { super("Index out of bounds"); } -} - -/** A mixin for associative array add function */ -template MAddAA(AA) { - - /** Inserts the specified items into the target AA by calling - * x[key]=value repeatedly. - */ - void add(...) { - vadd(_arguments,_argptr); - } - void vadd(TypeInfo[] arguments, void* argptr) { - for (int k=0;k<arguments.length;k++) { - TypeInfo tik = typeid(AA.IndexType); - if (arguments[k] == tik) { - // workaround for GNU compilers using std.c.stdarg - alias ParameterTupleOf!(va_arg!(AA.IndexType))[0] VaList; - VaList vaList = cast(VaList)argptr; - AA.IndexType key = va_arg!(AA.IndexType)(vaList); - k++; - (*this)[key] = va_arg!(AA.ValueType)(vaList); - argptr = cast(void*)vaList; - } else { - version (WithBox) { - Box b = box(tik,argptr); - AA.IndexType key = unbox!(AA.IndexType)(b); - k++; - TypeInfo tiv = arguments[k]; - b = box(tiv,argptr); - (*this)[key] = unbox!(AA.ValueType)(b); - argptr += va_argumentLength(tiv.tsize()); - } else { - throw new Exception("illegal add argument"); - } - } - } - } - - /** Construct a container with specified contents */ - static AA make(...) { - AA res; - res.vadd(_arguments,_argptr); - return res; - } -} - -/** Mixin template for defining opApply variations */ -template MOpApplyImpl(Container) { - - int opApplyNoKey(int delegate(inout Container.ValueType n) dg){ - return opApplyNoKeyStep(dg); - } - - int opApplyWithKey(int delegate(inout Container.IndexType n, inout Container.ValueType x) dg){ - return opApplyWithKeyStep(dg); - } - - int opApplyIter(int delegate(inout Container.SliceType n) dg){ - return opApplyIterStep(dg); - } - - int opApplyBackwards(int delegate(inout Container.ValueType x) dg){ - return opApplyNoKeyStep(dg,-1); - } - - int opApplyWithKeyBackwards(int delegate(inout Container.IndexType n, inout Container.ValueType x) dg){ - return opApplyWithKeyStep(dg,-1); - } - - int opApplyIterBackwards(int delegate(inout Container.SliceType x) dg){ - return opApplyIterStep(dg,-1); - } - -} - -/** Mixin template for defining opApply variations for - * backward iteration. Use in conjunction with mixing in - * MOpApplyHelpers into the primary structure. - */ -template MReverseImpl(Iter,Container = Iter) { - Container* list; - - int opApply(int delegate(inout Iter.ValueType x) dg){ - return list.opApplyNoKeyStep(dg,-1); - } - - int opApply(int delegate(inout Iter.IndexType n, inout Iter.ValueType x) dg){ - return list.opApplyWithKeyStep(dg,-1); - } - - int opApply(int delegate(inout Iter x) dg){ - return list.opApplyIterStep(dg,-1); - } -} - -/** Mixin for list algorithms */ -template MListAlgo(Container, alias list) { - - // return first occurrence of v - Container.SliceType opIn(Container.ValueType v) { - Container.SliceType res; - TypeInfo ti = typeid(Container.ValueType); - foreach(Container.SliceType i; list) { - Container.ValueType iv = i.value; - if (ti.equals(&v,&iv)) { - res = i; - break; - } - } - return res; - } - - // count number of occurrences of v - uint count(Container.ValueType v) { - uint res; - TypeInfo ti = typeid(Container.ValueType); - foreach(inout Container.ValueType val; list) { - if (ti.equals(&v,&val)) - res++; - } - return res; - } - - static if (!Container.isReadOnly) { - // swap values with v - void swap(Container v) { - if (v.isEmpty) return; - Container.SliceType jend = v.tail; - Container.SliceType j = v.head; - TypeInfo ti = typeid(Container.ValueType); - foreach(Container.SliceType i; list) { - Value v = i.value; - i.value = j.value; - j.value = v; - if (j == jend) break; - j.next(); - } - } - - // fill the container with a value - void fill(Container.ValueType v) { - foreach(inout Container.ValueType val; list) { - val = v; - } - } - - // copy the contents of v to this container - void copy(Container v) { - if (v.isEmpty) return; - Container.SliceType i = v.head; - Container.SliceType j = v.tail; - foreach(inout Container.ValueType val; list) { - val = i.value; - if (i == j) break; - i.next(); - } - } - - } // !isReadOnly - - // find first occurrence where delegate is true - Container.SliceType find(int delegate(inout Value v) dg) { - Container.SliceType res; - TypeInfo ti = typeid(Container.ValueType); - foreach(Container.SliceType i; list) { - Container.ValueType v = i.value; - if (dg(v)) { - res = i; - break; - } - } - return res; - } - -}
--- a/trunk/mintl/slist.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,882 +0,0 @@ -/** \file slist.d - * \brief A singly-linked list and circular singly-linked list. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.slist; - -private import mintl.share; // for ~ and ~= and SNode -import mintl.mem; - -// shared data structure between SList and CircularSList -private struct SNode(Value) { - SNode* next; - Value data; -} - -/** Template for member functions common to SList and CircularSList */ -template MCommonSList(alias head_, Container ) { - - /** Get the length of list. This operation is O(n) where n is - * the resulting length. - */ - size_t length() { - Container.Node* p = head_; - if (p is null) - return 0; - size_t len = 1; - while (p !is tail_) { - p = p.next; - len++; - } - return len; - } - - /** Test if container is empty. */ - bool isEmpty() { - return head_ is null; - } - - /** helper function to check if the index is legal. */ - void boundsCheck(Container.Node* p) { - version (MinTLNoIndexChecking) { - } else { - if (p is null) { - throw new IndexOutOfBoundsException(); - } - } - } - - /* Internal function to get the nth item of the list. */ - package Container.Node* getNode(size_t n) { - boundsCheck(head_); - Container.Node* p = head_; - while (n--) { - p = p.next; - boundsCheck(p); - } - return p; - } - - /** Get the nth item in the list from head. The operation is O(n). - * To efficiently access the tail of the list use the <tt>tail</tt> - * property. - * Indexing out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - Container.ValueType opIndex(size_t n) { - return getNode(n).data; - } - - static if (!Container.isReadOnly) { - - /** Get a pointer to the nth item in the list from head. The - * operation is O(n). To efficiently access the tail of the list - * use the <tt>tail</tt> property. Indexing out of bounds throws an - * IndexOutOfBoundsException unless version=MinTLNoIndexChecking is - * set. - */ - Container.ValueType* lookup(size_t n) { - return &getNode(n).data; - } - - /** Set the nth item in the list from head. The operation is O(n). - * To efficiently access the tail of the list use the <tt>tail</tt> - * property. - * Indexing out of bounds throws an IndexOutOfBoundsException unless - * version=MinTLNoIndexChecking is set. - */ - void opIndexAssign(Container.ValueType val, size_t n) { - getNode(n).data = val; - } - - } // !ReadOnly - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The value is passed to the delegate. - */ - int opApplyNoKey(int delegate(inout Container.ValueType x) dg){ - int dg2(inout size_t count, inout Container.ValueType val) { - return dg(val); - } - return opApplyWithKey(&dg2); - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. The index from 0 and the value are passed - * to the delegate. - */ - int opApplyWithKey(int delegate(inout size_t n, inout Container.ValueType x) dg){ - Container.Node* i = head_; - Container.Node* end = tail_; - int res = 0; - size_t n = 0; - while (i !is null) { - res = dg(n, i.data); - if (res || i is end) break; - n++; - i = i.next; - } - return res; - } - - /** Iterates over the list from head to tail calling delegate to - * perform an action. A one-item sub-list is passed to the delegate. - */ - int opApplyIter(int delegate(inout Container.SliceType n) dg){ - Container.Node* i = head_; - Container.Node* end = tail_; - int res = 0; - Container.SliceType n; - while (i !is null) { - n.head_ = n.tail_ = i; - res = dg(n); - if (res || i is end) break; - i = i.next; - } - return res; - } - - /** Test for equality of two lists. The operation is O(n) where n - * is length of the list. - */ - int opEquals(Container c) { - Container.Node* i = head_; - Container.Node* j = c.head_; - Container.Node* t = tail_; - Container.Node* ct = c.tail_; - TypeInfo ti = typeid(Container.ValueType); - while (i !is null && j !is null) { - if (!ti.equals(&i.data,&j.data)) - return 0; - if (i is t && j is ct) - return 1; - i = i.next; - j = j.next; - } - return (i is null && j is null); - } - - /** Compare two lists. */ - int opCmp(Container c) { - Container.Node* i = head_; - Container.Node* j = c.head_; - Container.Node* t = tail_; - Container.Node* ct = c.tail_; - TypeInfo ti = typeid(Container.ValueType); - while (i !is null && j !is null) { - int cmp = ti.compare(&i.data,&j.data); - if (cmp) - return cmp; - if (i is t && j is ct) - return 0; - i = i.next; - j = j.next; - } - if (i is null && j is null) - return 0; - else - return (i is null) ? -1 : 1; - } - - /** Create a one-item slice of the head. */ - Container.SliceType head() { - return opSlice(0,1); - } - - /** Return a one-item slice at the tail. */ - Container.SliceType tail() { - Container.SliceType res; - res.head_ = res.tail_ = tail_; - return res; - } - - /** Create a sub-list from index a to b (exclusive). The operation is - * O(max(a,b)). */ - Container.SliceType opSlice(size_t a, size_t b) { - Container.SliceType res; - if (a != b) { - res.head_ = getNode(a); - Container.Node *v = res.head_; - b = b-a-1; - while (b--) - v = v.next; - res.tail_ = v; - } - return res; - } - - /** Create a sub-list from the head of a to the tail of b (inclusive). */ - Container.SliceType opSlice(Container.SliceType a, Container.SliceType b) { - if (a.head_ is null) - return b; - if (b.head_ is null) - return a; - Container.SliceType res; - res.head_ = a.head_; - res.tail_ = b.tail_; - return res; - } - - /** Copies the list contents to an array. */ - Container.ValueType[] values() { - Container.ValueType[] buffer = new Container.ValueType[length()]; - foreach(size_t n, Container.ValueType val; *this) { - buffer[n] = val; - } - return buffer; - } -} - -/** \class SList - * \brief A singly-linked list. - * - * A SList!(Value) is a singly linked list of data of type Value. A - * list is similar to a dynamic array except accessing an element in - * the middle or near the end of the list is O(n) and appending to the - * front or back is O(1). Any operation that is not constant-time will - * explicitly have the performance behavior documented. - * - * A singly-linked list differs from a doubly-linked list in the speed - * of accessing elements near the end of the list and the ability to - * <tt>reverse</tt>, <tt>addBefore</tt> iterate <tt>backwards</tt> and - * <tt>remove</tt> a sublist. The only operations supported in the - * middle of a singly-linked list are operations that modify the items - * that follow the sublist. This prevents manipulations in one sublist - * from invalidating an adjacent sublist. - * - * The optional ReadOnly parameter SList!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter SList!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct SList(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias SList ContainerType; - alias SList SliceType; - alias Value ValueType; - alias size_t IndexType; - alias SNode!(Value) Node; - alias ReadOnly isReadOnly; - - const int NodeAllocationBlockSize = 10; // allocate 10 nodes at a time - - // private bug private { - Node* head_; // head_ is first item - Node* tail_; // tail_ is last item - // } - - mixin MCommonSList!(head_, SList ); - - SList getThis(){return *this;} - mixin MListAlgo!(SList, getThis); - - /** Get a ReadOnly view of the container */ - .SList!(Value, true, Alloc) readonly() { - .SList!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .SList!(Value, false, Alloc) readwrite() { - .SList!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (!ReadOnly) { - - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. - */ - void addTail(Value v) { - if (tail_ is null) { - // no available nodes so allocate a new one - tail_ = newNode(); - } else { - tail_ = tail_.next; - } - tail_.data = v; - if (head_ is null) - head_ = tail_; - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. - */ - void addTail(SList v) { - if (v.head_ is null) - return; - tail_.next = v.head_; - tail_ = v.tail_; - if (head_ is null) - head_ = v.head_; - } - - mixin MListCatOperators!(SList); - - /** Prepends an item to the head of the target list. */ - void addHead(Value v) { - if (head_ is null) { - addTail(v); - } else if (tail_.next is null) { - // no available nodes so allocate a new one - Node* t = head_; - head_ = new Node(); - head_.data = v; - head_.next = t; - } else { - // grab available node from end - Node* t = tail_.next; - tail_.next = t.next; - t.next = head_; - head_ = t; - t.data = v; - } - } - - /** Prepends a list to the head of the target list. */ - void addHead(SList v) { - if (v.head_ is null) - return; - Node* t = head_; - head_ = v.head_; - v.tail_.next = t; - if (tail_ is null) - tail_ = v.tail_; - } - - /** Removes and returns the head item of the list. The node that - * contained the item may be reused in future additions to the - * list. To prevent the node from being reused call <tt>trim</tt>. - * If the target list is empty an IndexOutOfBoundsException is thrown - * unless version=MinTLNoIndexChecking is set. - */ - Value takeHead() { - boundsCheck(head_); - Node* v = head_; - head_ = v.next; - // save node for future reuse - v.next = tail_.next; - tail_.next = v; - Value data = v.data; - v.data = Value.init; - return data; - } - - /** Removes the head item of the list. */ - void removeHead() { - boundsCheck(head_); - Node* v = head_; - head_ = v.next; - // save node for future reuse - v.next = tail_.next; - tail_.next = v; - v.data = Value.init; - } - - /** Insert a list after a sub-list. */ - void addAfter(SList subv, SList v) { - if (v.tail_ is null) - return; - Node* t = subv.tail_; - if (t is null) { - *this = v; - return; - } - v.tail_.next = t.next; - t.next = v.head_; - if (t is tail_) - tail_ = v.tail_; - } - - /** Trims off extra nodes that are not actively being used by the - * list but are available for recyling for future add operations. - */ - void trim() { - if (tail_ !is null) - tail_.next = null; - } - - /** Removes n items after a sublist. */ - void removeAfter(SList sublist, size_t n = 1) { - if (sublist.head_ is null) - return; - boundsCheck(head_); - Node* t = sublist.tail_; - Node* newt = t.next; - while (n--) - newt = newt.next; - t.next = newt; - if (newt is tail_) - tail_ = t; - } - - /** Removes items between the tail of a to the head to b (exclusive). */ - void removeBetween(SList a, SList b) { - // what to do if a or b is null? - boundsCheck(head_); - a.tail_.next = b.head_; - } - - /** Set the value of one-item slice (more generally the head value). */ - void value(Value newValue) { - head_.data = newValue; - } - - } // !ReadOnly - - /** Move a sub-list towards the tail by n items. By default moves - * to the next item. - */ - void next(int n = 1, int end = 0) { - while (n-- > 0) { - if (end <= 0) - head_ = head_.next; - if (end >= 0) - tail_ = tail_.next; - } - } - - /** Duplicates a list. */ - .SList!(Value,ReadOnly,Alloc) dup() { - .SList!(Value,false,Alloc) res; - foreach(ValueType val; *this) { - res ~= val; - } - static if (ReadOnly) { - return res.readonly; - } else { - return res; - } - } - - /** Get the value of one-item slice (more generally the head value). - * Useful for expressions like x.tail.value or x.head.value. */ - Value value() { - return head_.data; - } - - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - private Node* newNode() { - static if (is(Alloc == GCAllocator)) { - // allocate a block of nodes and return pointer to first one - Node[] block = new Node[NodeAllocationBlockSize]; - for (int k=1; k<NodeAllocationBlockSize; k++) { - block[k-1].next = &block[k]; - } - return &block[0]; - } else { - // can only allocate one at a time because we have to track each - Node* p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - *p = Node.init; - return p; - } - } - - invariant { - assert( (head_ is null && tail_ is null) || - (head_ !is null && tail_ !is null) ); - } - -} - -/** \class CircularSList - * \brief A circular singly-linked list. - * - * A CircularSList!(Value) is a circular singly linked list of data of type - * Value. A CircularSList differs from an SList in that the tail of the list - * is linked to the head. As a consequence no nodes are saved and - * reused between <tt>add</tt> and <rr>remove</tt> functions and - * slices can be moved forward around the list indefinitely. A CircularSList - * also has a smaller memory footprint since it requires only one - * pointer for the tail instead of two pointers for a tail and head. - * - * The optional ReadOnly parameter CircularSList!(Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter CircularSList!(Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct CircularSList(Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias CircularSList ContainerType; - alias SList!(Value,ReadOnly,Alloc) SliceType; - alias Value ValueType; - alias size_t IndexType; - alias SNode!(Value) Node; - alias ReadOnly isReadOnly; - - private { - Node* tail_; // tail_ is last item - } - - /** Return the circular list as a non-circular SList. */ - SliceType toSList() { - SliceType res; - if (tail_ is null) - return res; - res.head_ = tail_.next; - res.tail_ = tail_; - return res; - } - - /** Get a ReadOnly view of the container */ - .CircularSList!(Value, true, Alloc) readonly() { - .CircularSList!(Value, true, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .CircularSList!(Value, false, Alloc) readwrite() { - .CircularSList!(Value, false, Alloc) res; - res = *cast(typeof(&res))this; - return res; - } - - static if (!ReadOnly) { - - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. - */ - void addTail(Value v) { - Node* n = new Node; - n.data = v; - addNode(n); - tail_ = n; - } - - /** Adds a node after tail. */ - private void addNode(Node* n) { - if (tail_ is null) { - n.next = n; - tail_ = n; - } else { - n.next = tail_.next; - tail_.next = n; - } - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. - */ - void addTail(CircularSList v) { - addHead(v); - tail_ = v.tail_; - } - - mixin MListCatOperators!(CircularSList); - - /** Appends an item to the tail of the list. If the target list is - * a sub-list call addAfter instead of addTail to insert an item - * after a sub-list. - */ - void addHead(Value v) { - Node* n = newNode(); - n.data = v; - addNode(n); - } - - /** Appends a list to the tail of the target list. If the target - * list is a sub-list call addAfter instead of addTail to insert - * another list after a sub-list. - */ - void addHead(CircularSList v) { - if (v.tail_ is null) - return; - if (tail_ is null) { - tail_ = v.tail_; - return; - } - v.tail_.next = tail_.next; - tail_.next = v.tail_; - } - - /** Removes and returns the head item of the list. */ - Value takeHead() { - boundsCheck(tail_); - Node* v = tail_.next; - tail_.next = v.next; - Value val = v.data; - freeNode(v); - return val; - } - - /** Removes the head item of the list. */ - void removeHead() { - boundsCheck(tail_); - Node* v = tail_.next; - tail_.next = v.next; - freeNode(v); - } - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - Node* i = head_; - if (i !is null) - tail_.next = null; - while (i !is null) { - Node* next = i.next; - Alloc.gcFree(i); - i = next; - } - } - *this = CircularSList.init; - } - - /** Insert a list after a sub-list. */ - void addAfter(SliceType subv, SliceType v) { - if (v.tail_ is null) - return; - Node* t = subv.tail_; - if (t is null) { - tail_ = v.tail_; - return; - } - v.tail_.next = t.next; - t.next = v.head_; - if (t is tail_) - tail_ = v.tail_; - } - - /** Removes n items after a sublist. */ - void removeAfter(SliceType sublist, size_t n = 1) { - if (sublist.head_ is null) - return; - boundsCheck(tail_); - Node* t = sublist.tail_; - Node* newt = t.next; - while (n--) { - Node* i = newt; - newt = newt.next; - freeNode(i); - } - t.next = newt; - if (newt is tail_) - tail_ = t; - } - - /** Removes items between the tail of a to the head to b (exclusive). - * If a custom allocator is used the memory is not freed automatically. - */ - void removeBetween(SliceType a, SliceType b) { - // what to do if a or b is null? - boundsCheck(tail_); - a.tail_.next = b.head_; - } - - } // !ReadOnly - - /** Duplicates a list. */ - .CircularSList!(Value,ReadOnly,Alloc) dup() { - .CircularSList!(Value,false,Alloc) res; - foreach(ValueType val; *this) { - res ~= val; - } - static if (ReadOnly) { - return res.readonly; - } else { - return res; - } - } - - /** Rotate the list. */ - void rotate(int n = 1) { - while (n-- > 0) - tail_ = tail_.next; - } - - private Node* head_() { - if (tail_ is null) return null; - return tail_.next; - } - - CircularSList getThis(){return *this;} - mixin MListAlgo!(CircularSList, getThis); - - mixin MCommonSList!(head_, CircularSList ); - - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - - private Node* newNode() { - static if (is(Alloc == GCAllocator)) { - return new Node; - } else { - Node* p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - *p = Node.init; - return p; - } - } - - private void freeNode(Node* n) { - static if (is(Alloc == GCAllocator)) { - } else { - Alloc.gcFree(n); - } - } -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; - -version (MinTLUnittest) { - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.slist unittest\n"); - SList!(int) x; - x.add(3,4); - assert( x[0] == 3 ); - assert( x[1] == 4 ); - assert( x.length == 2 ); - - // test addHead - SList!(int) y; - y.addHead(4); - y.addHead(3); - - // test == - assert( x == y ); - SList!(int) w = x.dup; - w ~= 5; - assert( x != w); - - // test remove - assert( w.takeHead() == 3 ); - w.trim(); - w.addHead(3); - - SList!(int) z = x.dup; - // test foreach iteration - foreach(size_t n, inout int val; z) { - val = n*10; - } - assert( z[0] == 0 ); - assert( z[1] == 10 ); - int n = 0; - foreach(SList!(int) itr; z) { - assert(itr[0] == z[n++]); - } - - // test slicing - SList!(int) v = w[1..3]; - assert( v.length == 2 ); - assert( v[0] == 4 ); - assert( v[1] == 5 ); - - // test algorithms - assert( v.opIn(5) == v.tail ); - assert( v.count(5) == 1 ); - - // test another node type - SList!(char[]) str; - str ~= "hello"; - str ~= "world"; - assert( str[str.length-1] == "world" ); - - // test sub-list spanning - SList!(int) tmp; - int[10] tmp2; - tmp2[3] = 100; - tmp2[8] = 200; - foreach(int xx;tmp2) - tmp ~= xx; - SList!(int) a,b,c; - a = tmp[3..5]; - b = tmp[7..9]; - c = tmp[a..b]; - assert( c.length == 6 ); - assert( c[0] == 100 ); - assert( c[5] == 200 ); - - // CircularSList - - CircularSList!(int) cx; - cx.add(3,4); - assert( cx[0] == 3 ); - assert( cx[1] == 4 ); - assert( cx.length == 2 ); - - // test addHead - CircularSList!(int) cy; - cy.addHead(4); - cy.addHead(3); - - // test == - assert( cx == cy ); - CircularSList!(int) cw = cx.dup; - cw ~= 5; - assert( cx != cw); - - // test remove - assert( cw.takeHead() == 3 ); - cw.addHead(3); - - CircularSList!(int) cz = cx.dup; - // test foreach iteration - foreach(size_t n, inout int val; cz) { - val = n*10; - } - assert( cz[0] == 0 ); - assert( cz[1] == 10 ); - n = 0; - foreach(SList!(int) itr; cz) { - assert(itr[0] == cz[n++]); - } - - // test slicing - SList!(int) cv = cw[1..3]; - assert( cv.length == 2 ); - assert( cv[0] == 4 ); - assert( cv[1] == 5 ); - - // test algorithms - assert( cv.opIn(5) == cv.tail ); - assert( cv.count(5) == 1 ); - - // test another node type - CircularSList!(char[]) cstr; - cstr ~= "hello"; - cstr ~= "world"; - assert( cstr[cstr.length-1] == "world" ); - - // test sub-list spanning - CircularSList!(int) ctmp; - int[10] ctmp2; - ctmp2[3] = 100; - ctmp2[8] = 200; - foreach(int xx; ctmp2) - ctmp ~= xx; - SList!(int) ca,cb,cc; - ca = ctmp[3..5]; - cb = ctmp[7..9]; - cc = ctmp[a..b]; - assert( cc.length == 6 ); - assert( cc[0] == 100 ); - assert( cc[5] == 200 ); - - version (MinTLVerboseUnittest) - printf("finished mintl.slist unittest\n"); - } -} -
--- a/trunk/mintl/sortedaa.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1033 +0,0 @@ -/** \file sortedaa.d - * \brief A sorted associative array. - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * The red-black tree code is by Thomas Niemann. - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 2.7.1 - */ - -module mintl.sortedaa; - -private import mintl.share; // for mixins -import mintl.mem; - -// debug = dSortedAA; // can also pass at command line -//debug(dSortedAA) { -// private import std.stdio; -//} - -/** \class CompareFcnSetException - * \brief An exception thrown when attempting to set the compare - * function twice. In particular it cannot be set on a non-empty - * SortedAA. - */ -class CompareFcnSetException: Exception { - this(char[] str) { super(str); } - this() { super("Cannot set the comparison function twice"); } -} - -/** \class SortedAA - * \brief A sorted associative array. - * - * A SortedAA!(Key,Value) represents a sorted associative array with - * keys of type Key and values of type Value. A sorted associative - * array is similar to a builtin associative array except accessing an - * elements is O(log(n)), where n is the number of elements in the - * array, instead of O(1) and the elements are sorted by key. Any - * operation that is not O(log(n)) will explicitly have the - * performance behavior documented. - * - * The array is sorted by default according to the key's TypeInfo compare - * function. To use a custom key order call the CompareFcn property setter - * with a delegate of the form int delegate(Key* a, Key* b). The comparison - * function cannot be set after any elements are inserted. - * - * The optional ReadOnly parameter SortedAA!(Key,Value,ReadOnly) forbids - * operations that modify the container. The readonly() property returns - * a ReadOnly view of the container. - * - * The optional allocator parameter SortedAA!(Key,Value,false,Allocator) is used - * to allocate and free memory. The GC is the default allocator. - */ -struct SortedAA(Key,Value, bit ReadOnly = false, Alloc = GCAllocator) { - - alias SortedAA ContainerType; - alias SortedAA SliceType; - alias Value ValueType; - alias Key IndexType; - alias ReadOnly isReadOnly; - - /** Get a ReadOnly view of the container */ - .SortedAA!(Key,Value,true) readonly() { - .SortedAA!(Key,Value,true) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get a read-write view of the container */ - .SortedAA!(Key,Value,false) readwrite() { - .SortedAA!(Key,Value,false) res; - res = *cast(typeof(&res))this; - return res; - } - - /** Get the kays in the array. The operation is O(n) where n is the number of - * elements in the array. - */ - Key[] keys() { - Key[] res; - foreach(Key k,Value v;*this) - res ~= k; - return res; - } - - /** Get the values in the array. The operation is O(n) where n is the number of - * elements in the array. - */ - Value[] values() { - Value[] res; - foreach(Key k,Value v;*this) - res ~= v; - return res; - } - - /** Property for the default value of the array when a key is missing. */ - void missing(Value val) { - fixupShared(); - shared.missing = val; - } - Value missing() { - if (!shared) - return Value.init; - return shared.missing; - } - - /** Length of array. The operation is O(n) where n is the number of - * elements in the array. - */ - size_t length() { - size_t len = 0; - foreach(Value val; *this) - len++; - return len; - } - - /** Test if array is empty. */ - bool isEmpty() { - return shared is null || shared.root is null; - } - - static if (ReadOnly) { - - /** Duplicates an array. */ - SortedAA dup() { - .SortedAA!(Key,Value,false) res; - if (shared) { - if (shared.cmpFcn) - res.compareFcn = shared.cmpFcn; - res.missing = missing; - } - foreach(Key k,Value v;*this) - res[k] = v; - return res.readonly; - } - - } else { - - /** Clear all contents. */ - void clear() { - static if (is(Alloc == GCAllocator)) { - } else { - if (shared) { - void freeNode(Node*p) { - if(p) { - freeNode(p.left); - freeNode(p.right); - Alloc.gcFree(p); - } - } - freeNode(shared.root); - Alloc.gcFree(shared); - } - } - *this = SortedAA.init; - } - - /** Remove a key from the array. The target array can be a sub-array though - * the key may fall outside of the sub-array range. The value stored for - * the key is returned, if present. - */ - Value take(Key key) { - // debug(dSortedAA) writefln("getAndRemove: %s",key); - Node* node = getNode(key,NullOnMiss); - if (!node) return missing; - Value value = node.val; - deleteNode(node); - return value; - } - - /** Remove a key from the array. The target array can be a sub-array though - * the key may fall outside of the sub-array range. - */ - void remove(Key key) { - // debug(dSortedAA) writefln("remove: %s",key); - deleteNode(getNode(key,NullOnMiss)); - } - - /** Remove a sub-array from the array. The operation is O(max(log(m),n)) - * where m is the size of the target array and n is the number of - * elements in the sub-array. - */ - void remove(SortedAA subarray) { - if (subarray.head_ is subarray.tail_) { - deleteNode(subarray.head_); - } else { - Key[] keylist = subarray.keys; - foreach(Key key;keylist) - remove(key); - } - } - - /** Duplicates an array. */ - SortedAA dup() { - SortedAA res; - if (shared) { - if (shared.cmpFcn) - res.compareFcn = shared.cmpFcn; - res.missing = missing; - } - foreach(Key k,Value v;*this) - res[k] = v; - return res; - } - - } // !ReadOnly - - /** signature for a custom comparison function */ - alias int delegate(Key* a, Key* b) CompareFcn; - - /** Set custom comparison function. If the array is non-empty or the - * comparison function has already been set a CompareFcnSetException - * is thrown. - */ - void compareFcn(CompareFcn cmp) { - allocShared(); - if (shared.cmpFcn !is null) - throw new CompareFcnSetException(); - else - shared.cmpFcn = cmp; - } - - /** Find (and insert if not present) the element with a given key - * and return the value. The target array can be a sub-array though - * the key may fall outside of the sub-array range. - */ - Value opIndex(Key key) { - Node* t = getNode(key,NullOnMiss); - if (t) - return t.val; - else - return missing; - } - - /** Store a value with a key, overwriting any previous value. The - * target array can be a sub-array though the key may fall outside of the - * sub-array range. - */ - void opIndexAssign(Value val, Key key) { - Node* t = getNode(key,InsertOnMiss); - t.val = val; - } - - /** Returns the value of the first item of a slice. In particular gets - * the value of a one-item slice. - */ - Value value() { - if (head_ is null && tail_ is null) - return Value.init; - return head_.val; - } - - /** Returns the key of the first item of a slice. In particular gets - * the key of a one-item slice. - */ - Key key() { - if (head_ is null && tail_ is null) - return Key.init; - return head_.key; - } - - /** Return the start of the sorted items (the min). */ - SortedAA head() { - Node* node = head_ is null ? minNode() : head_; - SortedAA res; - res.shared = shared; - res.head_ = res.tail_ = node; - return res; - } - - /** Return the end of the sorted items (the max). */ - SortedAA tail() { - Node* node = tail_ is null ? maxNode() : tail_; - SortedAA res; - res.shared = shared; - res.head_ = res.tail_ = node; - return res; - } - - /** Return a one-item slice of the item less than key */ - SortedAA to(Key key) { - SortedAA res; - res.shared = shared; - res.head_ = res.tail_ = lookupSide(key,false); - return res; - } - - /** Return a one-item slice of the item greater than or equal to key */ - SortedAA from(Key key) { - SortedAA res; - res.shared = shared; - res.head_ = res.tail_ = lookupSide(key,true); - return res; - } - - /** Move a slice towards the head or tail by n items. If n is - * negative the slice moves towards the head. A positive end is - * the tail, negative the head and 0 is both. By default moves to - * the next item. - */ - void next(int n = 1, int end = 0) { - void doNext(inout Node* node, int m) { - while (m--) - node = nextNode(node); - } - void doPrev(inout Node* node, int m) { - while (m--) - node = prevNode(node); - } - if (n > 0) { - if (end >= 0) - doNext(tail_,n); - if (end <= 0) - doNext(head_,n); - } else { - n = -n; - if (end >= 0) - doPrev(tail_,n); - if (end <= 0) - doPrev(head_,n); - } - } - - /** Find the element with a given key and return a pointer to the - * value. If the key is not in the array null is returned or if - * throwOnMiss is true an exception is thrown. The target array can - * be a sub-array though the key may fall outside of the sub-array - * range. - */ - Value* get(Key key, bool throwOnMiss = false) { - Node* t = getNode(key,throwOnMiss ? ThrowOnMiss : NullOnMiss); - if (t) - return &t.val; - else - return null; - } - - /** Find a key in the array and return a pointer to the associated value. - * Insert the key and initialize with Value.init if the key is not - * in the array. - */ - Value* put(Key key) { - Node* t = getNode(key, InsertOnMiss); - return &t.val; - } - - /** Create a slice from the head of a to the tail in b (inclusive). */ - SortedAA opSlice(SortedAA a, SortedAA b) { - SortedAA res; - res.head_ = a.head_ is null ? minNode() : a.head_; - res.tail_ = b.tail_ is null ? maxNode() : b.tail_; - res.shared = shared; - return res; - } - - /** Create a sub-array from key a to b (exclusive). */ - SortedAA opSlice(Key a, Key b) { - return (*this)[from(a) .. to(b)]; - } - - /** Create a sub-array from slice a to key b (exclusive). */ - SortedAA opSlice(SortedAA a, Key b) { - return (*this)[a .. to(b)]; - } - /** Create a sub-array from key a to slice b (inclusive). */ - SortedAA opSlice(Key a, SortedAA b) { - return (*this)[from(a) .. b]; - } - - /** Test for equality of two arrays. The operation is O(n) where n - * is length of the array. - */ - int opEquals(SortedAA c) { - fixupShared(); - c.fixupShared(); - Node* i = head_ ? head_ : minNode(); - Node* j = c.head_ ? c.head_ : c.minNode(); - Node* end = tail_ ? tail_ : maxNode(); - Node* cend = c.tail_ ? c.tail_ : c.maxNode(); - TypeInfo ti_k = typeid(Key); - TypeInfo ti_v = typeid(Value); - int do_test(Node*p1,Node*p2) { - if (p1 is null && p2 is null) - return 1; - if ((p1 is null && p2 !is null) || - (p1 !is null && p2 is null)) - return 0; - if (!ti_k.equals(&p1.key,&p2.key)) - return 0; - if (!ti_v.equals(&p1.val,&p2.val)) - return 0; - return 1; - } - while (i !is end && j !is cend) { - if (!do_test(i,j)) - return 0; - i = nextNode(i); - j = c.nextNode(j); - } - return do_test(i,j); - } - - /** Test if a key is in the array. The target array can be a sub-array - * but the key may fall outside of the sub-array range. - */ - bool contains(Key key) { - Value* node = get(key); - return node !is null; - } - - /** Test if a key is in the array and set value if it is. */ - bool contains(Key key,out Value value) { - Value* node = get(key); - if (node) - value = *node; - return node !is null; - } - - /** Iterate over the array calling delegate to perform an action. - * The value is passed to the delegate. - */ - int opApplyNoKeyStep(int delegate(inout Value val) dg, int step=1) { - int dg2(inout SortedAA itr) { - Value value = itr.value; - return dg(value); - } - return opApplyIterStep(&dg2,step); - } - - /** Iterate over the array calling delegate to perform an action. - * The key and value are passed to the delegate. - */ - int opApplyWithKeyStep(int delegate(inout Key key, inout Value val) dg, - int step = 1) { - int dg2(inout SortedAA itr) { - Key key = itr.key; - Value value = itr.value; - return dg(key,value); - } - return opApplyIterStep(&dg2,step); - } - - /** Iterate over the array calling delegate to perform an action. A - * one-element sub-array is passed to the delegate. - */ - int opApplyIterStep(int delegate(inout SortedAA itr) dg,int step=1) { - SortedAA itr; - itr = *this; - int res; - if (shared is null) return 0; - Node* i = head_ ? head_ : minNode(); - Node* j = tail_ ? tail_ : maxNode(); - Node* x = step>0?i:j; - Node* end = step>0?j:i; - while (x !is null) { - itr.head_ = itr.tail_ = x; - res = dg(itr); - if (res || x is end) return res; - x = step>0?nextNode(x):prevNode(x); - } - return res; - } - - /** Iterate backwards over the array (from last to first key). This - * should only be called as the iteration parameter in a - * <tt>foreach</tt> statement - */ - SortedAAReverseIter!(Key,Value,ReadOnly,Alloc) backwards() { - SortedAAReverseIter!(Key,Value,ReadOnly,Alloc) res; - res.list = this; - return res; - } - - /** Helper functions for opApply */ - mixin MOpApplyImpl!(SortedAA); - alias opApplyNoKey opApply; - alias opApplyWithKey opApply; - alias opApplyIter opApply; - mixin MAddAA!(SortedAA); // mixin add function - - // End of public interface - - private { - enum Color:int { Red, Black } - // share some data between array and sub-arrays to make updating - // easier and shrink the SortedAA footprint. - struct SharedArrayData { - Node* root; - CompareFcn cmpFcn; - Value missing; - Node* freelist; - } - struct Node { - Node* left, right, parent; - Color color; - Key key; - Value val; - } - SharedArrayData *shared; - Node* head_, tail_; - } - - debug(dSortedAA) { - private void dumpTree(Node* x, char[] str,int indent) { - if (x !is null) { - int n = indent; - while (n--) printf(" "); - printf("%.*s %p: %d %.*s\n",str,x,x.color,x.key); - dumpTree(x.left,"left",indent+1); - dumpTree(x.right,"right",indent+1); - } - } - } - - // lookup the smallest item greater than or equal to key (from) - // or lookup the largest item less than key - Node* lookupSide(Key key, bool from) { - Node* current; - Node* parent; - fixupShared(); - current = shared.root; - parent = current; - int cmpVal = 0; - CompareFcn cmp = shared.cmpFcn; - while (current !is null) { - cmpVal = cmp(&key,¤t.key); - if (cmpVal == 0) { - return from?current:prevNode(current); - } - parent = current; - current = cmpVal < 0 ? current.left : current.right; - } - if (!parent) throw new Exception("Invalid Index"); - if (from) - return cmpVal<0?prevNode(parent):parent; - else - return cmpVal>0?nextNode(parent):parent; - } - - // initialize shared data if null - private void allocShared() { - if (shared is null) { - static if (is(Alloc == GCAllocator)) { - shared = new SharedArrayData; - } else { - shared = cast(SharedArrayData*)Alloc.gcMalloc(SharedArrayData.sizeof); - *shared = SharedArrayData.init; - } - } - } - - // initialize shared data if null and initialize cmpFcn - private void fixupShared() { - allocShared(); - if (shared.cmpFcn is null) { - TypeInfo ti = typeid(Key); - shared.cmpFcn = cast(CompareFcn)&ti.compare; - } - } - - // return the next largest node or null if none - // used when we can't traverse the whole tree - private Node* nextNode(Node* x) { - if (x.right !is null) { - x = x.right; - while (x.left != null) x = x.left; - } else { - while (x.parent !is null && x.parent.right == x) - x = x.parent; - if (x.parent !is null && x.parent.left == x) - x = x.parent; - else - x = null; - } - return x; - } - - // return the previous node or null if none - // used when we can't traverse the whole tree - private Node* prevNode(Node* x) { - if (x.left !is null) { - x = x.left; - while (x.right != null) x = x.right; - } else { - while (x.parent !is null && x.parent.left == x) - x = x.parent; - if (x.parent !is null && x.parent.right == x) - x = x.parent; - else - x = null; - } - return x; - } - - // fixup Red-Black invariant - private void rotateLeft(Node* x) { - Node* y = x.right; - assert( y !is null ); - x.right = y.left; - if (y.left !is null) - y.left.parent = x; - y.parent = x.parent; - if (x.parent !is null) { - if (x is x.parent.left) - x.parent.left = y; - else - x.parent.right = y; - } else { - shared.root = y; - } - y.left = x; - if (x !is null) x.parent = y; - } - - // fixup Red-Black invariant - private void rotateRight(Node* x) { - Node* y = x.left; - assert( y !is null ); - x.left = y.right; - if (y.right !is null) - y.right.parent = x; - y.parent = x.parent; - if (x.parent !is null) { - if (x is x.parent.right) - x.parent.right = y; - else - x.parent.left = y; - } else { - shared.root = y; - } - y.right = x; - if (x !is null) x.parent = y; - } - - // fixup Red-Black invariant after an insert - private void insertFixup(Node* x) { - Node* root = shared.root; - while (x !is root && x.parent.color == Color.Red) { - debug(dSortedAA) printf("fixing up parent %p\n",x.parent); - if (x.parent is x.parent.parent.left) { - Node* y = x.parent.parent.right; - if (y !is null && y.color == Color.Red) { - x.parent.color = Color.Black; - y.color = Color.Black; - x.parent.parent.color = Color.Red; - x = x.parent.parent; - } else { - if (x is x.parent.right) { - x = x.parent; - debug(dSortedAA) printf("rotating left %p\n",x); - rotateLeft(x); - } - x.parent.color = Color.Black; - x.parent.parent.color = Color.Red; - debug(dSortedAA) printf("rotating right1 %s\n",x.parent.parent); - rotateRight(x.parent.parent); - } - } else { - Node* y = x.parent.parent.left; - if (y !is null && y.color == Color.Red) { - x.parent.color = Color.Black; - y.color = Color.Black; - x.parent.parent.color = Color.Red; - x = x.parent.parent; - } else { - if (x is x.parent.left) { - x = x.parent; - debug(dSortedAA) printf("rotating right %p\n",x); - rotateRight(x); - } - x.parent.color = Color.Black; - x.parent.parent.color = Color.Red; - debug(dSortedAA) printf("rotating left1 %p\n",x.parent.parent); - rotateLeft(x.parent.parent); - } - } - } - while (x.parent !is null) - x = x.parent; - x.color = Color.Black; - } - - private enum {InsertOnMiss, ThrowOnMiss, NullOnMiss} - - // returns node for a given key - even if the key is ouside the - // sub-array. - private Node* getNode(Key key, int failureAction) { - // debug(dSortedAA) writefln("lookup %s",key); - Node* current; - fixupShared(); - current = shared.root; - Node* parent = null; - int cmpVal = 0; - CompareFcn cmp = shared.cmpFcn; - while (current !is null) { - cmpVal = cmp(&key,¤t.key); - // debug(dSortedAA) writefln("comparing %s %s got %s",key,current.key,cmpVal); - if (cmpVal == 0) return current; - parent = current; - current = cmpVal < 0 ? current.left : current.right; - } - switch (failureAction) { - case NullOnMiss: return null; - case ThrowOnMiss: throw new IndexOutOfBoundsException("Key not in container"); - case InsertOnMiss: return insertNode(key, Value.init, parent, cmpVal); - } - } - - // remove extra capacity - void trim() { - if (shared) - shared.freelist = null; - } - - // Parameters for controlling block allocations - private const int NodeAllocBlockSize = 10; // number of nodes in block - private const int AllocBlockCutoff = 96; // max node size to allow blocks - - // helper function to allocate a node - private Node* newNode() { - static if (is(Alloc == GCAllocator)) { - static if (Node.sizeof > AllocBlockCutoff) { - return new Node; - } else { - if (shared.freelist) { - Node* t = shared.freelist; - shared.freelist = t.left; - t.left = null; - return t; - } - Node[] block = new Node[NodeAllocBlockSize]; - for(int k=1;k<NodeAllocBlockSize-1;k++) - block[k].left = &block[k+1]; - shared.freelist = &block[1]; - return &block[0]; - } - } else { - Node* p = cast(Node*)Alloc.gcMalloc(Node.sizeof); - *p = Node.init; - return p; - } - } - - // insert and return new node at the given parent - private Node* insertNode(Key key, Value data, - Node* parent, int cmpVal) { - Node* x = newNode; - x.key = key; - x.val = data; - x.parent = parent; - x.color = Color.Red; - if (parent !is null) { - if (cmpVal < 0) { - parent.left = x; - } else { - parent.right = x; - } - } else { - shared.root = x; - } - insertFixup(x); - return x; - } - - // fixup Red-Black invariant after a delete - private void deleteFixup(Node* x) { - Node* root = shared.root; - while (x !is root && x.color == Color.Black) { - if (x is x.parent.left) { - Node* w = x.parent.right; - if (w !is null && w.color == Color.Red) { - w.color = Color.Black; - x.parent.color = Color.Red; - rotateLeft(x.parent); - w = x.parent.right; - } - assert( w !is null ); - if ((w.left is null || w.left.color == Color.Black) && - (w.right is null || w.right.color == Color.Black)) { - w.color = Color.Red; - x = x.parent; - } else { - if (w.right is null || w.right.color == Color.Black) { - w.left.color = Color.Black; - w.color = Color.Red; - rotateRight(w); - w = x.parent.right; - } - w.color = x.parent.color; - x.parent.color = Color.Black; - w.right.color = Color.Black; - rotateLeft(x.parent); - x = root; - } - } else { - Node* w = x.parent.left; - assert( w !is null ); - if (w.color == Color.Red) { - w.color = Color.Black; - x.parent.color = Color.Red; - rotateRight(x.parent); - w = x.parent.left; - } - assert( w !is null ); - if ((w.left is null || w.left.color == Color.Black) && - (w.right is null || w.right.color == Color.Black)) { - w.color = Color.Red; - x = x.parent; - } else { - if (w.left is null || w.left.color == Color.Black) { - w.right.color = Color.Black; - w.color = Color.Red; - rotateLeft(w); - w = x.parent.left; - } - w.color = x.parent.color; - x.parent.color = Color.Black; - w.left.color = Color.Black; - rotateRight(x.parent); - x = root; - } - } - } - x.color = Color.Black; - } - - // get the miminum element of the array - private Node* minNode() { - Node* x = shared.root; - while (x !is null && x.left !is null) { - x = x.left; - } - return x; - } - - // get the maximum element of the array - private Node* maxNode() { - Node* x = shared.root; - while (x !is null && x.right !is null) { - x = x.right; - } - return x; - } - - // deletes a node from the array. - // This routine should probably not copy node contents around to be - // nice to other sub-arrays. Instead copy around pointers to parents - // and children. - private void deleteNode(Node* z) { - Node* x,y; - if (z is null) - return; - debug(dSortedAA) printf("zleft %p right %p\n",z.left,z.right); - if (z.left is null || z.right is null) { - y = z; - } else { - y = z.right; - while (y.left !is null) { - y = y.left; - } - } - debug(dSortedAA) printf("y.left %p y right %p\n",y.left,y.right); - if (y.left !is null) - x = y.left; - else - x = y.right; - bool useTempX = x is null; - Node tempX; - if (useTempX) { - debug(dSortedAA) printf("allocating tmpxnode\n"); - x = &tempX; - x.color = Color.Black; - } - x.parent = y.parent; - if (y.parent !is null) { - if (y is y.parent.left) - y.parent.left = x; - else - y.parent.right = x; - } else { - shared.root = x; - } - if (y !is z) { - debug(dSortedAA) printf("swapping %p with %p\n",y,z); - z.key = y.key; - z.val = y.val; - } - if (y.color == Color.Black) { - deleteFixup(x); - } - if (useTempX) { - // replace temporary "NIL" with nulls - if (x is shared.root) - shared.root = null; - else if (x is x.parent.left) - x.parent.left = null; - else if (x is x.parent.right) - x.parent.right = null; - } - static if (is(Alloc == GCAllocator)) { - static if (Node.sizeof <= AllocBlockCutoff) { - *y = Node.init; - y.left = shared.freelist; - shared.freelist = y; - } - } else { - Alloc.gcFree(y); - } - } -} - -// helper structure for backwards() -struct SortedAAReverseIter(Key,Value, bit ReadOnly, Alloc) { - mixin MReverseImpl!(SortedAA!(Key,Value,ReadOnly,Alloc)); -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; - -version (MinTLUnittest) { - private import std.random; - private import std.string; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.sortedaa unittest\n"); - - SortedAA!(int,int) m; - m[4] = 100; - //private bug - // assert( m.shared.root !is null ); - // assert( m.shared.root.val == 100 ); - for (int k=1; k<1000; k++) { - int key = std.random.rand()%30; - if (m.contains(key)) - m.remove(key); - else - m[key] = 1; - } - SortedAA!(char[],char[]) m2; - for (int k=1; k<1000; k++) { - int key = rand()%300; - m2[toString(key)] = toString(key); - } - char[] prev; - foreach(char[] val; m2) { - assert( val > prev ); - prev = val; - } - /* private bug - SortedAA!(char[],char[]) m5 = m2; - m5.head_ = m5.minNode(); - m5.tail_ = m5.maxNode(); - prev = ""; - foreach(char[] val; m5) { - assert( val > prev ); - prev = val; - } - prev = m5.maxNode().val; - foreach(char[] val; m5.backwards()) { - assert( val <= prev ); - prev = val; - } - */ - SortedAA!(int,int) m3; - m3.compareFcn = delegate int(int* a, int* b) { - return *a-*b; - }; - m3[10] = -100; - m3[7] = 100; - m3[-10] = 200; - assert( m3.length == 3); - assert( m3[7] == 100 ); - assert( m3[-10] == 200 ); - assert( m3[10] == -100 ); - - SortedAA!(int,int) mm; - mm.add(10,-100, 7,100, -10,200); - assert( m3 == mm ); - - SortedAA!(int,int) m3a = m3.dup; - assert( m3a == m3 ); - assert( m3a !is m3 ); - assert( m3a.length == 3); - assert( m3a[7] == 100 ); - assert( m3a[-10] == 200 ); - assert( m3a[10] == -100 ); - - m3.remove(7); - m3.remove(10); - m3.remove(-10); - // assert( m3.shared.root is null ); - - int[] keys = m3a.keys; - assert( keys[0] == -10 ); - assert( keys[1] == 7 ); - assert( keys[2] == 10 ); - - // test slicing - SortedAA!(char[],int) m8 = - SortedAA!(char[],int).make("a",100,"c",300,"d",400,"b",200, - "f",600,"e",500); - SortedAA!(char[],int) msl,msl2,msl3; - // debug(dSortedAA) m8.dumpTree(m8.shared.root,"",0); - msl = m8["b".."d"]; - msl2 = m8[m8.from("b123") .. m8.to("e")]; - assert( msl.length == 2 ); - // assert( msl.head_.key == "b" ); - // assert( msl.tail_.key == "c" ); - msl2 = m8["c".."f"]; - assert( msl2.length == 3 ); - // assert( msl2.head_.key == "c" ); - // assert( msl2.tail_.key == "e" ); - msl3 = m8[msl..msl2]; - assert( msl3.length == 4 ); - // assert( msl3.head_.key == "b" ); - // assert( msl3.tail_.key == "e" ); - m8.remove(msl2); - assert( m8.length == 3 ); - debug(dSortedAA) printf("\nsize %d\n",m8.sizeof); - - SortedAA!(int,int,false,MallocNoRoots) mal; - mal[10] = 20; - mal[30] = 50; - assert( mal[10] == 20 ); - assert( mal[30] == 50 ); - mal.clear(); - assert( mal.isEmpty ); - - version (MinTLVerboseUnittest) - printf("starting mintl.sortedaa unittest\n"); - } -}
--- a/trunk/mintl/sorting.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/** \file sorting.d - * \brief Mixins for sorting random-access and sequential-access containers - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 1.0 - */ - -module mintl.sorting; - -// mixin for sorting random-access containers -// quicksort with insertion sort for short lists -template MRandomAccessSort(Container, alias list) { - void sort(int delegate(Container.ValueType* l, Container.ValueType* r) cmp = null) { - void swap(Container.ValueType* t1, Container.ValueType* t2 ) { - Container.ValueType t = *t1; *t1 = *t2; *t2 = t; - } - void insertionSort(Container data) { - size_t i = 1; - while(i < data.length) { - size_t j = i; - Container.ValueType* jp = data.lookup(j); - Container.ValueType* j1p; - while (j > 0 && cmp((j1p=data.lookup(j-1)),jp) > 0) { - swap(j1p,jp); - --j; - jp = j1p; - } - i++; - } - } - void dosort(Container data) { - if (data.length < 2) { - return; - } else if (data.length < 8) { - insertionSort(data); - return; - } - size_t tail = data.length-1; - size_t p = 1; - size_t q = tail; - Container.ValueType* headptr = data.lookup(0); - Container.ValueType* pptr = data.lookup(p); - Container.ValueType* qptr = data.lookup(q); - swap(headptr,data.lookup(data.length/2)); - if (cmp(pptr,qptr) > 0) swap(pptr,qptr); - if (cmp(headptr,qptr) > 0) swap(headptr,qptr); - if (cmp(pptr,headptr) > 0) swap(pptr,headptr); - while (1) { - do p++; while (cmp(data.lookup(p), headptr) < 0); - do q--; while (cmp(data.lookup(q), headptr) > 0); - if (p > q) break; - swap(data.lookup(p),data.lookup(q)); - } - swap(headptr,data.lookup(q)); - if (0 < q) - dosort(data[0 .. q+1]); - if (p < tail) - dosort(data[p .. tail+1]); - } - TypeInfo ti = typeid(Container.ValueType); - if (cmp is null) { - cmp = cast(typeof(cmp))&ti.compare; - } - dosort(list); - } -} - -// mixin for sorting sequential-access containers -// using mergesort customized for doublly-linked lists -// TODO: allow singly-linked lists, too -template MSequentialSort(Container, alias head_, alias tail_) { - void dosort(out Container.Node* newhead, - out Container.Node* newtail, - int delegate(Container.SortType* l, Container.SortType* r) cmp = null) { - void link(Container.Node* a, Container.Node* b) { - if (a) a.next = b; - if (b) b.prev = a; - } - if (cmp is null) { - TypeInfo ti = typeid(Container.SortType); - cmp = cast(typeof(cmp))&ti.compare; - } - Container.Node* head = head_; - Container.Node* tail = tail_; - Container.Node* headprev = head.prev; - Container.Node* i,j,e,itail; - i = tail; - tail = tail.next; // one past tail - i.next = null; - int depth; - size_t ilen, jlen, len = 1; - while (1) { - i = head; - depth = 0; - itail = null; - head = null; - while (i) { - depth++; - j = i; - ilen = 0; - for (size_t k = 0; k < len; k++) { - ilen++; - j = j.next; - if (!j) break; - } - jlen = len; - while (ilen > 0 || (jlen > 0 && j)) { - if (ilen == 0) { - e = j; j = j.next; jlen--; - } else if (jlen == 0 || !j || - cmp(i.sortLookup(),j.sortLookup()) <= 0) { - e = i; i = i.next; ilen--; - } else { - e = j; j = j.next; jlen--; - } - if (itail) { - link(itail,e); - } else { - head = e; - } - itail = e; - } - i = j; - } - itail.next = null; - if (depth <= 1) { - link(itail,tail); - newtail = itail; - link(headprev,head); - newhead = head; - return; - } - len *= 2; - } - } -}
--- a/trunk/mintl/stack.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/** \file stack.d - * \brief A stack container - * - * Written by Ben Hinkle and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - * Email comments and bug reports to ben.hinkle@gmail.com - * - * revision 1.1 - */ - -module mintl.stack; - -private import mintl.deque; -private import mintl.arraylist; -import mintl.adapter; -import mintl.share; -import mintl.mem; - -/** A stack of items of stype Value backed by a container of type ImplType. - * Aliases push and pop allow stack operations. By default the stack is - * backed by a Deque. - */ -struct Stack(Value, ImplType = Deque!(Value)) { - - alias Stack ContainerType; - alias Value ValueType; - alias size_t IndexType; - alias ImplType AdaptType; - const bit isReadOnly = ImplType.isReadOnly; - - ImplType impl; - - mixin MAdaptBuiltin!(impl,Stack); - mixin MAdaptBasic!(impl,Stack); - mixin MAdaptList!(impl,Stack); - mixin MListCatOperators!(Stack); - - // Stack specific - static if (!ImplType.isReadOnly) { - alias add push; - alias takeTail pop; - } - Value peek() { - ImplType last = impl.tail; - return last.isEmpty ? Value.init : last[0]; - } -} - -/** Convenience alias for a stack backed by an array */ -template ArrayStack(Value) { - alias Stack!(Value,ArrayList!(Value)) ArrayStack; -} - -//version = MinTLVerboseUnittest; -//version = MinTLUnittest; - -version (MinTLUnittest) { - import mintl.list; - unittest { - version (MinTLVerboseUnittest) - printf("starting mintl.stack unittest\n"); - Stack!(int) st; - st.push(10, 20); - assert( st.peek == 20 ); - assert( st.pop == 20 ); - assert( st[st.length - 1] == 10 ); - assert( st.pop == 10 ); - assert( st.length == 0 ); - - ArrayStack!(int) st2; - st2.push(10); - st2 ~= 20; - assert( st2.peek == 20 ); - assert( st2.pop == 20 ); - assert( st2[st2.length - 1] == 10 ); - assert( st2.pop == 10 ); - assert( st2.length == 0 ); - - Stack!(int,List!(int)) st3; - st3.push(10); - st3 ~= 20; - assert( st3.peek == 20 ); - assert( st3.pop == 20 ); - assert( st3[st3.length - 1] == 10 ); - assert( st3.pop == 10 ); - assert( st3.length == 0 ); - - version (MinTLVerboseUnittest) - printf("finished mintl.stack unittest\n"); - } -}
--- a/trunk/mintl/unittest.d Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - -import mintl.all; - -int main() { - return 0; -}
--- a/trunk/mintl/win32.mak Tue May 06 21:43:55 2008 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ - -# To build mintl.lib type -# make -f win32.mak DFLAGS=-g LIBNAME=mintl_debug.lib -# or -# make -f win32.mak DFLAGS=-release LIBNAME=mintl.lib -# The mintl.lib and object files will be created in the source directory. - -# flags to use building unittest.exe -DUNITFLAGS=-g -v -unittest -I.. -version=MinTLUnittest -version=MinTLVerboseUnittest - -# flags to use when building the mintl.lib library -DLIBFLAGS=$(DFLAGS) -release -I.. - -DMD = dmd -LIB = lib - -targets : unittest - -unittest : unittest.exe - -LIBNAME = mintl.lib - -#mintl : $(LIBNAME) - -SRC = all.d \ - array.d \ - arraylist.d \ - arrayheap.d \ - deque.d \ - hashaa.d \ - list.d \ - slist.d \ - share.d \ - adapter.d \ - stack.d \ - queue.d \ - set.d \ - multiaa.d \ - mem.d \ - sorting.d \ - sortedaa.d - -OBJS = all.obj \ - array.obj \ - arraylist.obj \ - arrayheap.obj \ - deque.obj \ - hashaa.obj \ - list.obj \ - slist.obj \ - share.obj \ - adapter.obj \ - stack.obj \ - queue.obj \ - set.obj \ - multiaa.obj \ - mem.obj \ - sorting.obj \ - sortedaa.obj - -.d.obj : - $(DMD) -c $(DLIBFLAGS) -of$@ $< - -$(LIBNAME) : $(OBJS) $(SRC) - $(LIB) -c $@ $(OBJS) - - -unittest.exe : $(LIBNAME) $(SRC) - $(DMD) $(DUNITFLAGS) unittest.d -ofunittest.exe $(SRC) - -clean: - del *.obj - del $(LIBNAME) - IF EXIST unittest.exe del unittest.exe