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