You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
5.1 KiB

/**
* @module ol/structs/LinkedList
*/
/**
* @typedef {Object} Item
* @property {Item} [prev] Previous.
* @property {Item} [next] Next.
* @property {?} data Data.
*/
/**
* @classdesc
* Creates an empty linked list structure.
*/
class LinkedList {
/**
* @param {boolean} [circular] The last item is connected to the first one,
* and the first item to the last one. Default is true.
*/
constructor(circular) {
/**
* @private
* @type {Item|undefined}
*/
this.first_;
/**
* @private
* @type {Item|undefined}
*/
this.last_;
/**
* @private
* @type {Item|undefined}
*/
this.head_;
/**
* @private
* @type {boolean}
*/
this.circular_ = circular === undefined ? true : circular;
/**
* @private
* @type {number}
*/
this.length_ = 0;
}
/**
* Inserts an item into the linked list right after the current one.
*
* @param {?} data Item data.
*/
insertItem(data) {
/** @type {Item} */
const item = {
prev: undefined,
next: undefined,
data: data,
};
const head = this.head_;
//Initialize the list.
if (!head) {
this.first_ = item;
this.last_ = item;
if (this.circular_) {
item.next = item;
item.prev = item;
}
} else {
//Link the new item to the adjacent ones.
const next = head.next;
item.prev = head;
item.next = next;
head.next = item;
if (next) {
next.prev = item;
}
if (head === this.last_) {
this.last_ = item;
}
}
this.head_ = item;
this.length_++;
}
/**
* Removes the current item from the list. Sets the cursor to the next item,
* if possible.
*/
removeItem() {
const head = this.head_;
if (head) {
const next = head.next;
const prev = head.prev;
if (next) {
next.prev = prev;
}
if (prev) {
prev.next = next;
}
this.head_ = next || prev;
if (this.first_ === this.last_) {
this.head_ = undefined;
this.first_ = undefined;
this.last_ = undefined;
} else if (this.first_ === head) {
this.first_ = this.head_;
} else if (this.last_ === head) {
this.last_ = prev ? this.head_.prev : this.head_;
}
this.length_--;
}
}
/**
* Sets the cursor to the first item, and returns the associated data.
*
* @return {?} Item data.
*/
firstItem() {
this.head_ = this.first_;
if (this.head_) {
return this.head_.data;
}
return undefined;
}
/**
* Sets the cursor to the last item, and returns the associated data.
*
* @return {?} Item data.
*/
lastItem() {
this.head_ = this.last_;
if (this.head_) {
return this.head_.data;
}
return undefined;
}
/**
* Sets the cursor to the next item, and returns the associated data.
*
* @return {?} Item data.
*/
nextItem() {
if (this.head_ && this.head_.next) {
this.head_ = this.head_.next;
return this.head_.data;
}
return undefined;
}
/**
* Returns the next item's data without moving the cursor.
*
* @return {?} Item data.
*/
getNextItem() {
if (this.head_ && this.head_.next) {
return this.head_.next.data;
}
return undefined;
}
/**
* Sets the cursor to the previous item, and returns the associated data.
*
* @return {?} Item data.
*/
prevItem() {
if (this.head_ && this.head_.prev) {
this.head_ = this.head_.prev;
return this.head_.data;
}
return undefined;
}
/**
* Returns the previous item's data without moving the cursor.
*
* @return {?} Item data.
*/
getPrevItem() {
if (this.head_ && this.head_.prev) {
return this.head_.prev.data;
}
return undefined;
}
/**
* Returns the current item's data.
*
* @return {?} Item data.
*/
getCurrItem() {
if (this.head_) {
return this.head_.data;
}
return undefined;
}
/**
* Sets the first item of the list. This only works for circular lists, and sets
* the last item accordingly.
*/
setFirstItem() {
if (this.circular_ && this.head_) {
this.first_ = this.head_;
this.last_ = this.head_.prev;
}
}
/**
* Concatenates two lists.
* @param {LinkedList} list List to merge into the current list.
*/
concat(list) {
if (list.head_) {
if (this.head_) {
const end = this.head_.next;
this.head_.next = list.first_;
list.first_.prev = this.head_;
end.prev = list.last_;
list.last_.next = end;
this.length_ += list.length_;
} else {
this.head_ = list.head_;
this.first_ = list.first_;
this.last_ = list.last_;
this.length_ = list.length_;
}
list.head_ = undefined;
list.first_ = undefined;
list.last_ = undefined;
list.length_ = 0;
}
}
/**
* Returns the current length of the list.
*
* @return {number} Length.
*/
getLength() {
return this.length_;
}
}
export default LinkedList;