123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- "use strict"
- var makeTree = require("../rbtree.js")
- var tape = require("tape")
- var util = require("util")
- var iota = require("iota-array")
- var COLORS = [ "r", "b", "bb" ]
- function printTree(tree) {
- if(!tree) {
- return []
- }
- return [ COLORS[tree._color], tree.key, printTree(tree.left), printTree(tree.right) ]
- }
- function print(t) {
- console.log(util.inspect(printTree(t.root), {depth:12}))
- }
- //Ensures the red black axioms are satisfied by tree
- function checkTree(tree, t) {
- if(!tree.root) {
- return
- }
- t.equals(tree.root._color, 1, "root is black")
- function checkNode(node) {
- if(!node) {
- return [1, 0]
- }
- if(node._color === 0) {
- t.assert(!node.left || node.left._color === 1, "children of red node must be black")
- t.assert(!node.right || node.right._color === 1, "children of red node must be black")
- } else {
- t.equals(node._color, 1, "node color must be red or black")
- }
- if(node.left) {
- t.assert(tree._compare(node.left.key, node.key) <= 0, "left tree order invariant")
- }
- if(node.right) {
- t.assert(tree._compare(node.right.key, node.key) >= 0, "right tree order invariant")
- }
- var cl = checkNode(node.left)
- var cr = checkNode(node.right)
- t.equals(cl[0], cr[0], "number of black nodes along all paths to root must be constant")
- t.equals(cl[1] + cr[1] + 1, node._count, "item count consistency")
- return [cl[0] + node._color, cl[1] + cr[1] + 1]
- }
- var r = checkNode(tree.root)
- t.equals(r[1], tree.length, "tree length")
- }
- tape("insert()", function(t) {
- var t1 = makeTree()
-
- var u = t1
- var arr = []
- for(var i=20; i>=0; --i) {
- var x = i
- var next = u.insert(x, true)
- checkTree(u, t)
- checkTree(next, t)
- t.equals(u.length, arr.length)
- arr.push(x)
- u = next
- }
- for(var i=-20; i<0; ++i) {
- var x = i
- var next = u.insert(x, true)
- checkTree(u, t)
- checkTree(next, t)
- arr.sort(function(a,b) { return a-b })
- var ptr = 0
- u.forEach(function(k,v) {
- t.equals(k, arr[ptr++])
- })
- t.equals(ptr, arr.length)
- arr.push(x)
- u = next
- }
- var start = u.begin
- for(var i=-20, j=0; j<=40; ++i, ++j) {
- t.equals(u.at(j).key, i, "checking at()")
- t.equals(start.key, i, "checking iter")
- t.equals(start.index, j, "checking index")
- t.assert(start.valid, "checking valid")
- if(j < 40) {
- t.assert(start.hasNext, "hasNext()")
- } else {
- t.assert(!start.hasNext, "eof hasNext()")
- }
- start.next()
- }
- t.assert(!start.valid, "invalid eof iterator")
- t.assert(!start.hasNext, "hasNext() at eof fail")
- t.equals(start.index, 41, "eof index")
- t.end()
- })
- tape("foreach", function(t) {
- var u = iota(31).reduce(function(u, k, v) {
- return u.insert(k, v)
- }, makeTree())
- //Check basic foreach
- var visit_keys = []
- var visit_vals = []
- u.forEach(function(k,v) {
- visit_keys.push(k)
- visit_vals.push(v)
- })
- t.same(visit_keys, u.keys)
- t.same(visit_vals, u.values)
- //Check foreach with termination
- visit_keys = []
- visit_vals = []
- t.equals(u.forEach(function(k,v) {
- if(k === 5) {
- return 1000
- }
- visit_keys.push(k)
- visit_vals.push(v)
- }), 1000)
- t.same(visit_keys, u.keys.slice(0, 5))
- t.same(visit_vals, u.values.slice(0, 5))
- //Check half interval foreach
- visit_keys = []
- visit_vals = []
- u.forEach(function(k,v) {
- visit_keys.push(k)
- visit_vals.push(v)
- }, 3)
- t.same(visit_keys, u.keys.slice(3))
- t.same(visit_vals, u.values.slice(3))
- //Check half interval foreach with termination
- visit_keys = []
- visit_vals = []
- t.equals(u.forEach(function(k,v) {
- if(k === 12) {
- return 1000
- }
- visit_keys.push(k)
- visit_vals.push(v)
- }, 3), 1000)
- t.same(visit_keys, u.keys.slice(3, 12))
- t.same(visit_vals, u.values.slice(3, 12))
- //Check interval foreach
- visit_keys = []
- visit_vals = []
- u.forEach(function(k,v) {
- visit_keys.push(k)
- visit_vals.push(v)
- }, 3, 15)
- t.same(visit_keys, u.keys.slice(3, 15))
- t.same(visit_vals, u.values.slice(3, 15))
- //Check interval foreach with termination
- visit_keys = []
- visit_vals = []
- t.equals(u.forEach(function(k,v) {
- if(k === 12) {
- return 1000
- }
- visit_keys.push(k)
- visit_vals.push(v)
- }, 3, 15), 1000)
- t.same(visit_keys, u.keys.slice(3, 12))
- t.same(visit_vals, u.values.slice(3, 12))
- t.end()
- })
- function compareIterators(a, b, t) {
- t.equals(a.tree, b.tree, "iter trees")
- t.equals(a.valid, b.valid, "iter validity")
- if(!b.valid) {
- return
- }
- t.equals(a.node, b.node, "iter node")
- t.equals(a.key, b.key, "iter key")
- t.equals(a.value, b.value, "iter value")
- t.equals(a.index, b.index, "iter index")
- }
- tape("iterators", function(t) {
- var u = iota(20).reduce(function(u, k, v) {
- return u.insert(k, v)
- }, makeTree())
- //Try walking forward
- var iter = u.begin
- var c = iter.clone()
- t.ok(iter.hasNext, "must have next at beginneing")
- t.ok(!iter.hasPrev, "must not have predecessor")
- for(var i=0; i<20; ++i) {
- var v = u.at(i)
- compareIterators(iter, v, t)
- t.equals(iter.index, i)
- iter.next()
- }
- t.ok(!iter.valid, "must be eof iterator")
- //Check if the clone worked
- compareIterators(c, u.begin, t)
- //Try walking backward
- var iter = u.end
- t.ok(!iter.hasNext, "must not have next")
- t.ok(iter.hasPrev, "must have predecessor")
- for(var i=19; i>=0; --i) {
- var v = u.at(i)
- compareIterators(iter, v, t)
- t.equals(iter.index, i)
- iter.prev()
- }
- t.ok(!iter.valid, "must be eof iterator")
- t.end()
- })
- tape("remove()", function(t) {
- var sz = [1, 2, 10, 20, 23, 31, 32, 33]
- for(var n=0; n<sz.length; ++n) {
- var c = sz[n]
- var u = iota(c).reduce(function(u, k, v) {
- return u.insert(k, v)
- }, makeTree())
- for(var i=0; i<c; ++i) {
- checkTree(u.remove(i), t)
- }
- }
- t.end()
- })
- tape("update()", function(t) {
- var arr = [0, 1, 2, 3, 4, 5, 6 ]
- var u = arr.reduce(function(u, k, v) {
- return u.insert(k, v)
- }, makeTree())
- for(var iter=u.begin; iter.hasNext; iter.next()) {
- var p = iter.value
- var updated = iter.update(1000)
- t.equals(iter.value, iter.key, "ensure no mutation")
- t.equals(updated.find(iter.key).value, 1000, "ensure update applied")
- checkTree(updated, t)
- checkTree(u, t)
- }
- t.end()
- })
- tape("keys and values", function(t) {
- var original_keys = [ "potato", "sock", "foot", "apple", "newspaper", "gameboy" ]
- var original_values = [ 42, 10, false, "!!!", {}, null ]
- var u = makeTree()
- for(var i=0; i<original_keys.length; ++i) {
- u = u.insert(original_keys[i], original_values[i])
- }
- var zipped = iota(6).map(function(i) {
- return [ original_keys[i], original_values[i] ]
- })
- zipped.sort(function(a,b) {
- if(a[0] < b[0]) { return -1 }
- if(a[0] > b[0]) { return 1 }
- return 0
- })
- var keys = zipped.map(function(v) { return v[0] })
- var values = zipped.map(function(v) { return v[1] })
- t.same(u.keys, keys)
- t.same(u.values, values)
- t.end()
- })
- tape("searching", function(t) {
- var arr = [0, 1, 1, 1, 1, 2, 3, 4, 5, 6, 6 ]
- var u = arr.reduce(function(u, k, v) {
- return u.insert(k, v)
- }, makeTree())
- for(var i=0; i<arr.length; ++i) {
- if(arr[i] !== arr[i-1] && arr[i] !== arr[i+1]) {
- t.equals(u.get(arr[i]), i, "get " + arr[i])
- }
- }
- t.equals(u.get(-1), undefined, "get missing")
- t.equals(u.ge(3).index, 6, "ge simple")
- t.equals(u.ge(0.9).index, 1, "ge run start")
- t.equals(u.ge(1).index, 1, "ge run mid")
- t.equals(u.ge(1.1).index, 5, "ge run end")
- t.equals(u.ge(0).index, 0, "ge first")
- t.equals(u.ge(6).index, 9, "ge last")
- t.equals(u.ge(100).valid, false, "ge big")
- t.equals(u.ge(-1).index, 0, "ge small")
- t.equals(u.gt(3).index, 7, "gt simple")
- t.equals(u.gt(0.9).index, 1, "gt run start")
- t.equals(u.gt(1).index, 5, "gt run mid")
- t.equals(u.gt(1.1).index, 5, "gt run end")
- t.equals(u.gt(0).index, 1, "gt first")
- t.equals(u.gt(6).valid, false, "gt last")
- t.equals(u.gt(100).valid, false, "gt big")
- t.equals(u.gt(-1).index, 0, "ge small")
- t.equals(u.le(3).index, 6, "le simple")
- t.equals(u.le(0.9).index, 0, "le run start")
- t.equals(u.le(1).index, 4, "le run mid")
- t.equals(u.le(1.1).index, 4, "le run end")
- t.equals(u.le(0).index, 0, "le first")
- t.equals(u.le(6).index, 10, "le last")
- t.equals(u.le(100).index, 10, "le big")
- t.equals(u.le(-1).valid, false, "le small")
-
- t.equals(u.lt(3).index, 5, "lt simple")
- t.equals(u.lt(0.9).index, 0, "lt run start")
- t.equals(u.lt(1).index, 0, "lt run mid")
- t.equals(u.lt(1.1).index, 4, "lt run end")
- t.equals(u.lt(0).valid, false, "lt first")
- t.equals(u.lt(6).index, 8, "lt last")
- t.equals(u.lt(100).index, 10, "lt big")
- t.equals(u.lt(-1).valid, false, "lt small")
- t.equals(u.find(-1).valid, false, "find missing small")
- t.equals(u.find(10000).valid, false, "find missing big")
- t.equals(u.find(3).index, 6, "find simple")
- t.ok(u.find(1).index > 0, "find repeat")
- t.ok(u.find(1).index < 5, "find repeat")
-
- for(var i=0; i<arr.length; ++i) {
- t.equals(u.find(arr[i]).key, arr[i], "find " + i)
- }
- for(var i=0; i<arr.length; ++i) {
- t.equals(u.at(i).key, arr[i], "at " + i)
- }
- t.equals(u.at(-1).valid, false, "at missing small")
- t.equals(u.at(1000).valid, false, "at missing big")
- t.end()
- })
- tape("slab-sequence", function(t) {
- var tree = makeTree()
- tree=tree.insert(0, 0)
- checkTree(tree, t)
- t.same(tree.values, [0])
- tree=tree.insert(1, 1)
- checkTree(tree, t)
- t.same(tree.values, [0,1])
- tree=tree.insert(0.5, 2)
- checkTree(tree, t)
- t.same(tree.values, [0,2,1])
- tree=tree.insert(0.25, 3)
- checkTree(tree, t)
- t.same(tree.values, [0,3,2,1])
- tree=tree.remove(0)
- checkTree(tree, t)
- t.same(tree.values, [3,2,1])
- tree=tree.insert(0.375, 4)
- checkTree(tree, t)
- t.same(tree.values, [3, 4, 2, 1])
- tree=tree.remove(1)
- checkTree(tree, t)
- t.same(tree.values, [3,4,2])
-
- tree=tree.remove(0.5)
- checkTree(tree, t)
- t.same(tree.values, [3,4])
- tree=tree.remove(0.375)
- checkTree(tree, t)
- t.same(tree.values, [3])
- tree=tree.remove(0.25)
- checkTree(tree, t)
- t.same(tree.values, [])
-
- t.end()
- })
- tape("slab-sequence-2", function(t) {
- var u = makeTree()
- u=u.insert( 12 , 22 )
- u=u.insert( 11 , 3 )
- u=u.insert( 10 , 28 )
- u=u.insert( 13 , 16 )
- u=u.insert( 9 , 9 )
- u=u.insert( 14 , 10 )
- u=u.insert( 8 , 15 )
- u=u.insert( 15 , 29 )
- u=u.insert( 16 , 4 )
- u=u.insert( 7 , 21 )
- u=u.insert( 17 , 23 )
- u=u.insert( 6 , 2 )
- u=u.insert( 5 , 27 )
- u=u.insert( 18 , 17 )
- u=u.insert( 4 , 8 )
- u=u.insert( 31 , 11 )
- u=u.insert( 30 , 30 )
- u=u.insert( 29 , 5 )
- u=u.insert( 28 , 24 )
- u=u.insert( 27 , 18 )
- u=u.insert( 26 , 12 )
- u=u.insert( 25 , 31 )
- u=u.insert( 24 , 6 )
- u=u.insert( 23 , 25 )
- u=u.insert( 19 , 7 )
- u=u.insert( 20 , 13 )
- u=u.insert( 1 , 20 )
- u=u.insert( 0 , 14 )
- u=u.insert( 22 , 0 )
- u=u.insert( 2 , 1 )
- u=u.insert( 3 , 26 )
- u=u.insert( 21 , 19 )
- u=u.remove( 18 , 17 )
- u=u.remove( 17 , 23 )
- u=u.remove( 16 , 4 )
- u=u.remove( 15 , 29 )
- u=u.remove( 14 , 10 )
- u=u.remove( 13 , 16 )
- u=u.remove( 12 , 22 )
- u=u.remove( 6 , 2 )
- u=u.remove( 7 , 21 )
- u=u.remove( 8 , 15 )
- u=u.remove( 11 , 3 )
- u=u.remove( 4 , 8 )
- u=u.remove( 9 , 9 )
- u=u.remove( 10 , 28 )
- u=u.remove( 5 , 27 )
- u=u.remove( 31 , 11 )
- u=u.remove( 0 , 14 )
- u=u.remove( 30 , 30 )
- u=u.remove( 29 , 5 )
- u=u.remove( 1 , 20 )
- u=u.remove( 28 , 24 )
- u=u.remove( 2 , 1 )
- u=u.remove( 3 , 26 )
- u=u.remove( 27 , 18 )
- u=u.remove( 19 , 7 )
- u=u.remove( 26 , 12 )
- u=u.remove( 20 , 13 )
- u=u.remove( 25 , 31 )
- u=u.remove( 24 , 6 )
- u=u.remove( 21 , 19 )
- u=u.remove( 23 , 25 )
- u=u.remove( 22 , 0 )
- t.end()
- })
|