3d-interface/js/List.js

241 lines
5.5 KiB
JavaScript

var utils = (function() {
var utils = {};
// Defines a double linked-list class
utils.List = function() {
this._size = 0;
this._begin = null;
this._end = null;
}
// Returns the number of element of a list
utils.List.prototype.size = function() {
return this._size;
}
// Pushes an element to the end of a class
utils.List.prototype.push = function(element) {
if (this._size === 0) {
this._begin = { data : element, next: null, prev: null };
this._end = this._begin;
this._size = 1;
} else {
var newObject = { data: element, next: null, prev: this._end };
this._end.next = newObject;
this._end = newObject;
this._size++;
}
}
// Sort the list
utils.List.prototype.sort = function(comparator) {
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
var array = [];
this.forEach(function(elt) {
array.push(elt);
});
array.sort(function(a, b) {
return comparator(a, b);
});
var size = this.size();
this.clear();
for (var i = 0; i < size; i++) {
this.push(array[i]);
}
}
// Remove last element and returns it
utils.List.prototype.pop = function() {
var tmp = this._end;
this._end = null;
return tmp.data;
}
// Apply a function to each element of the list
utils.List.prototype.forEach = function(callback) {
var chain = this._begin;
while (chain !== null) {
callback(chain.data);
chain = chain.next;
}
}
// Apply a function to each element of the list (starting from the end)
utils.List.prototype.forEachInverse = function(callback) {
var chain = this._end;
while (chain !== null) {
callback(chain.data);
chain = chain.prev;
}
}
// Get ith element of the list
utils.List.prototype.at = function(ith) {
if (ith < 0 || ith >= this.size()) {
return null;
}
var chain = this._begin;
for (var i = 0; i < ith; i++) {
chain = chain.next;
}
return chain.data;
}
// Clear the list
utils.List.prototype.clear = function() {
this._begin = null;
this._end = null;
this._size = 0;
}
// Insert an element at the right place in the list
// Precondition : list must be sorted
utils.List.prototype.insertSorted = function(elt, comparator) {
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
if (this._begin === null) {
// Inserted in front (empty list)
this.push(elt);
} else if (comparator(this._begin.data, elt) > 0) {
// Inserted in front (smallest element)
var newElement = {prev: null, next: this._begin, data: elt};
this._begin.prev = newElement;
this._begin = newElement;
this._size ++;
} else if (comparator(this._end.data, elt) < 0) {
// Inserted in end
this.push(elt);
} else {
// Inserted in the middle
var chain = this._begin;
while (chain.next !== null) {
// If chain < elt < chain.next
if (comparator(chain.next.data, elt) > 0) {
var newElement = {data: elt, next: chain.next, prev: chain};
if (chain.next) {
chain.next.prev = newElement;
}
chain.next = newElement;
this._size ++;
return;
}
// Next step
chain = chain.next;
}
}
}
// Check if a list is sorted of not
utils.List.prototype.isSorted = function(comparator) {
var chain = this._begin;
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
while (chain.next !== null) {
if (comparator(chain.data, chain.next.data) > 0) {
return false;
}
chain = chain.next;
}
return true;
}
// Gives an iterator to the begin of the list
utils.List.prototype.begin = function() {
return new utils.List.Iterator(this._begin, 0);
}
// Gives an iterator to the end of the list
utils.List.prototype.end = function() {
return new utils.List.Iterator(this._end, this.size() - 1);
}
// Class iterator
utils.List.Iterator = function(chain, counter) {
this._chain = chain;
this._counter = counter;
}
// Go to the next element
utils.List.Iterator.prototype.next = function() {
this._chain = this._chain.next;
this._counter ++;
}
// Go to the previous element
utils.List.Iterator.prototype.prev = function() {
this._chain = this._chain.prev;
this._counter --;
}
// Return the current element
utils.List.Iterator.prototype.get = function() {
return this._chain.data;
}
// Check if there is another element next
utils.List.Iterator.prototype.hasNext = function() {
return this._chain.next !== null;
}
// Check if there is another element before
utils.List.Iterator.prototype.hasPrev = function() {
return this._chain.prev !== null;
}
// Compares to another iterator of the same list
utils.List.Iterator.prototype.lowerThan = function(it2) {
return utils.distance(this, it2) > 0;
}
// Compares to another iterator of the same list
utils.List.Iterator.prototype.greaterThan = function(it2) {
return utils.distance(this, it2) < 0;
}
// Returns the distance between two iterators of the same list
utils.distance = function(it1, it2) {
return it2._counter - it1._counter;
}
priv = {};
priv.defaultComparator = function(a,b) {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
// Support for NodeJs
if (typeof module !== 'undefined' && module.exports) {
module.exports = utils;
} else {
return utils;
}
})();