sync/src/ullist.js

184 lines
3.8 KiB
JavaScript

/*
ullist.js
Description: Defines ULList, which represents a doubly linked list
in which each item has a unique identifier stored in the `uid` field.
*/
function ULList() {
this.first = null;
this.last = null;
this.length = 0;
}
/* Add an item to the beginning of the list */
ULList.prototype.prepend = function(item) {
if(this.first !== null) {
item.next = this.first;
this.first.prev = item;
}
else {
this.last = item;
}
this.first = item;
this.first.prev = null;
this.length++;
return true;
}
/* Add an item to the end of the list */
ULList.prototype.append = function(item) {
if(this.last !== null) {
item.prev = this.last;
this.last.next = item;
}
else {
this.first = item;
}
this.last = item;
this.last.next = null;
this.length++;
return true;
}
/* Insert an item after one which has a specified UID */
ULList.prototype.insertAfter = function(item, uid) {
var after = this.find(uid);
if(!after)
return false;
// Update links
item.next = after.next;
if(item.next)
item.next.prev = item;
item.prev = after;
after.next = item;
// New end of list
if(after == this.last)
this.last = item;
this.length++;
return true;
}
/* Insert an item before one that has a specified UID */
ULList.prototype.insertBefore = function(item, uid) {
var before = this.find(uid);
if(!before)
return false;
// Update links
item.next = before;
item.prev = before.prev;
if(item.prev)
item.prev.next = item;
before.prev = item;
// New beginning of list
if(before == this.first)
this.first = item;
this.length++;
return true;
}
/* Remove an item from the list */
ULList.prototype.remove = function(uid) {
var item = this.find(uid);
if(!item)
return false;
// Boundary conditions
if(item == this.first)
this.first = item.next;
if(item == this.last)
this.last = item.prev;
// General case
if(item.prev)
item.prev.next = item.next;
if(item.next)
item.next.prev = item.prev;
this.length--;
return true;
}
/* Find an element in the list, return false if specified UID not found */
ULList.prototype.find = function(uid) {
// Can't possibly find it in an empty list
if(this.first === null)
return false;
var item = this.first;
var iter = this.first;
while(iter !== null && item.uid != uid) {
item = iter;
iter = iter.next;
}
if(item && item.uid == uid)
return item;
return false;
}
/* Clear all elements from the list */
ULList.prototype.clear = function() {
this.first = null;
this.last = null;
this.length = 0;
}
/* Dump the contents of the list into an array */
ULList.prototype.toArray = function(pack) {
var arr = new Array(this.length);
var item = this.first;
var i = 0;
while(item !== null) {
if(pack !== false && typeof item.pack == "function")
arr[i++] = item.pack();
else
arr[i++] = item;
item = item.next;
}
return arr;
}
/* iterate across the playlist */
ULList.prototype.forEach = function (fn) {
var item = this.first;
while(item !== null) {
fn(item);
item = item.next;
}
};
/* find a media with the given video id */
ULList.prototype.findVideoId = function (id) {
var item = this.first;
while(item !== null) {
if(item.media && item.media.id === id)
return item;
item = item.next;
}
return false;
};
ULList.prototype.findAll = function(fn) {
var result = [];
this.forEach(function(item) {
if( fn(item) ) {
result.push(item);
}
});
return result;
}
module.exports = ULList;