UNPKG

ndn-js-contrib

Version:

Reusable 'Classes' for Named Data Networking: NameTree, PIT, FIB, ContentStore, Interfaces, and Transports

174 lines (156 loc) 4.9 kB
var NameTreeNode = require("./NameTreeNode.js") , binaryIndexOf = require("./../Utility/binarySearch.js") , ndn; /**Creates an empty NameTree. *@constructor */ var NameTree = function NameTree (){ this.addNode('/'); return this; }; NameTree.Node = NameTreeNode; /**Install ndn-lib. Only necessary if you're using require("ndn-Classes/src/DataStructures/NameTree.js"), done for you if require("ndn-Classes").NameTree *@private *@param {Object} NDN ndn-lib object */ NameTree.installNDN = function(NDN){ NameTree.Node.installNDN(NDN); ndn = NDN; return this; }; /** * Add a node to the NameTree, recursively populating all parents * @param {Name|String} prefix - the prefix for the new node. * @returns {NameTreeNode} node - the NameTree node created. */ NameTree.prototype.addNode = function(prefix){ if (typeof prefix === "string"){ prefix = new ndn.Name(prefix); } var self = this[prefix.toUri()]; if(self){ return self; } else { self = this[prefix.toUri()] = new NameTree.Node(prefix); while(prefix.size() > 0){ var parentPrefix = prefix.getPrefix(-1); if(!this[parentPrefix.toUri()]){ this[parentPrefix.toUri()] = new NameTree.Node(parentPrefix); } this[prefix.toUri()].parent = this[parentPrefix.toUri()]; this[parentPrefix.toUri()].addChild(this[prefix.toUri()]); prefix = parentPrefix; } } return self; }; /** * Delete a node (and all it's children, grandchildren, etc.). * @param {Name|URI} prefix - the name of the node to delete. * @returns {NameTree} the nameTree. */ NameTree.prototype.removeNode = function(prefix, cycleFinish){ if (typeof prefix === "string"){ prefix = new ndn.Name(prefix); } cycleFinish = cycleFinish || prefix; var self = this[prefix.toUri()]; if (!self){ return this; } else{ var child = self.children.shift(); if (child !== undefined){ return this.removeNode(child.prefix, cycleFinish); } else { delete this[self.prefix.toUri()]; if (cycleFinish.equals(prefix)){ self.parent.removeChild(self); return this; } else{ return this.removeNode(prefix.getPrefix(-1), cycleFinish); } } } }; /** * Perform a lookup on the NameTree and return the proper node, creating it if necessary. * @param {Name|URI} prefix the name of the node to lookup. * @returns {NameTreeNode} the resulting node. */ NameTree.prototype.lookup = function (prefix) { if (typeof prefix === "string"){ prefix = new ndn.Name(prefix); } var node = this[prefix.toUri()]; if (node){ return node; } else{ return (this.addNode(prefix)); } }; /** * Find the Longest Prefix Match in the NameTree that matches the selector * @param {Name|URI} prefix the name to lookup * @param {function} selector predicate function * @returns {NameTreeNode} the longest prefix match. */ NameTree.prototype.findLongestPrefixMatch = function(prefix, selector) { if (typeof prefix === "string"){ prefix = new ndn.Name(prefix); } selector = selector || function(){return true;}; var match = this[prefix.toUri()]; if ( match && selector(match)){ return match; } else if (prefix.size() > 0){ return this.findLongestPrefixMatch(prefix.getPrefix(-1), selector); } else { return null; } }; /** * Return an Iterator that provides a .next() method which returns the next longest Prefix matching the selector, returning null when depleted. * @param {Name} prefix - the prefix to begin iteration * @param {Function} selector - a selector function that returns a boolean when called with selector(node) * @returns {Object} Iterator - the .depleted property of the iterator will be true when there are no more matches. */ NameTree.prototype.findAllMatches = function(prefix, selector){ if (typeof prefix === "string"){ prefix = new ndn.Name(prefix); } selector = selector || function(){return true;}; var self = this , nextReturn = self[prefix.toUri()] , thisReturn , iterator = { next: function(){ if (!this.hasNext){ return null; } prefix = nextReturn.prefix; thisReturn = nextReturn; nextReturn = (thisReturn && thisReturn.parent && selector(thisReturn.parent)) ? thisReturn.parent : (prefix.size() > 0) ? self.findLongestPrefixMatch(prefix.getPrefix(-1), selector) : null ; if (!nextReturn){ this.hasNext = false; } else { this.hasNext = true; } return thisReturn; } }; if (nextReturn && selector(nextReturn)){ iterator.hasNext = true; return iterator; } else if (prefix.size() > 0){ return this.findAllMatches(prefix.getPrefix(-1), selector); } else{ iterator.hasNext = false; return iterator; } }; module.exports = NameTree;