diff --git a/mak/MANIFEST b/mak/MANIFEST
index 79fd9ca48ba..f3353cb7701 100644
--- a/mak/MANIFEST
+++ b/mak/MANIFEST
@@ -244,9 +244,13 @@ MANIFEST=\
src\rt\typeinfo\ti_wchar.d \
\
src\rt\util\array.d \
- src\rt\util\container.d \
src\rt\util\hash.d \
+ src\rt\util\random.d \
src\rt\util\string.d \
src\rt\util\utf.d \
+ src\rt\util\container\array.d \
+ src\rt\util\container\common.d \
+ src\rt\util\container\hashtab.d \
+ src\rt\util\container\treap.d \
\
src\etc\linux\memoryerror.d
diff --git a/mak/SRCS b/mak/SRCS
index b259b4c396e..a84dcfe7763 100644
--- a/mak/SRCS
+++ b/mak/SRCS
@@ -112,10 +112,14 @@ SRCS=\
src\rt\trace.d \
\
src\rt\util\array.d \
- src\rt\util\container.d \
src\rt\util\hash.d \
+ src\rt\util\random.d \
src\rt\util\string.d \
src\rt\util\utf.d \
+ src\rt\util\container\array.d \
+ src\rt\util\container\common.d \
+ src\rt\util\container\hashtab.d \
+ src\rt\util\container\treap.d \
\
src\rt\typeinfo\ti_AC.d \
src\rt\typeinfo\ti_Acdouble.d \
diff --git a/src/gc/gc.d b/src/gc/gc.d
index bca87f8e5b0..fab7d2a2823 100644
--- a/src/gc/gc.d
+++ b/src/gc/gc.d
@@ -39,6 +39,8 @@ import gc.bits;
import gc.stats;
import gc.os;
+import rt.util.container.treap;
+
import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
import core.stdc.string : memcpy, memset, memmove;
import core.bitop;
@@ -1095,10 +1097,10 @@ class GC
/**
*
*/
- @property int delegate(int delegate(ref void*)) rootIter()
+ @property auto rootIter()
{
gcLock.lock();
- auto rc = &gcx.rootIter;
+ auto rc = &gcx.roots.opApply;
gcLock.unlock();
return rc;
}
@@ -1152,10 +1154,10 @@ class GC
/**
*
*/
- @property int delegate(int delegate(ref Range)) rangeIter()
+ @property auto rangeIter()
{
gcLock.lock();
- auto rc = &gcx.rangeIter;
+ auto rc = &gcx.ranges.opApply;
gcLock.unlock();
return rc;
}
@@ -1321,6 +1323,13 @@ struct Range
{
void *pbot;
void *ptop;
+ alias pbot this; // only consider pbot for relative ordering (opCmp)
+}
+
+struct Root
+{
+ void *proot;
+ alias proot this;
}
@@ -1338,13 +1347,8 @@ struct Gcx
void *cached_info_key;
BlkInfo cached_info_val;
- size_t nroots;
- size_t rootdim;
- void **roots;
-
- size_t nranges;
- size_t rangedim;
- Range *ranges;
+ Treap!Root roots;
+ Treap!Range ranges;
uint noStack; // !=0 means don't scan stack
uint log; // turn on logging
@@ -1367,6 +1371,8 @@ struct Gcx
(cast(byte*)&this)[0 .. Gcx.sizeof] = 0;
log_init();
+ roots.initialize();
+ ranges.initialize();
//printf("gcx = %p, self = %x\n", &this, self);
inited = 1;
}
@@ -1403,11 +1409,8 @@ struct Gcx
pooltable = null;
}
- if (roots)
- cstdlib.free(roots);
-
- if (ranges)
- cstdlib.free(ranges);
+ roots.removeAll();
+ ranges.removeAll();
}
@@ -1438,24 +1441,15 @@ struct Gcx
}
}
- if (roots)
- {
- assert(rootdim != 0);
- assert(nroots <= rootdim);
- }
-
- if (ranges)
- {
- assert(rangedim != 0);
- assert(nranges <= rangedim);
-
- for (size_t i = 0; i < nranges; i++)
- {
- assert(ranges[i].pbot);
- assert(ranges[i].ptop);
- assert(ranges[i].pbot <= ranges[i].ptop);
+ // @@@BUG12739@@@
+ ranges.opApply(
+ (ref Range range) {
+ assert(range.pbot);
+ assert(range.ptop);
+ assert(range.pbot <= range.ptop);
+ return 0;
}
- }
+ );
for (size_t i = 0; i < B_PAGE; i++)
{
@@ -1472,23 +1466,7 @@ struct Gcx
*/
void addRoot(void *p) nothrow
{
- if (nroots == rootdim)
- {
- size_t newdim = rootdim * 2 + 16;
- void** newroots;
-
- newroots = cast(void**)cstdlib.malloc(newdim * newroots[0].sizeof);
- if (!newroots)
- onOutOfMemoryError();
- if (roots)
- { memcpy(newroots, roots, nroots * newroots[0].sizeof);
- cstdlib.free(roots);
- }
- roots = newroots;
- rootdim = newdim;
- }
- roots[nroots] = p;
- nroots++;
+ roots.insert(Root(p));
}
@@ -1497,32 +1475,7 @@ struct Gcx
*/
void removeRoot(void *p) nothrow
{
- for (size_t i = nroots; i--;)
- {
- if (roots[i] == p)
- {
- nroots--;
- memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
- return;
- }
- }
- assert(0);
- }
-
-
- /**
- *
- */
- int rootIter(int delegate(ref void*) dg)
- {
- int result = 0;
- for (size_t i = 0; i < nroots; ++i)
- {
- result = dg(roots[i]);
- if (result)
- break;
- }
- return result;
+ roots.remove(Root(p));
}
@@ -1532,25 +1485,8 @@ struct Gcx
void addRange(void *pbot, void *ptop) nothrow
{
//debug(PRINTF) printf("Thread %x ", pthread_self());
- debug(PRINTF) printf("%p.Gcx::addRange(%p, %p), nranges = %d\n", &this, pbot, ptop, nranges);
- if (nranges == rangedim)
- {
- size_t newdim = rangedim * 2 + 16;
- Range *newranges;
-
- newranges = cast(Range*)cstdlib.malloc(newdim * newranges[0].sizeof);
- if (!newranges)
- onOutOfMemoryError();
- if (ranges)
- { memcpy(newranges, ranges, nranges * newranges[0].sizeof);
- cstdlib.free(ranges);
- }
- ranges = newranges;
- rangedim = newdim;
- }
- ranges[nranges].pbot = pbot;
- ranges[nranges].ptop = ptop;
- nranges++;
+ debug(PRINTF) printf("%p.Gcx::addRange(%p, %p)\n", &this, pbot, ptop);
+ ranges.insert(Range(pbot, ptop));
}
@@ -1560,18 +1496,10 @@ struct Gcx
void removeRange(void *pbot) nothrow
{
//debug(PRINTF) printf("Thread %x ", pthread_self());
- debug(PRINTF) printf("Gcx.removeRange(%p), nranges = %d\n", pbot, nranges);
- for (size_t i = nranges; i--;)
- {
- if (ranges[i].pbot == pbot)
- {
- nranges--;
- memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
- return;
- }
- }
- debug(PRINTF) printf("Wrong thread\n");
+ debug(PRINTF) printf("Gcx.removeRange(%p)\n", pbot);
+ ranges.remove(Range(pbot, pbot)); // only pbot is used, see Range.opCmp
+ // debug(PRINTF) printf("Wrong thread\n");
// This is a fatal error, but ignore it.
// The problem is that we can get a Close() call on a thread
// other than the one the range was allocated on.
@@ -1673,22 +1601,6 @@ struct Gcx
}
- /**
- *
- */
- int rangeIter(int delegate(ref Range) dg)
- {
- int result = 0;
- for (size_t i = 0; i < nranges; ++i)
- {
- result = dg(ranges[i]);
- if (result)
- break;
- }
- return result;
- }
-
-
/**
* Find Pool that pointer is in.
* Return null if not in a Pool.
@@ -2560,16 +2472,25 @@ struct Gcx
// Scan roots[]
debug(COLLECT_PRINTF) printf("\tscan roots[]\n");
- mark(roots, roots + nroots);
+ // @@@BUG12739@@@
+ roots.opApply(
+ (ref Root root) {
+ mark(cast(void*)&root.proot, cast(void*)(&root.proot + 1));
+ return 0;
+ }
+ );
// Scan ranges[]
debug(COLLECT_PRINTF) printf("\tscan ranges[]\n");
//log++;
- for (n = 0; n < nranges; n++)
- {
- debug(COLLECT_PRINTF) printf("\t\t%p .. %p\n", ranges[n].pbot, ranges[n].ptop);
- mark(ranges[n].pbot, ranges[n].ptop);
- }
+ // @@@BUG12739@@@
+ ranges.opApply(
+ (ref Range range) {
+ debug(COLLECT_PRINTF) printf("\t\t%p .. %p\n", range.pbot, range.ptop);
+ mark(range.pbot, range.ptop);
+ return 0;
+ }
+ );
//log--;
debug(COLLECT_PRINTF) printf("\tscan heap\n");
diff --git a/src/gc/proxy.d b/src/gc/proxy.d
index 6521a7b54eb..430877fbf34 100644
--- a/src/gc/proxy.d
+++ b/src/gc/proxy.d
@@ -342,18 +342,36 @@ extern (C)
// TODO: Decide if this is an error condition.
}
proxy = p;
- foreach( r; _gc.rootIter )
- proxy.gc_addRoot( r );
- foreach( r; _gc.rangeIter )
- proxy.gc_addRange( r.pbot, r.ptop - r.pbot );
+ // @@@BUG12739@@@
+ _gc.rootIter()(
+ (ref Root r) {
+ proxy.gc_addRoot( r );
+ return 0;
+ }
+ );
+ _gc.rangeIter()(
+ (ref Range r) {
+ proxy.gc_addRange( r.pbot, r.ptop - r.pbot );
+ return 0;
+ }
+ );
}
void gc_clrProxy()
{
- foreach( r; _gc.rangeIter )
- proxy.gc_removeRange( r.pbot );
- foreach( r; _gc.rootIter )
- proxy.gc_removeRoot( r );
+ // @@@BUG12739@@@
+ _gc.rangeIter()(
+ (ref Range r) {
+ proxy.gc_removeRange( r.pbot );
+ return 0;
+ }
+ );
+ _gc.rootIter()(
+ (ref Root r) {
+ proxy.gc_removeRoot( r );
+ return 0;
+ }
+ );
proxy = null;
}
}
diff --git a/src/rt/sections_linux.d b/src/rt/sections_linux.d
index 29a64ec27bc..25dbdf0cfdc 100644
--- a/src/rt/sections_linux.d
+++ b/src/rt/sections_linux.d
@@ -24,7 +24,8 @@ import core.sys.posix.pthread;
import rt.deh;
import rt.dmain2;
import rt.minfo;
-import rt.util.container;
+import rt.util.container.array;
+import rt.util.container.hashtab;
alias DSO SectionGroup;
struct DSO
diff --git a/src/rt/sections_osx.d b/src/rt/sections_osx.d
index 8a002e176fb..960abef6a42 100644
--- a/src/rt/sections_osx.d
+++ b/src/rt/sections_osx.d
@@ -21,7 +21,7 @@ import core.sys.posix.pthread;
import core.sys.osx.mach.dyld;
import core.sys.osx.mach.getsect;
import rt.deh, rt.minfo;
-import rt.util.container;
+import rt.util.container.array;
struct SectionGroup
{
diff --git a/src/rt/util/container/array.d b/src/rt/util/container/array.d
new file mode 100644
index 00000000000..d42d537edc9
--- /dev/null
+++ b/src/rt/util/container/array.d
@@ -0,0 +1,180 @@
+/**
+ * Array container for internal usage.
+ *
+ * Copyright: Copyright Martin Nowak 2013.
+ * License: Boost License 1.0.
+ * Authors: Martin Nowak
+ */
+module rt.util.container.array;
+
+static import common = rt.util.container.common;
+
+struct Array(T)
+{
+ @disable this(this);
+
+ ~this()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ length = 0;
+ }
+
+ @property size_t length() const
+ {
+ return _length;
+ }
+
+ @property void length(size_t nlength)
+ {
+ if (nlength < length)
+ foreach (ref val; _ptr[nlength .. length]) common.destroy(val);
+ _ptr = cast(T*)common.xrealloc(_ptr, nlength * T.sizeof);
+ if (nlength > length)
+ foreach (ref val; _ptr[length .. nlength]) common.initialize(val);
+ _length = nlength;
+ }
+
+ @property bool empty() const
+ {
+ return !length;
+ }
+
+ @property ref inout(T) front() inout
+ in { assert(!empty); }
+ body
+ {
+ return _ptr[0];
+ }
+
+ @property ref inout(T) back() inout
+ in { assert(!empty); }
+ body
+ {
+ return _ptr[_length - 1];
+ }
+
+ ref inout(T) opIndex(size_t idx) inout
+ in { assert(idx < length); }
+ body
+ {
+ return _ptr[idx];
+ }
+
+ inout(T)[] opSlice() inout
+ {
+ return _ptr[0 .. _length];
+ }
+
+ inout(T)[] opSlice(size_t a, size_t b) inout
+ in { assert(a < b && b <= length); }
+ body
+ {
+ return _ptr[a .. b];
+ }
+
+ alias length opDollar;
+
+ void insertBack()(auto ref T val)
+ {
+ length = length + 1;
+ back = val;
+ }
+
+ void popBack()
+ {
+ length = length - 1;
+ }
+
+ void remove(size_t idx)
+ in { assert(idx < length); }
+ body
+ {
+ foreach (i; idx .. length - 1)
+ _ptr[i] = _ptr[i+1];
+ popBack();
+ }
+
+ void swap(ref Array other)
+ {
+ auto ptr = _ptr;
+ _ptr = other._ptr;
+ other._ptr = ptr;
+ immutable len = _length;
+ _length = other._length;
+ other._length = len;
+ }
+
+private:
+ T* _ptr;
+ size_t _length;
+}
+
+unittest
+{
+ Array!size_t ary;
+
+ assert(ary[] == []);
+ ary.insertBack(5);
+ assert(ary[] == [5]);
+ assert(ary[$-1] == 5);
+ ary.popBack();
+ assert(ary[] == []);
+ ary.insertBack(0);
+ ary.insertBack(1);
+ assert(ary[] == [0, 1]);
+ assert(ary[0 .. 1] == [0]);
+ assert(ary[1 .. 2] == [1]);
+ assert(ary[$ - 2 .. $] == [0, 1]);
+ size_t idx;
+ foreach (val; ary) assert(idx++ == val);
+ foreach_reverse (val; ary) assert(--idx == val);
+ foreach (i, val; ary) assert(i == val);
+ foreach_reverse (i, val; ary) assert(i == val);
+
+ ary.insertBack(2);
+ ary.remove(1);
+ assert(ary[] == [0, 2]);
+
+ assert(!ary.empty);
+ ary.reset();
+ assert(ary.empty);
+ ary.insertBack(0);
+ assert(!ary.empty);
+ destroy(ary);
+ assert(ary.empty);
+
+ // not copyable
+ static assert(!__traits(compiles, { Array!size_t ary2 = ary; }));
+ Array!size_t ary2;
+ static assert(!__traits(compiles, ary = ary2));
+ static void foo(Array!size_t copy) {}
+ static assert(!__traits(compiles, foo(ary)));
+
+ ary2.insertBack(0);
+ assert(ary.empty);
+ assert(ary2[] == [0]);
+ ary.swap(ary2);
+ assert(ary[] == [0]);
+ assert(ary2.empty);
+}
+
+unittest
+{
+ alias RC = common.RC;
+ Array!RC ary;
+
+ size_t cnt;
+ assert(cnt == 0);
+ ary.insertBack(RC(&cnt));
+ assert(cnt == 1);
+ ary.insertBack(ary.front);
+ assert(cnt == 2);
+ ary.popBack();
+ assert(cnt == 1);
+ ary.popBack();
+ assert(cnt == 0);
+}
diff --git a/src/rt/util/container/common.d b/src/rt/util/container/common.d
new file mode 100644
index 00000000000..13e6d19bae0
--- /dev/null
+++ b/src/rt/util/container/common.d
@@ -0,0 +1,61 @@
+/**
+ * Common code for writing containers.
+ *
+ * Copyright: Copyright Martin Nowak 2013.
+ * License: Boost License 1.0.
+ * Authors: Martin Nowak
+ */
+module rt.util.container.common;
+
+import core.stdc.stdlib : free, malloc, realloc;
+
+void* xrealloc(void* ptr, size_t sz)
+{
+ import core.exception;
+
+ if (!sz) { .free(ptr); return null; }
+ if (auto nptr = .realloc(ptr, sz)) return nptr;
+ .free(ptr); onOutOfMemoryError();
+ assert(0);
+}
+
+void* xmalloc(size_t sz) nothrow
+{
+ import core.exception;
+ if (auto nptr = .malloc(sz))
+ return nptr;
+ onOutOfMemoryError();
+ assert(0);
+}
+
+void destroy(T)(ref T t) if (is(T == struct))
+{
+ object.destroy(t);
+}
+
+void destroy(T)(ref T t) if (!is(T == struct))
+{
+ t = T.init;
+}
+
+void initialize(T)(ref T t) if (is(T == struct))
+{
+ import core.stdc.string;
+ if(auto p = typeid(T).init().ptr)
+ memcpy(&t, p, T.sizeof);
+ else
+ memset(&t, 0, T.sizeof);
+}
+
+void initialize(T)(ref T t) if (!is(T == struct))
+{
+ t = T.init;
+}
+
+version (unittest) struct RC
+{
+ this(size_t* cnt) { ++*(_cnt = cnt); }
+ ~this() { if (_cnt) --*_cnt; }
+ this(this) { if (_cnt) ++*_cnt; }
+ size_t* _cnt;
+}
diff --git a/src/rt/util/container.d b/src/rt/util/container/hashtab.d
similarity index 58%
rename from src/rt/util/container.d
rename to src/rt/util/container/hashtab.d
index 473bd40831e..ec78a693fc1 100644
--- a/src/rt/util/container.d
+++ b/src/rt/util/container/hashtab.d
@@ -1,226 +1,14 @@
/**
- * Basic containers for internal usage.
+ * HashTab container for internal usage.
*
* Copyright: Copyright Martin Nowak 2013.
* License: Boost License 1.0.
* Authors: Martin Nowak
- * Source: $(DRUNTIMESRC src/rt/util/_container.d)
*/
-module rt.util.container;
+module rt.util.container.hashtab;
-import core.stdc.stdlib : free, malloc, realloc;
-
-private void* xrealloc(void* ptr, size_t sz)
-{
- import core.exception;
-
- if (!sz) { .free(ptr); return null; }
- if (auto nptr = .realloc(ptr, sz)) return nptr;
- .free(ptr); onOutOfMemoryError();
- assert(0);
-}
-
-private void destroy(T)(ref T t) if (is(T == struct))
-{
- object.destroy(t);
-}
-
-private void destroy(T)(ref T t) if (!is(T == struct))
-{
- t = T.init;
-}
-
-private void initialize(T)(ref T t) if (is(T == struct))
-{
- import core.stdc.string;
- if(auto p = typeid(T).init().ptr)
- memcpy(&t, p, T.sizeof);
- else
- memset(&t, 0, T.sizeof);
-}
-
-private void initialize(T)(ref T t) if (!is(T == struct))
-{
- t = T.init;
-}
-
-struct Array(T)
-{
- @disable this(this);
-
- ~this()
- {
- reset();
- }
-
- void reset()
- {
- length = 0;
- }
-
- @property size_t length() const
- {
- return _length;
- }
-
- @property void length(size_t nlength)
- {
- if (nlength < length)
- foreach (ref val; _ptr[nlength .. length]) destroy(val);
- _ptr = cast(T*)xrealloc(_ptr, nlength * T.sizeof);
- if (nlength > length)
- foreach (ref val; _ptr[length .. nlength]) initialize(val);
- _length = nlength;
- }
-
- @property bool empty() const
- {
- return !length;
- }
-
- @property ref inout(T) front() inout
- in { assert(!empty); }
- body
- {
- return _ptr[0];
- }
-
- @property ref inout(T) back() inout
- in { assert(!empty); }
- body
- {
- return _ptr[_length - 1];
- }
-
- ref inout(T) opIndex(size_t idx) inout
- in { assert(idx < length); }
- body
- {
- return _ptr[idx];
- }
-
- inout(T)[] opSlice() inout
- {
- return _ptr[0 .. _length];
- }
-
- inout(T)[] opSlice(size_t a, size_t b) inout
- in { assert(a < b && b <= length); }
- body
- {
- return _ptr[a .. b];
- }
-
- alias length opDollar;
-
- void insertBack()(auto ref T val)
- {
- length = length + 1;
- back = val;
- }
-
- void popBack()
- {
- length = length - 1;
- }
-
- void remove(size_t idx)
- in { assert(idx < length); }
- body
- {
- foreach (i; idx .. length - 1)
- _ptr[i] = _ptr[i+1];
- popBack();
- }
-
- void swap(ref Array other)
- {
- auto ptr = _ptr;
- _ptr = other._ptr;
- other._ptr = ptr;
- immutable len = _length;
- _length = other._length;
- other._length = len;
- }
-
-private:
- T* _ptr;
- size_t _length;
-}
-
-unittest
-{
- Array!size_t ary;
-
- assert(ary[] == []);
- ary.insertBack(5);
- assert(ary[] == [5]);
- assert(ary[$-1] == 5);
- ary.popBack();
- assert(ary[] == []);
- ary.insertBack(0);
- ary.insertBack(1);
- assert(ary[] == [0, 1]);
- assert(ary[0 .. 1] == [0]);
- assert(ary[1 .. 2] == [1]);
- assert(ary[$ - 2 .. $] == [0, 1]);
- size_t idx;
- foreach (val; ary) assert(idx++ == val);
- foreach_reverse (val; ary) assert(--idx == val);
- foreach (i, val; ary) assert(i == val);
- foreach_reverse (i, val; ary) assert(i == val);
-
- ary.insertBack(2);
- ary.remove(1);
- assert(ary[] == [0, 2]);
-
- assert(!ary.empty);
- ary.reset();
- assert(ary.empty);
- ary.insertBack(0);
- assert(!ary.empty);
- destroy(ary);
- assert(ary.empty);
-
- // not copyable
- static assert(!__traits(compiles, { Array!size_t ary2 = ary; }));
- Array!size_t ary2;
- static assert(!__traits(compiles, ary = ary2));
- static void foo(Array!size_t copy) {}
- static assert(!__traits(compiles, foo(ary)));
-
- ary2.insertBack(0);
- assert(ary.empty);
- assert(ary2[] == [0]);
- ary.swap(ary2);
- assert(ary[] == [0]);
- assert(ary2.empty);
-}
-
-
-version (unittest) struct RC
-{
- this(size_t* cnt) { ++*(_cnt = cnt); }
- ~this() { if (_cnt) --*_cnt; }
- this(this) { if (_cnt) ++*_cnt; }
- size_t* _cnt;
-}
-
-unittest
-{
- Array!RC ary;
-
- size_t cnt;
- assert(cnt == 0);
- ary.insertBack(RC(&cnt));
- assert(cnt == 1);
- ary.insertBack(ary.front);
- assert(cnt == 2);
- ary.popBack();
- assert(cnt == 1);
- ary.popBack();
- assert(cnt == 0);
-}
+import rt.util.container.array;
+static import common = rt.util.container.common;
struct HashTab(Key, Value)
{
@@ -245,8 +33,8 @@ struct HashTab(Key, Value)
while (p !is null)
{
auto pn = p._next;
- destroy(*p);
- .free(p);
+ common.destroy(*p);
+ common.free(p);
p = pn;
}
}
@@ -278,8 +66,8 @@ struct HashTab(Key, Value)
if (p._key == key)
{
*pp = p._next;
- destroy(*p);
- .free(p);
+ common.destroy(*p);
+ common.free(p);
if (--_length < _buckets.length && _length >= 4)
shrink();
return;
@@ -346,8 +134,8 @@ private:
_buckets.length = 4;
immutable hash = hashOf(key) & mask;
- auto p = cast(Node*).malloc(Node.sizeof);
- initialize(*p);
+ auto p = cast(Node*)common.xmalloc(Node.sizeof);
+ common.initialize(*p);
p._key = key;
p._next = _buckets[hash];
_buckets[hash] = p;
@@ -503,6 +291,7 @@ unittest
unittest
{
+ alias RC = common.RC;
HashTab!(size_t, RC) tab;
size_t cnt;
diff --git a/src/rt/util/container/treap.d b/src/rt/util/container/treap.d
new file mode 100644
index 00000000000..da52520f181
--- /dev/null
+++ b/src/rt/util/container/treap.d
@@ -0,0 +1,349 @@
+/**
+ * Treap container for internal usage.
+ *
+ * Copyright: Copyright Digital Mars 2014 - 2014.
+ * License: Boost License 1.0.
+ */
+module rt.util.container.treap;
+
+static import common = rt.util.container.common;
+import rt.util.random;
+
+struct Treap(E)
+{
+nothrow:
+ static struct Node
+ {
+ Node* left, right;
+ E element;
+ uint priority;
+ }
+
+ @disable this(this);
+
+ ~this()
+ {
+ removeAll();
+ }
+
+ void initialize()
+ {
+ rand48.defaultSeed();
+ }
+
+ void insert(E element)
+ {
+ root = insert(root, element);
+ }
+
+ void remove(E element)
+ {
+ remove(&root, element);
+ }
+
+ int opApply(scope int delegate(ref E) nothrow dg)
+ {
+ return (cast(const)&this).opApply((ref const E e) => dg(*cast(E*)&e));
+ }
+
+ int opApply(scope int delegate(ref const E) nothrow dg) const
+ {
+ return opApplyHelper(root, dg);
+ }
+
+ version(unittest)
+ bool opEquals(E[] elements)
+ {
+ size_t i;
+ // @@@BUG12739@@@
+ auto res = this.opApply(
+ (ref E e) {
+ if (i >= elements.length)
+ return 1;
+ if (e != elements[i++])
+ return 1;
+ return 0;
+ }
+ );
+ if (res)
+ return false;
+ /*foreach (e; this)
+ {
+ if (i >= elements.length)
+ return false;
+ if (e != elements[i++])
+ return false;
+ }*/
+ return i == elements.length;
+ }
+
+ void removeAll()
+ {
+ removeAll(root);
+ root = null;
+ }
+
+ version(unittest)
+ bool valid()
+ {
+ return valid(root);
+ }
+
+
+ version(none)
+ uint height()
+ {
+ static uint height(Node* node)
+ {
+ if (!node)
+ return 0;
+ auto left = height(node.left);
+ auto right = height(node.right);
+ return 1 + (left > right ? left : right);
+ }
+ return height(root);
+ }
+
+ version(none)
+ size_t count()
+ {
+ static size_t count(Node* node)
+ {
+ if (!node)
+ return 0;
+ return count(node.left) + count(node.right) + 1;
+ }
+ return count(root);
+ }
+
+
+private:
+ Node* root;
+ Rand48 rand48;
+
+ Node* allocNode(E element)
+ {
+ Node* node = cast(Node*)common.xmalloc(Node.sizeof);
+ node.left = node.right = null;
+ node.priority = rand48();
+ node.element = element;
+ return node;
+ }
+
+ Node* insert(Node* node, E element)
+ {
+ if (!node)
+ return allocNode(element);
+ else if (element < node.element)
+ {
+ node.left = insert(node.left, element);
+ if (node.left.priority < node.priority)
+ node = rotateR(node);
+ }
+ else if (element > node.element)
+ {
+ node.right = insert(node.right, element);
+ if (node.right.priority < node.priority)
+ node = rotateL(node);
+ }
+ else
+ {} // ignore duplicate
+
+ return node;
+ }
+
+static:
+
+ void freeNode(Node* node)
+ {
+ common.free(node);
+ }
+
+ Node* rotateL(Node* root)
+ {
+ auto pivot = root.right;
+ root.right = pivot.left;
+ pivot.left = root;
+ return pivot;
+ }
+
+ Node* rotateR(Node* root)
+ {
+ auto pivot = root.left;
+ root.left = pivot.right;
+ pivot.right = root;
+ return pivot;
+ }
+
+ void remove(Node** ppnode, E element)
+ {
+ Node* node = *ppnode;
+ if (!node)
+ return; // element not in treap
+
+ if (element < node.element)
+ {
+ remove(&node.left, element);
+ }
+ else if (element > node.element)
+ {
+ remove(&node.right, element);
+ }
+ else
+ {
+ while (node.left && node.right)
+ {
+ if (node.left.priority < node.right.priority)
+ {
+ *ppnode = rotateR(node);
+ ppnode = &(*ppnode).right;
+ }
+ else
+ {
+ *ppnode = rotateL(node);
+ ppnode = &(*ppnode).left;
+ }
+ }
+ if (!node.left)
+ *ppnode = node.right;
+ else
+ *ppnode = node.left;
+ freeNode(node);
+ }
+ }
+
+ void removeAll(Node* node)
+ {
+ if (!node)
+ return;
+ removeAll(node.left);
+ removeAll(node.right);
+ freeNode(node);
+ }
+
+ int opApplyHelper(const Node* node, scope int delegate(ref const E) nothrow dg)
+ {
+ if (!node)
+ return 0;
+
+ int result = opApplyHelper(node.left, dg);
+ if (result)
+ return result;
+ result = dg(node.element);
+ if (result)
+ return result;
+ return opApplyHelper(node.right, dg);
+ }
+
+ version(unittest)
+ bool valid(Node* node)
+ {
+ if (!node)
+ return true;
+
+ if (node.left)
+ {
+ if (node.left.priority < node.priority)
+ return false;
+ if (node.left.element > node.element)
+ return false;
+ }
+ if (node.right)
+ {
+ if (node.right.priority < node.priority)
+ return false;
+ if (node.right.element < node.element)
+ return false;
+ }
+ return valid(node.left) && valid(node.right);
+ }
+}
+
+unittest
+{
+ // randomized unittest for randomized data structure
+ import cstdlib = core.stdc.stdlib : rand, srand;
+ import ctime = core.stdc.time : time;
+
+ enum OP { add, remove }
+ enum initialSize = 1000;
+ enum randOps = 1000;
+
+ Treap!uint treap;
+ OP[] ops;
+ uint[] opdata;
+
+ treap.initialize();
+ srand(cast(uint)time(null));
+
+ uint[] data;
+initialLoop:
+ foreach (i; 0 .. initialSize)
+ {
+ data ~= rand();
+ treap.insert(data[$-1]);
+ foreach (e; data[0..$-1])
+ if (e == data[$-1])
+ {
+ data = data[0..$-1];
+ continue initialLoop;
+ }
+ }
+ data.sort;
+ assert(treap == data);
+ assert(treap.valid());
+
+ for (int i = randOps; i > 0; --i)
+ {
+ ops ~= cast(OP)(rand() < uint.max / 2 ? OP.add: OP.remove);
+ opdata ~= rand();
+ }
+
+ foreach (op; ops)
+ {
+ if (op == OP.add)
+ {
+ treap.insert(opdata[0]);
+
+ size_t i;
+ for (i = 0; i < data.length; ++i)
+ if (data[i] >= opdata[0])
+ break;
+
+ if (i == data.length || data[i] != opdata[0])
+ { // not a duplicate
+ data.length++;
+ uint tmp = opdata[0];
+ for (; i < data.length; ++i)
+ {
+ uint tmp2 = data[i];
+ data[i] = tmp;
+ tmp = tmp2;
+ }
+ }
+ }
+ else if (!data.length) // nothing to remove
+ {
+ opdata = opdata[1..$];
+ continue;
+ }
+ else
+ {
+ uint tmp = data[opdata[0]%data.length];
+ treap.remove(tmp);
+ size_t i;
+ for (i = 0; data[i] < tmp; ++i)
+ {}
+ for (; i < data.length-1; ++i)
+ data[i] = data[i+1];
+ data.length--;
+ }
+ assert(treap.valid());
+ assert(treap == data);
+ opdata = opdata[1..$];
+ }
+
+ treap.removeAll();
+ data.length = 0;
+ assert(treap == data);
+}
\ No newline at end of file
diff --git a/src/rt/util/random.d b/src/rt/util/random.d
new file mode 100644
index 00000000000..3947a403695
--- /dev/null
+++ b/src/rt/util/random.d
@@ -0,0 +1,48 @@
+/**
+ * Random number generators for internal usage.
+ *
+ * Copyright: Copyright Digital Mars 2014.
+ * License: Boost License 1.0.
+ */
+module rt.util.random;
+
+struct Rand48
+{
+nothrow:
+ private ulong rng_state;
+
+ void defaultSeed()
+ {
+ import ctime = core.stdc.time : time;
+ seed(cast(uint)ctime.time(null));
+ }
+
+ void seed(uint seedval)
+ {
+ assert(seedval);
+ rng_state = cast(ulong)seedval << 16 | 0x330e;
+ popFront();
+ }
+
+ auto opCall()
+ {
+ auto result = front();
+ popFront();
+ return result;
+ }
+
+ @property uint front()
+ {
+ return cast(uint)(rng_state >> 16);
+ }
+
+ void popFront()
+ {
+ immutable ulong a = 25214903917;
+ immutable ulong c = 11;
+ immutable ulong m_mask = (1uL << 48uL) - 1;
+ rng_state = (a*rng_state+c) & m_mask;
+ }
+
+ enum empty = false;
+}
\ No newline at end of file