ndn-js-contrib
Version:
Reusable 'Classes' for Named Data Networking: NameTree, PIT, FIB, ContentStore, Interfaces, and Transports
283 lines (282 loc) • 8.52 kB
JavaScript
var Name = require('ndn-js/js/name.js').Name;
function checkNode(functionName, node) {
if (!(node && node._isNTN))
throw new Error(functionName + ": invalid argument, requires a NameTreeNode");
}
var NameTree = function NameTree() {
this.root = new NameTree.Node(new Name(""));
var self = this;
this[Symbol.iterator] = function NameTree_Iterator() {
var iter;
if (self._traversal_direction + 1 === 0) {
throw new Error("NameTree[Symbol.iterator](): must use NameTree.up(prefix)/.left(prefix)/.right(prefix) to set traversal direction");
} else if (self._traversal_direction === NameTree.TRAVERSE_UP) {
iter = new Prefix_Iterator(self, self._traversal_prefix, self._skipper());
} else {
iter = new Suffix_Iterator(self, self._traversal_prefix, self._traversal_direction, this._skipper());
}
self._traversal_direction = -1;
self._traversal_prefix = null;
return iter;
};
return this;
};
NameTree.TRAVERSE_LEFT = 0;
NameTree.TRAVERSE_RIGHT = 1;
NameTree.TRAVERSE_UP = 2;
module.exports = NameTree;
NameTree.prototype.insert = function NameTree_insert(node) {
var curr = this.root;
while (!curr.equals(node)) {
curr = curr.insert(node);
}
curr.insert(node);
return this;
};
NameTree.prototype.remove = function NameTree_remove(prefix) {
this.up(prefix);
var first = true,
item = null,
removeSuffix;
var $__3 = true;
var $__4 = false;
var $__5 = undefined;
try {
for (var $__1 = void 0,
$__0 = (this)[$traceurRuntime.toProperty(Symbol.iterator)](); !($__3 = ($__1 = $__0.next()).done); $__3 = true) {
var node = $__1.value;
{
if (first) {
item = node.getItem();
node.setItem(null);
}
first = false;
if (removeSuffix)
node.remove(removeSuffix);
removeSuffix = false;
if (node.isEmpty() && node.prefix.size() > 0)
removeSuffix = node.prefix.get(-1);
else {
node.updateDepth(~(prefix.size() - node.prefix.size()));
}
}
}
} catch ($__6) {
$__4 = true;
$__5 = $__6;
} finally {
try {
if (!$__3 && $__0.return != null) {
$__0.return();
}
} finally {
if ($__4) {
throw $__5;
}
}
}
if (removeSuffix)
this.root.remove(removeSuffix);
else
this.root.updateDepth(~prefix.size());
return item;
};
NameTree.prototype.get = function NameTree_get(prefix) {
var node = new NameTree.Node(prefix);
var curr = this.root;
while (!curr.equals(node)) {
curr = curr.insert(node);
}
node = curr;
return node;
};
function Prefix_Iterator(nameTree, prefix, skip) {
var node = new NameTree.Node(prefix);
var curr = nameTree.root;
this._stack = [];
while (!curr.equals(node)) {
if (!skip(curr))
this._stack.push(curr);
curr = curr.insert(node);
}
if (!skip(curr))
this._stack.push(curr);
}
Prefix_Iterator.prototype.next = function NameTree_Iterator_next() {
var done = (this._stack.length === 0);
if (!done)
var next = this._stack.pop();
return {
value: next,
done: done
};
};
function Suffix_Iterator(nameTree, prefix, _reverse, skip) {
this._stack = [(_reverse) ? nameTree.get(prefix)._reverse()[Symbol.iterator]() : nameTree.get(prefix)[Symbol.iterator]()];
this._reverse = _reverse;
this.skip = skip;
this.first = [nameTree.get(prefix)];
return this;
}
Suffix_Iterator.prototype.next = function Suffix_Iterator_next() {
if (this.first.length) {
return (!this.skip(this.first[0])) ? {
value: this.first.pop(),
done: false
} : {
value: null,
done: true
};
}
var iter = this._stack.pop();
while (iter) {
do {
var next = iter.next();
if (next.done)
break;
} while (this.skip(next.value));
if (!next.done) {
this._stack.push(iter);
this._stack.push((this._reverse) ? next.value._reverse()[Symbol.iterator]() : next.value[Symbol.iterator]());
return next;
} else {
iter = this._stack.pop();
}
}
return {
value: null,
done: true
};
};
NameTree.prototype.skip = function NameTree_skip(skip) {
var self = this;
this._skipper = function _skipper() {
self._skipper = NameTree.prototype._skipper;
return skip;
};
};
NameTree.prototype._skipper = function NameTree__skipper() {
return function skip() {
return false;
};
};
NameTree.prototype.up = function NameTree_up(prefix, skip) {
this._traversal_direction = NameTree.TRAVERSE_UP;
this._traversal_prefix = prefix || this.head;
};
NameTree.prototype.left = function NameTree_left(prefix) {
this._traversal_direction = NameTree.TRAVERSE_LEFT;
this._traversal_prefix = prefix || this.root.prefix;
};
NameTree.prototype.right = function NameTree_right(prefix) {
this._traversal_direction = NameTree.TRAVERSE_RIGHT;
this._traversal_prefix = prefix || this.root.prefix;
};
NameTree.prototype._traversal_direction = -1;
NameTree.prototype._traversal_start = null;
NameTree.Node = function NameTree_Node(prefix, item) {
this.item = item;
this.children = [];
this.prefix = prefix;
this.depth = 0;
var self = this;
this[Symbol.iterator] = function NameTree_Node_Iterator() {
var iter = new Child_Iterator(self, self._traversal_direction, self._skipper());
self._traversal_direction = NameTree.TRAVERSE_LEFT;
return iter;
};
return this;
};
NameTree.Node.prototype.depth = function NameTree_Node_depth() {
return this.depth;
};
NameTree.Node.prototype.skip = NameTree.prototype.skip;
NameTree.Node.prototype._skipper = NameTree.prototype._skipper;
NameTree.Node.prototype.equals = function NameTree_Node_equals(node) {
return this.prefix.equals(node.prefix);
};
NameTree.Node.prototype.getItem = function NameTree_Node_getItem() {
return this.item;
};
NameTree.Node.prototype.setItem = function NameTree_Node_setItem(item) {
this.item = item;
};
NameTree.Node.prototype.indexOf = function NameTree_Node_indexOf(suffix) {
var min = 0,
max = this.children.length - 1,
guess,
comparison;
while (min <= max) {
guess = Math.floor((min + max) / 2);
if (this.children[guess].prefix.get(-1).equals(suffix)) {
return guess;
} else {
comparison = this.children[guess].prefix.get(-1).compare(suffix);
if (comparison < 0)
min = ++guess;
else
max = --guess;
}
}
return ~(max + 1);
};
NameTree.Node.prototype.insert = function NameTree_Node_insert(node) {
if (this.equals(node)) {
if (this.item && node.item)
throw new Error("NameTree.Node.insert: Already have that node with an Item");
else if (!this.getItem() && node.getItem()) {
this.setItem(node.getItem());
}
return this;
}
var suffix = node.prefix.get(this.prefix.size()),
childIndex = this.indexOf(suffix),
insertion;
if (childIndex < 0) {
childIndex = ~childIndex;
insertion = new NameTree.Node(node.prefix.getPrefix(this.prefix.size() + 1));
this.children.splice(childIndex, 0, insertion);
} else {
insertion = this.children[childIndex];
}
this.updateDepth(node.prefix.size() - this.prefix.size());
return insertion;
};
NameTree.Node.prototype.updateDepth = function NameTree_Node_updateDepth(depth) {
this.depth = (depth && depth > this.depth) ? depth : (depth) ? this.depth : (this.children.length === 0) ? 0 : Math.max.apply(null, this.children.map(function(child) {
return child.depth;
})) + 1;
};
NameTree.Node.prototype.remove = function NameTree_Node_remove(suffix) {
var childIndex = this.indexOf(suffix),
node;
if (childIndex < 0)
node = null;
else
node = this.children.splice(childIndex, 1)[0];
this.updateDepth();
return node;
};
NameTree.Node.prototype._reverse = function NameTree_Node__reverse() {
this._traversal_direction = NameTree.TRAVERSE_RIGHT;
return this;
};
NameTree.Node.prototype.isEmpty = function NameTree_Node_isEmpty() {
return (!this.children.length && !this.item);
};
NameTree.Node.prototype._traversal_direction = NameTree.TRAVERSE_LEFT;
function Child_Iterator(node, direction, skip) {
this.direction = direction;
this.children = node.children.slice(0);
this.skip = skip;
}
Child_Iterator.prototype.next = function() {
var next;
do {
next = (!this.direction) ? this.children.shift() : this.children.pop();
} while (next && this.skip(next));
return {
done: (!next && !this.children.length) ? true : false,
value: next
};
};