chain-lightning
Advanced tools
+368
-165
@@ -31,2 +31,6 @@ /* | ||
| const arrayKit = require( 'array-kit' ) ; | ||
| /* | ||
@@ -44,3 +48,3 @@ For balancing, it uses the AVL algorithm. | ||
| this.keyFn = options && options.keyFn ; | ||
| this.uniqueKeys = !! ( options && options.uniqueKeys ) ; | ||
| this.stack = !! ( options && options.stack ) ; | ||
@@ -73,4 +77,3 @@ if ( ! this.keyFn ) { | ||
| function Node( tree , key , element , parent = null ) { | ||
| this.tree = tree ; | ||
| function Node( key , element , parent = null ) { | ||
| this.key = key ; | ||
@@ -88,6 +91,11 @@ this.element = element ; | ||
| class Stack extends Array {} | ||
| BinaryTree.Stack = Stack ; | ||
| // /!\ DEPRECATED? .truncate*() does not call it /!\ | ||
| // Used when a node is deleted | ||
| // Does it help garbage collection? | ||
| BinaryTree.prototype.destroyNode = function( node ) { | ||
| node.tree = null ; | ||
| node.key = null ; | ||
@@ -112,6 +120,15 @@ node.element = null ; | ||
| BinaryTree.prototype.values = function *() { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| yield current.element ; | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| yield element ; | ||
| } | ||
| } | ||
| else { | ||
| yield current.element ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -237,5 +254,6 @@ } | ||
| // Set: replace existing element | ||
| BinaryTree.prototype.set = function( key , element , noOverwrite ) { | ||
| if ( ! this.trunc ) { | ||
| this.trunc = new Node( this , key , element ) ; | ||
| this.trunc = new Node( key , element ) ; | ||
| this.length ++ ; | ||
@@ -254,10 +272,9 @@ return ; | ||
| if ( this.uniqueKeys ) { | ||
| node.element = element ; | ||
| return ; | ||
| } | ||
| node.element = element ; | ||
| return ; | ||
| } | ||
| // No uniqueKey? So insert it after | ||
| if ( this.isOrdered( node.key , key ) ) { | ||
| if ( ! node.right ) { | ||
| node.right = new Node( this , key , element , node ) ; | ||
| node.right = new Node( key , element , node ) ; | ||
| this.length ++ ; | ||
@@ -270,6 +287,45 @@ this.rebalance( node , true ) ; | ||
| } | ||
| else { | ||
| if ( ! node.left ) { | ||
| node.left = new Node( key , element , node ) ; | ||
| this.length ++ ; | ||
| this.rebalance( node , true ) ; | ||
| return ; | ||
| } | ||
| node = node.left ; | ||
| } | ||
| } | ||
| } ; | ||
| // Add: stack element if there is one already existing. | ||
| // If .stack is false, fallback to .set() | ||
| BinaryTree.prototype.add = function( key , element ) { | ||
| if ( ! this.stack ) { return this.set( key , element ) ; } | ||
| if ( ! this.trunc ) { | ||
| this.trunc = new Node( key , element ) ; | ||
| this.length ++ ; | ||
| return ; | ||
| } | ||
| var node = this.trunc ; | ||
| for ( ;; ) { | ||
| if ( key === node.key ) { | ||
| if ( node.element instanceof Stack ) { | ||
| node.element.push( element ) ; | ||
| } | ||
| else { | ||
| node.element = new Stack( node.element , element ) ; | ||
| } | ||
| return ; | ||
| } | ||
| if ( this.isOrdered( node.key , key ) ) { | ||
| if ( ! node.right ) { | ||
| node.right = new Node( this , key , element , node ) ; | ||
| node.right = new Node( key , element , node ) ; | ||
| this.length ++ ; | ||
@@ -284,3 +340,3 @@ this.rebalance( node , true ) ; | ||
| if ( ! node.left ) { | ||
| node.left = new Node( this , key , element , node ) ; | ||
| node.left = new Node( key , element , node ) ; | ||
| this.length ++ ; | ||
@@ -298,3 +354,3 @@ this.rebalance( node , true ) ; | ||
| BinaryTree.prototype.insert = function( ... elements ) { | ||
| BinaryTree.prototype.insertUnique = function( ... elements ) { | ||
| elements.forEach( element => this.set( this.keyFn( element ) , element , true ) ) ; | ||
@@ -305,3 +361,10 @@ } ; | ||
| // Divide and conquer algo, to avoid rotation when all elements are in the correct order | ||
| BinaryTree.prototype.insert = function( ... elements ) { | ||
| elements.forEach( element => this.add( this.keyFn( element ) , element ) ) ; | ||
| } ; | ||
| // Divide and conquer algo, to avoid rotation when all elements are in the correct order. | ||
| // Each one should be unique. | ||
| BinaryTree.prototype.insertOrdered = function( ... elements ) { | ||
@@ -359,2 +422,58 @@ var start , end , middle , diff , listIndex , | ||
| if ( node.left && node.right ) { | ||
| // Ok, both node exist... it's the complicated case, | ||
| // Find a replacerNode. | ||
| // Note that the replacer has only one child, since it's either the min or the max of the subtree. | ||
| /* OLD | ||
| // Swap node's element, it's easier and faster, but it's also bad because the node could be referenced somewhere else, | ||
| // so breaking the node-element relationship may cause really nasty bugs. | ||
| // .inPlaceFilter() have had a bug because of this (it stored the .nextNode() before calling .deleteNode()). | ||
| // Choose the heavier child | ||
| if ( node.left.depth >= node.right.depth ) { | ||
| // We will use the left subtree, the replacer is the maximum of this sub-tree | ||
| replacerNode = this.getMaxNode( node.left ) ; | ||
| } | ||
| else { | ||
| // We will use the right subtree, the replacer is the minimum of this sub-tree | ||
| replacerNode = this.getMinNode( node.right ) ; | ||
| } | ||
| // Copy key/value... | ||
| node.key = replacerNode.key ; | ||
| node.element = replacerNode.element ; | ||
| // ... and just delete the replacer using .deleteNode() | ||
| this.deleteNode( replacerNode ) ; | ||
| //*/ | ||
| //* NEW | ||
| // Swap node's place in the tree. It's way more complicated and a bit slower, but it's safer because | ||
| // it doesn't break the node-element relationship. | ||
| // Choose the heavier child | ||
| if ( node.left.depth >= node.right.depth ) { | ||
| // We will use the left subtree, the replacer is the maximum of this sub-tree | ||
| replacerNode = this.getMaxNode( node.left ) ; | ||
| } | ||
| else { | ||
| // We will use the right subtree, the replacer is the minimum of this sub-tree | ||
| replacerNode = this.getMinNode( node.right ) ; | ||
| } | ||
| this.swapNodes( node , replacerNode ) ; | ||
| // Copy key/value... | ||
| node.key = replacerNode.key ; | ||
| // We would like to try to delete it again using .deleteNode(). | ||
| // But since it would branch in the "simple" case (because of .getMaxNode()/.getMinNode()), | ||
| // we can continue to the rest of this function. | ||
| //return this.deleteNode( replacerNode ) ; | ||
| //*/ | ||
| } | ||
| parent = node.parent ; | ||
@@ -372,34 +491,8 @@ | ||
| if ( node.left ) { | ||
| if ( node.right ) { | ||
| // Ok, both node exist... it's the complicated case, | ||
| // Find a replacerNode, copy its key and value in the current node, | ||
| // and delete the replacer instead of this one. | ||
| // Note that the replacer has only one child, since it's either the min or the max of the subtree. | ||
| // Choose the heavier child | ||
| if ( node.left.depth >= node.right.depth ) { | ||
| // We will use the left subtree, the replacer is the maximum of this sub-tree | ||
| replacerNode = this.getMaxNode( node.left ) ; | ||
| } | ||
| else { | ||
| // We will use the right subtree, the replacer is the minimum of this sub-tree | ||
| replacerNode = this.getMinNode( node.right ) ; | ||
| } | ||
| // Copy key/value... | ||
| node.key = replacerNode.key ; | ||
| node.element = replacerNode.element ; | ||
| // ... and just delete the replacer using .deleteNode() | ||
| this.deleteNode( replacerNode ) ; | ||
| } | ||
| else { | ||
| // Only a left child, attach its subtree to the parent | ||
| referer[ refererProp ] = node.left ; | ||
| node.left.parent = parent ; | ||
| this.length -- ; | ||
| this.rebalance( node , true ) ; | ||
| this.destroyNode( node ) ; | ||
| } | ||
| // Only a left child, attach its subtree to the parent | ||
| referer[ refererProp ] = node.left ; | ||
| node.left.parent = parent ; | ||
| this.length -- ; | ||
| this.rebalance( node , true ) ; | ||
| this.destroyNode( node ) ; | ||
| } | ||
@@ -426,3 +519,3 @@ else if ( node.right ) { | ||
| BinaryTree.prototype.truncateBefore = function( key , including ) { | ||
| var lastTruncatedNode = this.getClosestNode( key , ! including , -1 ) ; | ||
| var lastTruncatedNode = this.getClosestNode( key , including , -1 ) ; | ||
| //var firstKeptNode = this.nextNode( lastTruncatedNode ) ; | ||
@@ -509,3 +602,3 @@ | ||
| BinaryTree.prototype.truncateAfter = function( key , including ) { | ||
| var firstTruncatedNode = this.getClosestNode( key , ! including , 1 ) ; | ||
| var firstTruncatedNode = this.getClosestNode( key , including , 1 ) ; | ||
| //var firstKeptNode = this.nextNode( firstTruncatedNode ) ; | ||
@@ -592,2 +685,48 @@ | ||
| /* | ||
| Advanced custom features | ||
| */ | ||
| // Delete all occurences of a value | ||
| BinaryTree.prototype.deleteValue = | ||
| BinaryTree.prototype.removeValue = function( value ) { | ||
| this.inPlaceFilter( e => ! isIdenticalTo( e , value ) ) ; | ||
| } ; | ||
| BinaryTree.prototype.inPlaceFilter = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() , | ||
| next ; | ||
| while ( current ) { | ||
| if ( current.element instanceof Stack ) { | ||
| arrayKit.inPlaceFilter( current.element , fn , thisArg , current.key ) ; | ||
| if ( current.element.length ) { | ||
| current = this.nextNode( current ) ; | ||
| } | ||
| else { | ||
| next = this.nextNode( current ) ; | ||
| this.deleteNode( current ) ; | ||
| current = next ; | ||
| } | ||
| } | ||
| else if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| current = this.nextNode( current ) ; | ||
| } | ||
| else { | ||
| next = this.nextNode( current ) ; | ||
| this.deleteNode( current ) ; | ||
| current = next ; | ||
| } | ||
| } | ||
| return this ; | ||
| } ; | ||
| /* | ||
| Advanced Array-like features | ||
@@ -606,7 +745,11 @@ */ | ||
| BinaryTree.prototype.keyOf = function( element , fromKey ) { | ||
| BinaryTree.prototype.keyOf = function( searchElement , fromKey ) { | ||
| var current = fromKey ? this.getNode( fromKey ) : this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( isIdenticalTo( current.element , element ) ) { return current.key ; } | ||
| if ( current.element instanceof Stack ) { | ||
| if ( current.element.includes( searchElement ) ) { return current.key ; } | ||
| } | ||
| else if ( isIdenticalTo( current.element , searchElement ) ) { return current.key ; } | ||
| current = this.nextNode( current ) ; | ||
@@ -620,7 +763,11 @@ } | ||
| BinaryTree.prototype.lastKeyOf = function( element , fromKey ) { | ||
| BinaryTree.prototype.lastKeyOf = function( searchElement , fromKey ) { | ||
| var current = fromKey ? this.getNode( fromKey ) : this.getTailNode() ; | ||
| while ( current ) { | ||
| if ( isIdenticalTo( current.element , element ) ) { return current.key ; } | ||
| if ( current.element instanceof Stack ) { | ||
| if ( current.element.includes( searchElement ) ) { return current.key ; } | ||
| } | ||
| else if ( isIdenticalTo( current.element , searchElement ) ) { return current.key ; } | ||
| current = this.previousNode( current ) ; | ||
@@ -634,14 +781,13 @@ } | ||
| BinaryTree.prototype.includes = function( element ) { | ||
| if ( ! this.trunc ) { return false ; } | ||
| return this._recursiveIncludes( element , this.trunc ) ; | ||
| } ; | ||
| BinaryTree.prototype.includes = function( searchElement , current = this.trunc ) { | ||
| if ( ! current ) { return false ; } | ||
| if ( current.element instanceof Stack ) { | ||
| if ( current.element.includes( searchElement ) ) { return true ; } | ||
| } | ||
| else if ( isIdenticalTo( current.element , searchElement ) ) { | ||
| return true ; | ||
| } | ||
| BinaryTree.prototype._recursiveIncludes = function( element , current ) { | ||
| if ( isIdenticalTo( current.element , element ) ) { return true ; } | ||
| if ( current.left && this._recursiveIncludes( element , current.left ) ) { return true ; } | ||
| if ( current.right && this._recursiveIncludes( element , current.right ) ) { return true ; } | ||
| return false ; | ||
| return this.includes( searchElement , current.left ) || this.includes( searchElement , current.right ) ; | ||
| } ; | ||
@@ -652,6 +798,15 @@ | ||
| BinaryTree.prototype.forEach = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| fn.call( thisArg , current.element , current.key , this ) ; | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| fn.call( thisArg , element , current.key , this ) ; | ||
| } | ||
| } | ||
| else { | ||
| fn.call( thisArg , current.element , current.key , this ) ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -664,6 +819,15 @@ } | ||
| BinaryTree.prototype.some = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( fn.call( thisArg , current.element , current.key , this ) ) { return true ; } | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| if ( fn.call( thisArg , element , current.key , this ) ) { return true ; } | ||
| } | ||
| } | ||
| else if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| return true ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -678,6 +842,15 @@ } | ||
| BinaryTree.prototype.every = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( ! fn.call( thisArg , current.element , current.key , this ) ) { return false ; } | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| if ( ! fn.call( thisArg , element , current.key , this ) ) { return false ; } | ||
| } | ||
| } | ||
| else if ( ! fn.call( thisArg , current.element , current.key , this ) ) { | ||
| return false ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -692,6 +865,12 @@ } | ||
| BinaryTree.prototype.find = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| if ( fn.call( thisArg , element , current.key , this ) ) { return element ; } | ||
| } | ||
| } | ||
| else if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| return current.element ; | ||
@@ -709,6 +888,12 @@ } | ||
| BinaryTree.prototype.findKey = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| if ( fn.call( thisArg , element , current.key , this ) ) { return current.key ; } | ||
| } | ||
| } | ||
| else if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| return current.key ; | ||
@@ -728,8 +913,16 @@ } | ||
| BinaryTree.prototype.map = function( fn , thisArg ) { | ||
| var array = new Array( this.length ) , | ||
| index = 0 , | ||
| var element , index = 0 , | ||
| array = new Array( this.length ) , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| array[ index ++ ] = fn.call( thisArg , current.element , current.key , this ) ; | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| array[ index ++ ] = fn.call( thisArg , element , current.key , this ) ; | ||
| } | ||
| } | ||
| else { | ||
| array[ index ++ ] = fn.call( thisArg , current.element , current.key , this ) ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -744,6 +937,15 @@ } | ||
| BinaryTree.prototype.reduce = function( fn , accumulator ) { | ||
| var current = this.getHeadNode() ; | ||
| var element , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| accumulator = fn( accumulator , current.element , current.key , this ) ; | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| accumulator = fn( accumulator , element , current.key , this ) ; | ||
| } | ||
| } | ||
| else { | ||
| accumulator = fn( accumulator , current.element , current.key , this ) ; | ||
| } | ||
| current = this.nextNode( current ) ; | ||
@@ -758,6 +960,18 @@ } | ||
| BinaryTree.prototype.reduceRight = function( fn , accumulator ) { | ||
| var current = this.getTailNode() ; | ||
| var index , element , | ||
| current = this.getTailNode() ; | ||
| while ( current ) { | ||
| accumulator = fn( accumulator , current.element , current.key , this ) ; | ||
| if ( current.element instanceof Stack ) { | ||
| // Not sure if it makes sense to call it backward, since it's not backward at all... | ||
| index = current.element.length ; | ||
| while ( index -- ) { | ||
| element = current.element[ index ] ; | ||
| accumulator = fn( accumulator , element , current.key , this ) ; | ||
| } | ||
| } | ||
| else { | ||
| accumulator = fn( accumulator , current.element , current.key , this ) ; | ||
| } | ||
| current = this.previousNode( current ) ; | ||
@@ -774,8 +988,12 @@ } | ||
| BinaryTree.prototype.filter = function( fn , thisArg ) { | ||
| var array = [] , | ||
| index = 0 , | ||
| var element , index = 0 , array = [] , | ||
| current = this.getHeadNode() ; | ||
| while ( current ) { | ||
| if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| if ( current.element instanceof Stack ) { | ||
| for ( element of current.element ) { | ||
| if ( fn.call( thisArg , element , current.key , this ) ) { array[ index ++ ] = element ; } | ||
| } | ||
| } | ||
| else if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| array[ index ++ ] = current.element ; | ||
@@ -793,36 +1011,2 @@ } | ||
| /* | ||
| Advanced custom features | ||
| */ | ||
| // Delete all occurences of a value | ||
| BinaryTree.prototype.deleteValue = | ||
| BinaryTree.prototype.removeValue = function( value ) { | ||
| this.inPlaceFilter( e => ! isIdenticalTo( e , value ) ) ; | ||
| } ; | ||
| BinaryTree.prototype.inPlaceFilter = function( fn , thisArg ) { | ||
| var current = this.getHeadNode() , | ||
| next ; | ||
| while ( current ) { | ||
| if ( fn.call( thisArg , current.element , current.key , this ) ) { | ||
| current = this.nextNode( current ) ; | ||
| } | ||
| else { | ||
| next = this.nextNode( current ) ; | ||
| this.deleteNode( current ) ; | ||
| current = next ; | ||
| } | ||
| } | ||
| return this ; | ||
| } ; | ||
| /* | ||
| Internal, low-level | ||
@@ -1033,4 +1217,4 @@ */ | ||
| /* | ||
| excluding: exclude the current key | ||
| direction: how to choose a node for a non uniqueKeys tree or when excluding the key: | ||
| including: include the current key if it exists | ||
| direction: how to choose a node when excluding the key: | ||
| * unset: don't care | ||
@@ -1040,3 +1224,3 @@ * 1: forward direction, choose the left-most node | ||
| */ | ||
| BinaryTree.prototype.getClosestNode = function( key , excluding , direction ) { | ||
| BinaryTree.prototype.getClosestNode = function( key , including , direction ) { | ||
| if ( ! this.trunc ) { return null ; } | ||
@@ -1052,41 +1236,5 @@ | ||
| if ( node.key === key ) { | ||
| if ( excluding ) { | ||
| if ( this.uniqueKeys ) { | ||
| if ( direction > 0 ) { return this.nextNode( node ) ; } | ||
| return this.previousNode( node ) ; | ||
| } | ||
| if ( direction > 0 ) { | ||
| do { | ||
| node = this.nextNode( node ) ; | ||
| } while ( node && node.key === key ) ; | ||
| return node ; | ||
| } | ||
| do { | ||
| node = this.previousNode( node ) ; | ||
| } while ( node && node.key === key ) ; | ||
| return node ; | ||
| } | ||
| else if ( this.uniqueKeys ) { | ||
| return node ; | ||
| } | ||
| else if ( direction > 0 ) { | ||
| if ( ! node.left || node.left.key !== key ) { return node ; } | ||
| lastRightAncestor = lastNode = node ; | ||
| lastDirection = -1 ; | ||
| node = node.left ; | ||
| } | ||
| else { // if ( direction < 0 ) { | ||
| if ( ! node.right || node.right.key !== key ) { return node ; } | ||
| lastLeftAncestor = lastNode = node ; | ||
| lastDirection = 1 ; | ||
| node = node.right ; | ||
| } | ||
| if ( including ) { return node ; } | ||
| if ( direction > 0 ) { return this.nextNode( node ) ; } | ||
| return this.previousNode( node ) ; | ||
| } | ||
@@ -1120,2 +1268,51 @@ else if ( this.isOrdered( node.key , key ) ) { | ||
| // .deleteNode() uses it | ||
| BinaryTree.prototype.swapNodes = function( a , b ) { | ||
| var aParent = a.parent , | ||
| bParent = b.parent , | ||
| aLeft = a.left , | ||
| bLeft = b.left , | ||
| aRight = a.right , | ||
| bRight = b.right , | ||
| aDepth = a.depth , | ||
| bDepth = b.depth ; | ||
| // Swap nodes' refs | ||
| a.parent = bParent !== a ? bParent : b ; | ||
| b.parent = aParent !== b ? aParent : a ; | ||
| a.left = bLeft !== a ? bLeft : b ; | ||
| b.left = aLeft !== b ? aLeft : a ; | ||
| a.right = bRight !== a ? bRight : b ; | ||
| b.right = aRight !== b ? aRight : a ; | ||
| a.depth = bDepth ; | ||
| b.depth = aDepth ; | ||
| // Swap parents' refs | ||
| if ( bParent ) { | ||
| if ( bParent !== a ) { bParent[ b === bParent.left ? 'left' : 'right' ] = a ; } | ||
| } | ||
| else { | ||
| this.trunc = a ; | ||
| } | ||
| if ( aParent ) { | ||
| if ( aParent !== b ) { aParent[ a === aParent.left ? 'left' : 'right' ] = b ; } | ||
| } | ||
| else { | ||
| this.trunc = b ; | ||
| } | ||
| // Fix children's refs | ||
| if ( a.left ) { a.left.parent = a ; } | ||
| if ( a.right ) { a.right.parent = a ; } | ||
| if ( b.left ) { b.left.parent = b ; } | ||
| if ( b.right ) { b.right.parent = b ; } | ||
| } ; | ||
| // DEPRECATED? | ||
@@ -1153,3 +1350,5 @@ // Delete subtree without re-balancing | ||
| BinaryTree.prototype.debug = function( node = this.trunc , spaces = 0 , prefix = '━' ) { | ||
| const util = require( 'util' ) ; | ||
| BinaryTree.prototype.debug = function( node = this.trunc , spaces = 0 , prefix = '━' , showValue = false ) { | ||
| if ( ! node ) { | ||
@@ -1167,4 +1366,8 @@ console.log( '(empty)' ) ; | ||
| if ( showValue ) { | ||
| str += ' => ' + util.inspect( node.element ) ; | ||
| } | ||
| if ( node.right ) { | ||
| this.debug( node.right , nextSpaces , '┏' ) ; | ||
| this.debug( node.right , nextSpaces , '┏' , showValue ) ; | ||
| } | ||
@@ -1175,6 +1378,7 @@ | ||
| if ( node.left ) { | ||
| this.debug( node.left , nextSpaces , '┗' ) ; | ||
| this.debug( node.left , nextSpaces , '┗' , showValue ) ; | ||
| } | ||
| } ; | ||
| BinaryTree.prototype.debugValues = function() { return this.debug( this.trunc , 0 , '━' , true ) ; } ; | ||
@@ -1209,3 +1413,2 @@ | ||
| assert.strictEqual( node.tree , this , "Current node doesn't belong to the current tree, key: " + node.key ) ; | ||
| assert.strictEqual( node.parent , parentNode , "Parent mismatch, key: " + node.key ) ; | ||
@@ -1212,0 +1415,0 @@ |
+5
-3
| { | ||
| "name": "chain-lightning", | ||
| "version": "0.3.0", | ||
| "version": "0.4.0", | ||
| "description": "Linked list", | ||
@@ -12,3 +12,5 @@ "main": "lib/chainlightning.js", | ||
| }, | ||
| "dependencies": {}, | ||
| "dependencies": { | ||
| "array-kit": "^0.2.2" | ||
| }, | ||
| "scripts": { | ||
@@ -44,2 +46,2 @@ "test": "tea-time -R dot -O" | ||
| } | ||
| } | ||
| } |
+261
-93
@@ -87,3 +87,3 @@ /* | ||
| tree = new BinaryTree() ; | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
@@ -102,5 +102,6 @@ tree.set( 3 , 'jack' ) ; | ||
| tree.set( 2.77 , 'vlad' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' ] ) ; | ||
| tree.add( 6 , 'bob' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' , 'bob' ] ) ; | ||
| expect( tree.keys() ).to.equal( [ 2 , 2.5 , 2.7 , 2.72 , 2.75 , 2.76 , 2.77 , 2.8 , 2.85 , 3 , 5 , 6 ] ) ; | ||
| expect( [ ... tree.values() ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' ] ) ; | ||
| expect( [ ... tree.values() ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' , 'bob' ] ) ; | ||
| } ) ; | ||
@@ -177,28 +178,56 @@ | ||
| it( "duplicated keys and the 'uniqueKeys' option" , () => { | ||
| it( "add and get elements in conjunction with the 'stack' option" , () => { | ||
| var tree ; | ||
| tree = new BinaryTree() ; | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| // Without uniqueKeys | ||
| tree.set( 2 , 'jean' ) ; | ||
| tree.set( 3 , 'jack' ) ; | ||
| // Try getting unexisting keys | ||
| expect( tree.get( 0 ) ).to.be( undefined ) ; | ||
| expect( tree.get( 9 ) ).to.be( undefined ) ; | ||
| tree.add( 3 , 'jack' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jack' ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.add( 2 , 'jean' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'jack' ] ) ; | ||
| expect( [ ... tree.keys() ] ).to.equal( [ 2 , 3 ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.set( 2 , 'bob' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'bob' , 'jack' ] ) ; | ||
| expect( [ ... tree.keys() ] ).to.equal( [ 2 , 2 , 3 ] ) ; | ||
| tree.add( 5 , 'steve' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'jack' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| // With uniqueKeys | ||
| tree = new BinaryTree( { uniqueKeys: true } ) ; | ||
| tree.set( 2 , 'jean' ) ; | ||
| tree.set( 3 , 'jack' ) ; | ||
| tree.set( 2 , 'bob' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'bob' , 'jack' ] ) ; | ||
| expect( [ ... tree.keys() ] ).to.equal( [ 2 , 3 ] ) ; | ||
| tree.add( 2.5 , 'john' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'jack' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.add( 2.7 , 'robert' ) ; | ||
| expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'jack' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.add( 3 , 'bobby' ) ; | ||
| expect( [ ... tree ] ).to.be.like( [ 'jean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.add( 2 , 'jeanjean' ) ; | ||
| expect( [ ... tree ] ).to.be.like( [ 'jean' , 'jeanjean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| tree.add( 2 , 'jeanjeanjean' ) ; | ||
| expect( [ ... tree ] ).to.be.like( [ 'jean' , 'jeanjean' , 'jeanjeanjean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ; | ||
| tree.sanityCheck() ; | ||
| //tree.debug() ; | ||
| expect( tree.get( 3 ) ).to.be.a( BinaryTree.Stack ) ; | ||
| expect( tree.get( 3 ) ).to.be.like( [ 'jack' , 'bobby' ] ) ; | ||
| expect( tree.get( 2 ) ).to.be.a( BinaryTree.Stack ) ; | ||
| expect( tree.get( 2 ) ).to.be.like( [ 'jean' , 'jeanjean' , 'jeanjeanjean' ] ) ; | ||
| expect( tree.get( 5 ) ).to.be( 'steve' ) ; | ||
| expect( tree.get( 2.5 ) ).to.be( 'john' ) ; | ||
| expect( tree.get( 2.7 ) ).to.be( 'robert' ) ; | ||
| // Try getting unexisting keys | ||
| expect( tree.get( 0 ) ).to.be( undefined ) ; | ||
| expect( tree.get( 9 ) ).to.be( undefined ) ; | ||
| } ) ; | ||
@@ -223,3 +252,5 @@ | ||
| } ) ; | ||
| it( ".insertUnique()" ) ; | ||
| it( "delete by key" , () => { | ||
@@ -301,3 +332,3 @@ var tree ; | ||
| tree = new BinaryTree( { uniqueKeys: true } , e1 , e2 , e3 ) ; | ||
| tree = new BinaryTree( null , e1 , e2 , e3 ) ; | ||
| expect( tree.keyOf( e2 ) ).to.be( 1 ) ; | ||
@@ -311,2 +342,20 @@ expect( tree.keyOf( e4 ) ).to.be( undefined ) ; | ||
| expect( [ ... tree ] ).to.equal( [ { v: 'jack' } , { v: 'bobby' } , { v: 'steve' } , { v: 'bob' } , { v: 'bob' } , { v: 'bobby' } ] ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e1 ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 4 , e1 ) ; | ||
| tree.add( 4 , e2 ) ; | ||
| tree.add( 4.5 , e3 ) ; | ||
| expect( tree.keyOf( e1 ) ).to.be( 2 ) ; | ||
| expect( tree.keyOf( e2 ) ).to.be( 2 ) ; | ||
| expect( tree.keyOf( e3 ) ).to.be( 2.5 ) ; | ||
| expect( tree.keyOf( e4 ) ).to.be( undefined ) ; | ||
| expect( tree.lastKeyOf( e1 ) ).to.be( 4 ) ; | ||
| expect( tree.lastKeyOf( e2 ) ).to.be( 4 ) ; | ||
| expect( tree.lastKeyOf( e3 ) ).to.be( 4.5 ) ; | ||
| expect( tree.lastKeyOf( e4 ) ).to.be( undefined ) ; | ||
| } ) ; | ||
@@ -318,3 +367,4 @@ | ||
| e2 = { v: 'bob' } , | ||
| e3 = { v: 'steve' } ; | ||
| e3 = { v: 'steve' } , | ||
| e4 = { v: 'bobby' } ; | ||
@@ -344,7 +394,17 @@ tree = new BinaryTree() ; | ||
| expect( tree.includes( e2 ) ).to.be.true() ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e1 ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| expect( tree.includes( e1 ) ).to.be.true() ; | ||
| expect( tree.includes( e2 ) ).to.be.true() ; | ||
| expect( tree.includes( e3 ) ).to.be.true() ; | ||
| expect( tree.includes( e4 ) ).to.be.false() ; | ||
| } ) ; | ||
| it( ".forEach()" , () => { | ||
| var tree , | ||
| accumulator = [] , | ||
| var tree , values , keys , | ||
| e1 = { v: 'jack' } , | ||
@@ -354,9 +414,26 @@ e2 = { v: 'bob' } , | ||
| keys = [] ; | ||
| values = [] ; | ||
| tree = new BinaryTree() ; | ||
| tree.forEach( element => accumulator.push( element.v ) ) ; | ||
| expect( accumulator ).to.equal( [] ) ; | ||
| tree.forEach( element => values.push( element.v ) ) ; | ||
| expect( values ).to.equal( [] ) ; | ||
| keys = [] ; | ||
| values = [] ; | ||
| tree = new BinaryTree( null , e1 , e2 , e3 ) ; | ||
| tree.forEach( element => accumulator.push( element.v ) ) ; | ||
| expect( accumulator ).to.equal( [ 'jack' , 'bob' , 'steve' ] ) ; | ||
| tree.forEach( element => values.push( element.v ) ) ; | ||
| expect( values ).to.equal( [ 'jack' , 'bob' , 'steve' ] ) ; | ||
| keys = [] ; | ||
| values = [] ; | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e1 ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 2.5 , e1 ) ; | ||
| tree.add( 2.2 , e2 ) ; | ||
| tree.forEach( ( element , key ) => { keys.push( key ) ; values.push( element.v ) ; } ) ; | ||
| expect( keys ).to.equal( [ 2 , 2 , 2.2 , 2.5 , 2.5 , 2.5 ] ) ; | ||
| expect( values ).to.equal( [ 'jack' , 'bob' , 'bob' , 'steve' , 'steve' , 'jack' ] ) ; | ||
| } ) ; | ||
@@ -401,2 +478,22 @@ | ||
| expect( tree.every( element => element.v === 'bob' ) ).to.be.true() ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| expect( tree.some( element => element.v === 'jack' ) ).to.be.false() ; | ||
| expect( tree.every( element => element.v === 'jack' ) ).to.be.false() ; | ||
| expect( tree.some( element => element.v === 'bob' ) ).to.be.true() ; | ||
| expect( tree.every( element => element.v === 'bob' ) ).to.be.true() ; | ||
| expect( tree.some( element => element.v === 'steve' ) ).to.be.false() ; | ||
| expect( tree.every( element => element.v === 'steve' ) ).to.be.false() ; | ||
| tree.add( 2 , e1 ) ; | ||
| expect( tree.some( element => element.v === 'jack' ) ).to.be.true() ; | ||
| expect( tree.every( element => element.v === 'jack' ) ).to.be.false() ; | ||
| expect( tree.some( element => element.v === 'bob' ) ).to.be.true() ; | ||
| expect( tree.every( element => element.v === 'bob' ) ).to.be.false() ; | ||
| expect( tree.some( element => element.v === 'steve' ) ).to.be.false() ; | ||
| expect( tree.every( element => element.v === 'steve' ) ).to.be.false() ; | ||
| } ) ; | ||
@@ -420,2 +517,13 @@ | ||
| expect( tree.find( element => element.v === 'bob' ) ).to.be( e4 ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| expect( tree.find( element => element.v === 'jack' ) ).to.be( e1 ) ; | ||
| expect( tree.find( element => element.v === 'bob' ) ).to.be( e2 ) ; | ||
| expect( tree.find( element => element.v === 'steve' ) ).to.be( undefined ) ; | ||
| } ) ; | ||
@@ -440,6 +548,17 @@ | ||
| expect( tree.findKey( element => element.v === 'bob' ) ).to.be( 3 ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| expect( tree.findKey( element => element.v === 'jack' ) ).to.be( 1 ) ; | ||
| expect( tree.findKey( element => element.v === 'bob' ) ).to.be( 2 ) ; | ||
| expect( tree.findKey( element => element.v === 'steve' ) ).to.be( undefined ) ; | ||
| } ) ; | ||
| it( ".arrayMap()" , () => { | ||
| var array , | ||
| it( ".map() (or alias .arrayMap())" , () => { | ||
| var tree , array , | ||
| e1 = { v: 'jack' } , | ||
@@ -449,3 +568,3 @@ e2 = { v: 'bob' } , | ||
| array = new BinaryTree( null ).arrayMap( element => element.v + element.v ) ; | ||
| array = new BinaryTree( null ).map( element => element.v + element.v ) ; | ||
| expect( array ).to.equal( [] ) ; | ||
@@ -458,2 +577,12 @@ | ||
| expect( array ).to.equal( [ 'jackjack' , 'bobbob' , 'stevesteve' ] ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| array = tree.map( element => element.v + element.v ) ; | ||
| expect( array ).to.equal( [ 'jackjack' , 'bobbob' , 'stevesteve' , 'bobbob' ] ) ; | ||
| } ) ; | ||
@@ -478,6 +607,16 @@ | ||
| expect( tree.reduceRight( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'stevebobjack' ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| expect( tree.reduce( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'jackbobstevebob' ) ; | ||
| expect( tree.reduceRight( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'bobstevebobjack' ) ; | ||
| } ) ; | ||
| it( ".arrayFilter()" , () => { | ||
| var array , | ||
| it( ".filter() (or alias .arrayFilter())" , () => { | ||
| var tree , array , | ||
| e1 = { v: 'jack' } , | ||
@@ -507,2 +646,14 @@ e2 = { v: 'bob' } , | ||
| expect( array ).to.equal( [ e2 ] ) ; | ||
| // Stack | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 2 , e2 ) ; | ||
| tree.add( 2.5 , e3 ) ; | ||
| tree.add( 2.5 , e2 ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| expect( tree.filter( element => element.v.length < 4 ) ).to.equal( [ e2 , e2 ] ) ; | ||
| expect( tree.filter( element => element.v.length > 4 ) ).to.equal( [ e3 ] ) ; | ||
| expect( tree.filter( element => element.v.length <= 4 ) ).to.equal( [ e1 , e2 , e2 ] ) ; | ||
| expect( tree.filter( element => element.v.length >= 4 ) ).to.equal( [ e1 , e3 ] ) ; | ||
| } ) ; | ||
@@ -513,3 +664,3 @@ } ) ; | ||
| it( ".deleteValue()" , () => { | ||
| it( ".deleteValue() (and alias .removeValue())" , () => { | ||
| var tree , | ||
@@ -557,2 +708,19 @@ e1 = { v: 'jack' } , | ||
| tree.sanityCheck() ; | ||
| // Stacked values | ||
| tree = new BinaryTree( { stack: true } ) ; | ||
| tree.add( 1 , e1 ) ; | ||
| tree.add( 1 , e4 ) ; | ||
| tree.add( 2 , e1 ) ; | ||
| tree.add( 3 , e2 ) ; | ||
| tree.add( 3 , e1 ) ; | ||
| tree.add( 3 , e3 ) ; | ||
| tree.add( 4 , e4 ) ; | ||
| //tree.debugValues() ; | ||
| expect( [ ... tree ] ).to.equal( [ e1 , e4 , e1 , e2 , e1 , e3 , e4 ] ) ; | ||
| tree.deleteValue( e1 ) ; | ||
| //tree.debugValues() ; | ||
| expect( [ ... tree ] ).to.equal( [ e4 , e2 , e3 , e4 ] ) ; | ||
| tree.sanityCheck() ; | ||
| } ) ; | ||
@@ -996,38 +1164,64 @@ | ||
| // Including existing | ||
| expect( tree.getClosestNode( 2 , false , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2 , false , 1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.72 , false , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.72 , false , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.8 , false , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.8 , false , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.85 , false , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.85 , false , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 6 , false , -1 ).key ).to.be( 6 ) ; | ||
| expect( tree.getClosestNode( 6 , false , 1 ).key ).to.be( 6 ) ; | ||
| expect( tree.getClosestNode( 2 , true , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2 , true , 1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.72 , true , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.72 , true , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.8 , true , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.8 , true , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.85 , true , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.85 , true , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 6 , true , -1 ).key ).to.be( 6 ) ; | ||
| expect( tree.getClosestNode( 6 , true , 1 ).key ).to.be( 6 ) ; | ||
| // Excluding existing | ||
| expect( tree.getClosestNode( 2 , true , -1 ) ).to.be( null ) ; | ||
| expect( tree.getClosestNode( 2 , true , 1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.5 , true , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.5 , true , 1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.7 , true , -1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.7 , true , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.72 , true , -1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.72 , true , 1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.75 , true , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.75 , true , 1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.76 , true , -1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.76 , true , 1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.77 , true , -1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.77 , true , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.8 , true , -1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.8 , true , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.85 , true , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.85 , true , 1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 3 , true , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 3 , true , 1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 6 , true , -1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 6 , true , 1 ) ).to.be( null ) ; | ||
| expect( tree.getClosestNode( 2 , false , -1 ) ).to.be( null ) ; | ||
| expect( tree.getClosestNode( 2 , false , 1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.5 , false , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.5 , false , 1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.7 , false , -1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.7 , false , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.72 , false , -1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.72 , false , 1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.75 , false , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.75 , false , 1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.76 , false , -1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.76 , false , 1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.77 , false , -1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.77 , false , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.8 , false , -1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.8 , false , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.85 , false , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.85 , false , 1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 3 , false , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 3 , false , 1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 6 , false , -1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 6 , false , 1 ) ).to.be( null ) ; | ||
| // Including unexisting | ||
| expect( tree.getClosestNode( 1 , true , -1 ) ).to.be( null ) ; | ||
| expect( tree.getClosestNode( 1 , true , 1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.1 , true , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.1 , true , 1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.6 , true , -1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.6 , true , 1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.71 , true , -1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.71 , true , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.73 , true , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.73 , true , 1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.755 , true , -1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.755 , true , 1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.765 , true , -1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.765 , true , 1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.78 , true , -1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.78 , true , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.84 , true , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.84 , true , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.9 , true , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.9 , true , 1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 4 , true , -1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 4 , true , 1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 7 , true , -1 ).key ).to.be( 6 ) ; | ||
| expect( tree.getClosestNode( 7 , true , 1 ) ).to.be( null ) ; | ||
| // Excluding unexisting -- should be identical to 'including unexisting' | ||
| expect( tree.getClosestNode( 1 , false , -1 ) ).to.be( null ) ; | ||
@@ -1057,28 +1251,2 @@ expect( tree.getClosestNode( 1 , false , 1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 7 , false , 1 ) ).to.be( null ) ; | ||
| // Excluding unexisting -- should be identical to 'including unexisting' | ||
| expect( tree.getClosestNode( 1 , true , -1 ) ).to.be( null ) ; | ||
| expect( tree.getClosestNode( 1 , true , 1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.1 , true , -1 ).key ).to.be( 2 ) ; | ||
| expect( tree.getClosestNode( 2.1 , true , 1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.6 , true , -1 ).key ).to.be( 2.5 ) ; | ||
| expect( tree.getClosestNode( 2.6 , true , 1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.71 , true , -1 ).key ).to.be( 2.7 ) ; | ||
| expect( tree.getClosestNode( 2.71 , true , 1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.73 , true , -1 ).key ).to.be( 2.72 ) ; | ||
| expect( tree.getClosestNode( 2.73 , true , 1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.755 , true , -1 ).key ).to.be( 2.75 ) ; | ||
| expect( tree.getClosestNode( 2.755 , true , 1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.765 , true , -1 ).key ).to.be( 2.76 ) ; | ||
| expect( tree.getClosestNode( 2.765 , true , 1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.78 , true , -1 ).key ).to.be( 2.77 ) ; | ||
| expect( tree.getClosestNode( 2.78 , true , 1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.84 , true , -1 ).key ).to.be( 2.8 ) ; | ||
| expect( tree.getClosestNode( 2.84 , true , 1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.9 , true , -1 ).key ).to.be( 2.85 ) ; | ||
| expect( tree.getClosestNode( 2.9 , true , 1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 4 , true , -1 ).key ).to.be( 3 ) ; | ||
| expect( tree.getClosestNode( 4 , true , 1 ).key ).to.be( 5 ) ; | ||
| expect( tree.getClosestNode( 7 , true , -1 ).key ).to.be( 6 ) ; | ||
| expect( tree.getClosestNode( 7 , true , 1 ) ).to.be( null ) ; | ||
| } ) ; | ||
@@ -1085,0 +1253,0 @@ } ) ; |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
128688
9.72%3272
10.24%0
-100%1
Infinity%4
100%+ Added
+ Added