"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 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 0, "find repeat") t.ok(u.find(1).index < 5, "find repeat") for(var i=0; i