Manual class transform
This commit is contained in:
@@ -27,272 +27,277 @@ import EventType from '../events/EventType.js';
|
||||
* @template T
|
||||
* @param {number=} opt_highWaterMark High water mark.
|
||||
*/
|
||||
const LRUCache = function(opt_highWaterMark) {
|
||||
class LRUCache {
|
||||
|
||||
constructor(opt_highWaterMark) {
|
||||
|
||||
EventTarget.call(this);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.highWaterMark = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.count_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, module:ol/structs/LRUCache~Entry>}
|
||||
*/
|
||||
this.entries_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/structs/LRUCache~Entry}
|
||||
*/
|
||||
this.oldest_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/structs/LRUCache~Entry}
|
||||
*/
|
||||
this.newest_ = null;
|
||||
|
||||
}
|
||||
|
||||
EventTarget.call(this);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @return {boolean} Can expire cache.
|
||||
*/
|
||||
this.highWaterMark = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;
|
||||
canExpireCache() {
|
||||
return this.getCount() > this.highWaterMark;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
this.count_ = 0;
|
||||
clear() {
|
||||
this.count_ = 0;
|
||||
this.entries_ = {};
|
||||
this.oldest_ = null;
|
||||
this.newest_ = null;
|
||||
this.dispatchEvent(EventType.CLEAR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, module:ol/structs/LRUCache~Entry>}
|
||||
* @param {string} key Key.
|
||||
* @return {boolean} Contains key.
|
||||
*/
|
||||
this.entries_ = {};
|
||||
containsKey(key) {
|
||||
return this.entries_.hasOwnProperty(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/structs/LRUCache~Entry}
|
||||
* @param {function(this: S, T, string, module:ol/structs/LRUCache): ?} f The function
|
||||
* to call for every entry from the oldest to the newer. This function takes
|
||||
* 3 arguments (the entry value, the entry key and the LRUCache object).
|
||||
* The return value is ignored.
|
||||
* @param {S=} opt_this The object to use as `this` in `f`.
|
||||
* @template S
|
||||
*/
|
||||
this.oldest_ = null;
|
||||
forEach(f, opt_this) {
|
||||
let entry = this.oldest_;
|
||||
while (entry) {
|
||||
f.call(opt_this, entry.value_, entry.key_, this);
|
||||
entry = entry.newer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/structs/LRUCache~Entry}
|
||||
* @param {string} key Key.
|
||||
* @return {T} Value.
|
||||
*/
|
||||
this.newest_ = null;
|
||||
get(key) {
|
||||
const entry = this.entries_[key];
|
||||
assert(entry !== undefined,
|
||||
15); // Tried to get a value for a key that does not exist in the cache
|
||||
if (entry === this.newest_) {
|
||||
return entry.value_;
|
||||
} else if (entry === this.oldest_) {
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (this.oldest_.newer);
|
||||
this.oldest_.older = null;
|
||||
} else {
|
||||
entry.newer.older = entry.older;
|
||||
entry.older.newer = entry.newer;
|
||||
}
|
||||
entry.newer = null;
|
||||
entry.older = this.newest_;
|
||||
this.newest_.newer = entry;
|
||||
this.newest_ = entry;
|
||||
return entry.value_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an entry from the cache.
|
||||
* @param {string} key The entry key.
|
||||
* @return {T} The removed entry.
|
||||
*/
|
||||
remove(key) {
|
||||
const entry = this.entries_[key];
|
||||
assert(entry !== undefined, 15); // Tried to get a value for a key that does not exist in the cache
|
||||
if (entry === this.newest_) {
|
||||
this.newest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.older);
|
||||
if (this.newest_) {
|
||||
this.newest_.newer = null;
|
||||
}
|
||||
} else if (entry === this.oldest_) {
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);
|
||||
if (this.oldest_) {
|
||||
this.oldest_.older = null;
|
||||
}
|
||||
} else {
|
||||
entry.newer.older = entry.older;
|
||||
entry.older.newer = entry.newer;
|
||||
}
|
||||
delete this.entries_[key];
|
||||
--this.count_;
|
||||
return entry.value_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
getCount() {
|
||||
return this.count_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<string>} Keys.
|
||||
*/
|
||||
getKeys() {
|
||||
const keys = new Array(this.count_);
|
||||
let i = 0;
|
||||
let entry;
|
||||
for (entry = this.newest_; entry; entry = entry.older) {
|
||||
keys[i++] = entry.key_;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<T>} Values.
|
||||
*/
|
||||
getValues() {
|
||||
const values = new Array(this.count_);
|
||||
let i = 0;
|
||||
let entry;
|
||||
for (entry = this.newest_; entry; entry = entry.older) {
|
||||
values[i++] = entry.value_;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {T} Last value.
|
||||
*/
|
||||
peekLast() {
|
||||
return this.oldest_.value_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Last key.
|
||||
*/
|
||||
peekLastKey() {
|
||||
return this.oldest_.key_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the key of the newest item in the cache. Throws if the cache is empty.
|
||||
* @return {string} The newest key.
|
||||
*/
|
||||
peekFirstKey() {
|
||||
return this.newest_.key_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {T} value Value.
|
||||
*/
|
||||
pop() {
|
||||
const entry = this.oldest_;
|
||||
delete this.entries_[entry.key_];
|
||||
if (entry.newer) {
|
||||
entry.newer.older = null;
|
||||
}
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);
|
||||
if (!this.oldest_) {
|
||||
this.newest_ = null;
|
||||
}
|
||||
--this.count_;
|
||||
return entry.value_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
replace(key, value) {
|
||||
this.get(key); // update `newest_`
|
||||
this.entries_[key].value_ = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
set(key, value) {
|
||||
assert(!(key in this.entries_),
|
||||
16); // Tried to set a value for a key that is used already
|
||||
const entry = /** @type {module:ol/structs/LRUCache~Entry} */ ({
|
||||
key_: key,
|
||||
newer: null,
|
||||
older: this.newest_,
|
||||
value_: value
|
||||
});
|
||||
if (!this.newest_) {
|
||||
this.oldest_ = entry;
|
||||
} else {
|
||||
this.newest_.newer = entry;
|
||||
}
|
||||
this.newest_ = entry;
|
||||
this.entries_[key] = entry;
|
||||
++this.count_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a maximum number of entries for the cache.
|
||||
* @param {number} size Cache size.
|
||||
* @api
|
||||
*/
|
||||
setSize(size) {
|
||||
this.highWaterMark = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prune the cache.
|
||||
*/
|
||||
prune() {
|
||||
while (this.canExpireCache()) {
|
||||
this.pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(LRUCache, EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Can expire cache.
|
||||
*/
|
||||
LRUCache.prototype.canExpireCache = function() {
|
||||
return this.getCount() > this.highWaterMark;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
LRUCache.prototype.clear = function() {
|
||||
this.count_ = 0;
|
||||
this.entries_ = {};
|
||||
this.oldest_ = null;
|
||||
this.newest_ = null;
|
||||
this.dispatchEvent(EventType.CLEAR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @return {boolean} Contains key.
|
||||
*/
|
||||
LRUCache.prototype.containsKey = function(key) {
|
||||
return this.entries_.hasOwnProperty(key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {function(this: S, T, string, module:ol/structs/LRUCache): ?} f The function
|
||||
* to call for every entry from the oldest to the newer. This function takes
|
||||
* 3 arguments (the entry value, the entry key and the LRUCache object).
|
||||
* The return value is ignored.
|
||||
* @param {S=} opt_this The object to use as `this` in `f`.
|
||||
* @template S
|
||||
*/
|
||||
LRUCache.prototype.forEach = function(f, opt_this) {
|
||||
let entry = this.oldest_;
|
||||
while (entry) {
|
||||
f.call(opt_this, entry.value_, entry.key_, this);
|
||||
entry = entry.newer;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @return {T} Value.
|
||||
*/
|
||||
LRUCache.prototype.get = function(key) {
|
||||
const entry = this.entries_[key];
|
||||
assert(entry !== undefined,
|
||||
15); // Tried to get a value for a key that does not exist in the cache
|
||||
if (entry === this.newest_) {
|
||||
return entry.value_;
|
||||
} else if (entry === this.oldest_) {
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (this.oldest_.newer);
|
||||
this.oldest_.older = null;
|
||||
} else {
|
||||
entry.newer.older = entry.older;
|
||||
entry.older.newer = entry.newer;
|
||||
}
|
||||
entry.newer = null;
|
||||
entry.older = this.newest_;
|
||||
this.newest_.newer = entry;
|
||||
this.newest_ = entry;
|
||||
return entry.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove an entry from the cache.
|
||||
* @param {string} key The entry key.
|
||||
* @return {T} The removed entry.
|
||||
*/
|
||||
LRUCache.prototype.remove = function(key) {
|
||||
const entry = this.entries_[key];
|
||||
assert(entry !== undefined, 15); // Tried to get a value for a key that does not exist in the cache
|
||||
if (entry === this.newest_) {
|
||||
this.newest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.older);
|
||||
if (this.newest_) {
|
||||
this.newest_.newer = null;
|
||||
}
|
||||
} else if (entry === this.oldest_) {
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);
|
||||
if (this.oldest_) {
|
||||
this.oldest_.older = null;
|
||||
}
|
||||
} else {
|
||||
entry.newer.older = entry.older;
|
||||
entry.older.newer = entry.newer;
|
||||
}
|
||||
delete this.entries_[key];
|
||||
--this.count_;
|
||||
return entry.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
LRUCache.prototype.getCount = function() {
|
||||
return this.count_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<string>} Keys.
|
||||
*/
|
||||
LRUCache.prototype.getKeys = function() {
|
||||
const keys = new Array(this.count_);
|
||||
let i = 0;
|
||||
let entry;
|
||||
for (entry = this.newest_; entry; entry = entry.older) {
|
||||
keys[i++] = entry.key_;
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<T>} Values.
|
||||
*/
|
||||
LRUCache.prototype.getValues = function() {
|
||||
const values = new Array(this.count_);
|
||||
let i = 0;
|
||||
let entry;
|
||||
for (entry = this.newest_; entry; entry = entry.older) {
|
||||
values[i++] = entry.value_;
|
||||
}
|
||||
return values;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {T} Last value.
|
||||
*/
|
||||
LRUCache.prototype.peekLast = function() {
|
||||
return this.oldest_.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Last key.
|
||||
*/
|
||||
LRUCache.prototype.peekLastKey = function() {
|
||||
return this.oldest_.key_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the key of the newest item in the cache. Throws if the cache is empty.
|
||||
* @return {string} The newest key.
|
||||
*/
|
||||
LRUCache.prototype.peekFirstKey = function() {
|
||||
return this.newest_.key_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {T} value Value.
|
||||
*/
|
||||
LRUCache.prototype.pop = function() {
|
||||
const entry = this.oldest_;
|
||||
delete this.entries_[entry.key_];
|
||||
if (entry.newer) {
|
||||
entry.newer.older = null;
|
||||
}
|
||||
this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);
|
||||
if (!this.oldest_) {
|
||||
this.newest_ = null;
|
||||
}
|
||||
--this.count_;
|
||||
return entry.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
LRUCache.prototype.replace = function(key, value) {
|
||||
this.get(key); // update `newest_`
|
||||
this.entries_[key].value_ = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
LRUCache.prototype.set = function(key, value) {
|
||||
assert(!(key in this.entries_),
|
||||
16); // Tried to set a value for a key that is used already
|
||||
const entry = /** @type {module:ol/structs/LRUCache~Entry} */ ({
|
||||
key_: key,
|
||||
newer: null,
|
||||
older: this.newest_,
|
||||
value_: value
|
||||
});
|
||||
if (!this.newest_) {
|
||||
this.oldest_ = entry;
|
||||
} else {
|
||||
this.newest_.newer = entry;
|
||||
}
|
||||
this.newest_ = entry;
|
||||
this.entries_[key] = entry;
|
||||
++this.count_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set a maximum number of entries for the cache.
|
||||
* @param {number} size Cache size.
|
||||
* @api
|
||||
*/
|
||||
LRUCache.prototype.setSize = function(size) {
|
||||
this.highWaterMark = size;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prune the cache.
|
||||
*/
|
||||
LRUCache.prototype.prune = function() {
|
||||
while (this.canExpireCache()) {
|
||||
this.pop();
|
||||
}
|
||||
};
|
||||
export default LRUCache;
|
||||
|
||||
@@ -19,242 +19,249 @@
|
||||
* @param {boolean=} opt_circular The last item is connected to the first one,
|
||||
* and the first item to the last one. Default is true.
|
||||
*/
|
||||
const LinkedList = function(opt_circular) {
|
||||
class LinkedList {
|
||||
|
||||
constructor(opt_circular) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
*/
|
||||
this.first_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
*/
|
||||
this.last_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
*/
|
||||
this.head_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.circular_ = opt_circular === undefined ? true : opt_circular;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.length_ = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
* Inserts an item into the linked list right after the current one.
|
||||
*
|
||||
* @param {?} data Item data.
|
||||
*/
|
||||
this.first_;
|
||||
insertItem(data) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
*/
|
||||
this.last_;
|
||||
/** @type {module:ol/structs/LinkedList~Item} */
|
||||
const item = {
|
||||
prev: undefined,
|
||||
next: undefined,
|
||||
data: data
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/structs/LinkedList~Item|undefined}
|
||||
*/
|
||||
this.head_;
|
||||
const head = this.head_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.circular_ = opt_circular === undefined ? true : opt_circular;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.length_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts an item into the linked list right after the current one.
|
||||
*
|
||||
* @param {?} data Item data.
|
||||
*/
|
||||
LinkedList.prototype.insertItem = function(data) {
|
||||
|
||||
/** @type {module:ol/structs/LinkedList~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_) {
|
||||
//Initialize the list.
|
||||
if (!head) {
|
||||
this.first_ = item;
|
||||
this.last_ = item;
|
||||
}
|
||||
}
|
||||
this.head_ = item;
|
||||
this.length_++;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the current item from the list. Sets the cursor to the next item,
|
||||
* if possible.
|
||||
*/
|
||||
LinkedList.prototype.removeItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.firstItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.lastItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.nextItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.getNextItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.prevItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.getPrevItem = function() {
|
||||
if (this.head_ && this.head_.prev) {
|
||||
return this.head_.prev.data;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current item's data.
|
||||
*
|
||||
* @return {?} Item data.
|
||||
*/
|
||||
LinkedList.prototype.getCurrItem = function() {
|
||||
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.
|
||||
*/
|
||||
LinkedList.prototype.setFirstItem = function() {
|
||||
if (this.circular_ && this.head_) {
|
||||
this.first_ = this.head_;
|
||||
this.last_ = this.head_.prev;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Concatenates two lists.
|
||||
* @param {module:ol/structs/LinkedList} list List to merge into the current list.
|
||||
*/
|
||||
LinkedList.prototype.concat = function(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_;
|
||||
if (this.circular_) {
|
||||
item.next = item;
|
||||
item.prev = item;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
};
|
||||
//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 {module:ol/structs/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_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current length of the list.
|
||||
*
|
||||
* @return {number} Length.
|
||||
*/
|
||||
LinkedList.prototype.getLength = function() {
|
||||
return this.length_;
|
||||
};
|
||||
export default LinkedList;
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
import {assert} from '../asserts.js';
|
||||
import {clear} from '../obj.js';
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
export const DROP = Infinity;
|
||||
|
||||
|
||||
/**
|
||||
* Priority queue.
|
||||
*
|
||||
@@ -19,257 +26,256 @@ import {clear} from '../obj.js';
|
||||
* @struct
|
||||
* @template T
|
||||
*/
|
||||
const PriorityQueue = function(priorityFunction, keyFunction) {
|
||||
class PriorityQueue {
|
||||
|
||||
/**
|
||||
* @type {function(T): number}
|
||||
* @private
|
||||
*/
|
||||
this.priorityFunction_ = priorityFunction;
|
||||
constructor(priorityFunction, keyFunction) {
|
||||
|
||||
/**
|
||||
* @type {function(T): string}
|
||||
* @private
|
||||
*/
|
||||
this.keyFunction_ = keyFunction;
|
||||
/**
|
||||
* @type {function(T): number}
|
||||
* @private
|
||||
*/
|
||||
this.priorityFunction_ = priorityFunction;
|
||||
|
||||
/**
|
||||
* @type {Array.<T>}
|
||||
* @private
|
||||
*/
|
||||
this.elements_ = [];
|
||||
/**
|
||||
* @type {function(T): string}
|
||||
* @private
|
||||
*/
|
||||
this.keyFunction_ = keyFunction;
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.priorities_ = [];
|
||||
/**
|
||||
* @type {Array.<T>}
|
||||
* @private
|
||||
*/
|
||||
this.elements_ = [];
|
||||
|
||||
/**
|
||||
* @type {!Object.<string, boolean>}
|
||||
* @private
|
||||
*/
|
||||
this.queuedElements_ = {};
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.priorities_ = [];
|
||||
|
||||
};
|
||||
/**
|
||||
* @type {!Object.<string, boolean>}
|
||||
* @private
|
||||
*/
|
||||
this.queuedElements_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
export const DROP = Infinity;
|
||||
|
||||
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
PriorityQueue.prototype.clear = function() {
|
||||
this.elements_.length = 0;
|
||||
this.priorities_.length = 0;
|
||||
clear(this.queuedElements_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove and return the highest-priority element. O(log N).
|
||||
* @return {T} Element.
|
||||
*/
|
||||
PriorityQueue.prototype.dequeue = function() {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const element = elements[0];
|
||||
if (elements.length == 1) {
|
||||
elements.length = 0;
|
||||
priorities.length = 0;
|
||||
} else {
|
||||
elements[0] = elements.pop();
|
||||
priorities[0] = priorities.pop();
|
||||
this.siftUp_(0);
|
||||
}
|
||||
const elementKey = this.keyFunction_(element);
|
||||
delete this.queuedElements_[elementKey];
|
||||
return element;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enqueue an element. O(log N).
|
||||
* @param {T} element Element.
|
||||
* @return {boolean} The element was added to the queue.
|
||||
*/
|
||||
PriorityQueue.prototype.enqueue = function(element) {
|
||||
assert(!(this.keyFunction_(element) in this.queuedElements_),
|
||||
31); // Tried to enqueue an `element` that was already added to the queue
|
||||
const priority = this.priorityFunction_(element);
|
||||
if (priority != DROP) {
|
||||
this.elements_.push(element);
|
||||
this.priorities_.push(priority);
|
||||
this.queuedElements_[this.keyFunction_(element)] = true;
|
||||
this.siftDown_(0, this.elements_.length - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
PriorityQueue.prototype.getCount = function() {
|
||||
return this.elements_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the left child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the left child for.
|
||||
* @return {number} The index of the left child.
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.getLeftChildIndex_ = function(index) {
|
||||
return index * 2 + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the right child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the right child for.
|
||||
* @return {number} The index of the right child.
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.getRightChildIndex_ = function(index) {
|
||||
return index * 2 + 2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the parent of the node at the given index.
|
||||
* @param {number} index The index of the node to get the parent for.
|
||||
* @return {number} The index of the parent.
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.getParentIndex_ = function(index) {
|
||||
return (index - 1) >> 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make this a heap. O(N).
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.heapify_ = function() {
|
||||
let i;
|
||||
for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {
|
||||
this.siftUp_(i);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
PriorityQueue.prototype.isEmpty = function() {
|
||||
return this.elements_.length === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @return {boolean} Is key queued.
|
||||
*/
|
||||
PriorityQueue.prototype.isKeyQueued = function(key) {
|
||||
return key in this.queuedElements_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {T} element Element.
|
||||
* @return {boolean} Is queued.
|
||||
*/
|
||||
PriorityQueue.prototype.isQueued = function(element) {
|
||||
return this.isKeyQueued(this.keyFunction_(element));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} index The index of the node to move down.
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.siftUp_ = function(index) {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const count = elements.length;
|
||||
const element = elements[index];
|
||||
const priority = priorities[index];
|
||||
const startIndex = index;
|
||||
|
||||
while (index < (count >> 1)) {
|
||||
const lIndex = this.getLeftChildIndex_(index);
|
||||
const rIndex = this.getRightChildIndex_(index);
|
||||
|
||||
const smallerChildIndex = rIndex < count &&
|
||||
priorities[rIndex] < priorities[lIndex] ?
|
||||
rIndex : lIndex;
|
||||
|
||||
elements[index] = elements[smallerChildIndex];
|
||||
priorities[index] = priorities[smallerChildIndex];
|
||||
index = smallerChildIndex;
|
||||
}
|
||||
|
||||
elements[index] = element;
|
||||
priorities[index] = priority;
|
||||
this.siftDown_(startIndex, index);
|
||||
};
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
clear() {
|
||||
this.elements_.length = 0;
|
||||
this.priorities_.length = 0;
|
||||
clear(this.queuedElements_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} startIndex The index of the root.
|
||||
* @param {number} index The index of the node to move up.
|
||||
* @private
|
||||
*/
|
||||
PriorityQueue.prototype.siftDown_ = function(startIndex, index) {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const element = elements[index];
|
||||
const priority = priorities[index];
|
||||
|
||||
while (index > startIndex) {
|
||||
const parentIndex = this.getParentIndex_(index);
|
||||
if (priorities[parentIndex] > priority) {
|
||||
elements[index] = elements[parentIndex];
|
||||
priorities[index] = priorities[parentIndex];
|
||||
index = parentIndex;
|
||||
/**
|
||||
* Remove and return the highest-priority element. O(log N).
|
||||
* @return {T} Element.
|
||||
*/
|
||||
dequeue() {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const element = elements[0];
|
||||
if (elements.length == 1) {
|
||||
elements.length = 0;
|
||||
priorities.length = 0;
|
||||
} else {
|
||||
break;
|
||||
elements[0] = elements.pop();
|
||||
priorities[0] = priorities.pop();
|
||||
this.siftUp_(0);
|
||||
}
|
||||
const elementKey = this.keyFunction_(element);
|
||||
delete this.queuedElements_[elementKey];
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enqueue an element. O(log N).
|
||||
* @param {T} element Element.
|
||||
* @return {boolean} The element was added to the queue.
|
||||
*/
|
||||
enqueue(element) {
|
||||
assert(!(this.keyFunction_(element) in this.queuedElements_),
|
||||
31); // Tried to enqueue an `element` that was already added to the queue
|
||||
const priority = this.priorityFunction_(element);
|
||||
if (priority != DROP) {
|
||||
this.elements_.push(element);
|
||||
this.priorities_.push(priority);
|
||||
this.queuedElements_[this.keyFunction_(element)] = true;
|
||||
this.siftDown_(0, this.elements_.length - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
getCount() {
|
||||
return this.elements_.length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the left child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the left child for.
|
||||
* @return {number} The index of the left child.
|
||||
* @private
|
||||
*/
|
||||
getLeftChildIndex_(index) {
|
||||
return index * 2 + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the right child of the node at the given index.
|
||||
* @param {number} index The index of the node to get the right child for.
|
||||
* @return {number} The index of the right child.
|
||||
* @private
|
||||
*/
|
||||
getRightChildIndex_(index) {
|
||||
return index * 2 + 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the parent of the node at the given index.
|
||||
* @param {number} index The index of the node to get the parent for.
|
||||
* @return {number} The index of the parent.
|
||||
* @private
|
||||
*/
|
||||
getParentIndex_(index) {
|
||||
return (index - 1) >> 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make this a heap. O(N).
|
||||
* @private
|
||||
*/
|
||||
heapify_() {
|
||||
let i;
|
||||
for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {
|
||||
this.siftUp_(i);
|
||||
}
|
||||
}
|
||||
elements[index] = element;
|
||||
priorities[index] = priority;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
PriorityQueue.prototype.reprioritize = function() {
|
||||
const priorityFunction = this.priorityFunction_;
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
let index = 0;
|
||||
const n = elements.length;
|
||||
let element, i, priority;
|
||||
for (i = 0; i < n; ++i) {
|
||||
element = elements[i];
|
||||
priority = priorityFunction(element);
|
||||
if (priority == DROP) {
|
||||
delete this.queuedElements_[this.keyFunction_(element)];
|
||||
} else {
|
||||
priorities[index] = priority;
|
||||
elements[index++] = element;
|
||||
}
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.elements_.length === 0;
|
||||
}
|
||||
elements.length = index;
|
||||
priorities.length = index;
|
||||
this.heapify_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key.
|
||||
* @return {boolean} Is key queued.
|
||||
*/
|
||||
isKeyQueued(key) {
|
||||
return key in this.queuedElements_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {T} element Element.
|
||||
* @return {boolean} Is queued.
|
||||
*/
|
||||
isQueued(element) {
|
||||
return this.isKeyQueued(this.keyFunction_(element));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} index The index of the node to move down.
|
||||
* @private
|
||||
*/
|
||||
siftUp_(index) {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const count = elements.length;
|
||||
const element = elements[index];
|
||||
const priority = priorities[index];
|
||||
const startIndex = index;
|
||||
|
||||
while (index < (count >> 1)) {
|
||||
const lIndex = this.getLeftChildIndex_(index);
|
||||
const rIndex = this.getRightChildIndex_(index);
|
||||
|
||||
const smallerChildIndex = rIndex < count &&
|
||||
priorities[rIndex] < priorities[lIndex] ?
|
||||
rIndex : lIndex;
|
||||
|
||||
elements[index] = elements[smallerChildIndex];
|
||||
priorities[index] = priorities[smallerChildIndex];
|
||||
index = smallerChildIndex;
|
||||
}
|
||||
|
||||
elements[index] = element;
|
||||
priorities[index] = priority;
|
||||
this.siftDown_(startIndex, index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} startIndex The index of the root.
|
||||
* @param {number} index The index of the node to move up.
|
||||
* @private
|
||||
*/
|
||||
siftDown_(startIndex, index) {
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
const element = elements[index];
|
||||
const priority = priorities[index];
|
||||
|
||||
while (index > startIndex) {
|
||||
const parentIndex = this.getParentIndex_(index);
|
||||
if (priorities[parentIndex] > priority) {
|
||||
elements[index] = elements[parentIndex];
|
||||
priorities[index] = priorities[parentIndex];
|
||||
index = parentIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
elements[index] = element;
|
||||
priorities[index] = priority;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
reprioritize() {
|
||||
const priorityFunction = this.priorityFunction_;
|
||||
const elements = this.elements_;
|
||||
const priorities = this.priorities_;
|
||||
let index = 0;
|
||||
const n = elements.length;
|
||||
let element, i, priority;
|
||||
for (i = 0; i < n; ++i) {
|
||||
element = elements[i];
|
||||
priority = priorityFunction(element);
|
||||
if (priority == DROP) {
|
||||
delete this.queuedElements_[this.keyFunction_(element)];
|
||||
} else {
|
||||
priorities[index] = priority;
|
||||
elements[index++] = element;
|
||||
}
|
||||
}
|
||||
elements.length = index;
|
||||
priorities.length = index;
|
||||
this.heapify_();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default PriorityQueue;
|
||||
|
||||
@@ -24,55 +24,31 @@ import {isEmpty} from '../obj.js';
|
||||
* @struct
|
||||
* @template T
|
||||
*/
|
||||
const RBush = function(opt_maxEntries) {
|
||||
class RBush {
|
||||
|
||||
constructor(opt_maxEntries) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.rbush_ = rbush(opt_maxEntries, undefined);
|
||||
|
||||
/**
|
||||
* A mapping between the objects added to this rbush wrapper
|
||||
* and the objects that are actually added to the internal rbush.
|
||||
* @private
|
||||
* @type {Object.<number, module:ol/structs/RBush~Entry>}
|
||||
*/
|
||||
this.items_ = {};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Insert a value into the RBush.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
this.rbush_ = rbush(opt_maxEntries, undefined);
|
||||
|
||||
/**
|
||||
* A mapping between the objects added to this rbush wrapper
|
||||
* and the objects that are actually added to the internal rbush.
|
||||
* @private
|
||||
* @type {Object.<number, module:ol/structs/RBush~Entry>}
|
||||
*/
|
||||
this.items_ = {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert a value into the RBush.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
RBush.prototype.insert = function(extent, value) {
|
||||
/** @type {module:ol/structs/RBush~Entry} */
|
||||
const item = {
|
||||
minX: extent[0],
|
||||
minY: extent[1],
|
||||
maxX: extent[2],
|
||||
maxY: extent[3],
|
||||
value: value
|
||||
};
|
||||
|
||||
this.rbush_.insert(item);
|
||||
this.items_[getUid(value)] = item;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Bulk-insert values into the RBush.
|
||||
* @param {Array.<module:ol/extent~Extent>} extents Extents.
|
||||
* @param {Array.<T>} values Values.
|
||||
*/
|
||||
RBush.prototype.load = function(extents, values) {
|
||||
const items = new Array(values.length);
|
||||
for (let i = 0, l = values.length; i < l; i++) {
|
||||
const extent = extents[i];
|
||||
const value = values[i];
|
||||
|
||||
insert(extent, value) {
|
||||
/** @type {module:ol/structs/RBush~Entry} */
|
||||
const item = {
|
||||
minX: extent[0],
|
||||
@@ -81,158 +57,187 @@ RBush.prototype.load = function(extents, values) {
|
||||
maxY: extent[3],
|
||||
value: value
|
||||
};
|
||||
items[i] = item;
|
||||
|
||||
this.rbush_.insert(item);
|
||||
this.items_[getUid(value)] = item;
|
||||
}
|
||||
this.rbush_.load(items);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove a value from the RBush.
|
||||
* @param {T} value Value.
|
||||
* @return {boolean} Removed.
|
||||
*/
|
||||
RBush.prototype.remove = function(value) {
|
||||
const uid = getUid(value);
|
||||
/**
|
||||
* Bulk-insert values into the RBush.
|
||||
* @param {Array.<module:ol/extent~Extent>} extents Extents.
|
||||
* @param {Array.<T>} values Values.
|
||||
*/
|
||||
load(extents, values) {
|
||||
const items = new Array(values.length);
|
||||
for (let i = 0, l = values.length; i < l; i++) {
|
||||
const extent = extents[i];
|
||||
const value = values[i];
|
||||
|
||||
// get the object in which the value was wrapped when adding to the
|
||||
// internal rbush. then use that object to do the removal.
|
||||
const item = this.items_[uid];
|
||||
delete this.items_[uid];
|
||||
return this.rbush_.remove(item) !== null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update the extent of a value in the RBush.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
RBush.prototype.update = function(extent, value) {
|
||||
const item = this.items_[getUid(value)];
|
||||
const bbox = [item.minX, item.minY, item.maxX, item.maxY];
|
||||
if (!equals(bbox, extent)) {
|
||||
this.remove(value);
|
||||
this.insert(extent, value);
|
||||
/** @type {module:ol/structs/RBush~Entry} */
|
||||
const item = {
|
||||
minX: extent[0],
|
||||
minY: extent[1],
|
||||
maxX: extent[2],
|
||||
maxY: extent[3],
|
||||
value: value
|
||||
};
|
||||
items[i] = item;
|
||||
this.items_[getUid(value)] = item;
|
||||
}
|
||||
this.rbush_.load(items);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return all values in the RBush.
|
||||
* @return {Array.<T>} All.
|
||||
*/
|
||||
RBush.prototype.getAll = function() {
|
||||
const items = this.rbush_.all();
|
||||
return items.map(function(item) {
|
||||
return item.value;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Remove a value from the RBush.
|
||||
* @param {T} value Value.
|
||||
* @return {boolean} Removed.
|
||||
*/
|
||||
remove(value) {
|
||||
const uid = getUid(value);
|
||||
|
||||
// get the object in which the value was wrapped when adding to the
|
||||
// internal rbush. then use that object to do the removal.
|
||||
const item = this.items_[uid];
|
||||
delete this.items_[uid];
|
||||
return this.rbush_.remove(item) !== null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return all values in the given extent.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @return {Array.<T>} All in extent.
|
||||
*/
|
||||
RBush.prototype.getInExtent = function(extent) {
|
||||
/** @type {module:ol/structs/RBush~Entry} */
|
||||
const bbox = {
|
||||
minX: extent[0],
|
||||
minY: extent[1],
|
||||
maxX: extent[2],
|
||||
maxY: extent[3]
|
||||
};
|
||||
const items = this.rbush_.search(bbox);
|
||||
return items.map(function(item) {
|
||||
return item.value;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a callback function with each value in the tree.
|
||||
* If the callback returns a truthy value, this value is returned without
|
||||
* checking the rest of the tree.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
RBush.prototype.forEach = function(callback, opt_this) {
|
||||
return this.forEach_(this.getAll(), callback, opt_this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a callback function with each value in the provided extent.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
RBush.prototype.forEachInExtent = function(extent, callback, opt_this) {
|
||||
return this.forEach_(this.getInExtent(extent), callback, opt_this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<T>} values Values.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @private
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
RBush.prototype.forEach_ = function(values, callback, opt_this) {
|
||||
let result;
|
||||
for (let i = 0, l = values.length; i < l; i++) {
|
||||
result = callback.call(opt_this, values[i]);
|
||||
if (result) {
|
||||
return result;
|
||||
/**
|
||||
* Update the extent of a value in the RBush.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {T} value Value.
|
||||
*/
|
||||
update(extent, value) {
|
||||
const item = this.items_[getUid(value)];
|
||||
const bbox = [item.minX, item.minY, item.maxX, item.maxY];
|
||||
if (!equals(bbox, extent)) {
|
||||
this.remove(value);
|
||||
this.insert(extent, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
RBush.prototype.isEmpty = function() {
|
||||
return isEmpty(this.items_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all values from the RBush.
|
||||
*/
|
||||
RBush.prototype.clear = function() {
|
||||
this.rbush_.clear();
|
||||
this.items_ = {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/extent~Extent=} opt_extent Extent.
|
||||
* @return {module:ol/extent~Extent} Extent.
|
||||
*/
|
||||
RBush.prototype.getExtent = function(opt_extent) {
|
||||
// FIXME add getExtent() to rbush
|
||||
const data = this.rbush_.data;
|
||||
return createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, opt_extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/structs/RBush} rbush R-Tree.
|
||||
*/
|
||||
RBush.prototype.concat = function(rbush) {
|
||||
this.rbush_.load(rbush.rbush_.all());
|
||||
for (const i in rbush.items_) {
|
||||
this.items_[i | 0] = rbush.items_[i | 0];
|
||||
/**
|
||||
* Return all values in the RBush.
|
||||
* @return {Array.<T>} All.
|
||||
*/
|
||||
getAll() {
|
||||
const items = this.rbush_.all();
|
||||
return items.map(function(item) {
|
||||
return item.value;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return all values in the given extent.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @return {Array.<T>} All in extent.
|
||||
*/
|
||||
getInExtent(extent) {
|
||||
/** @type {module:ol/structs/RBush~Entry} */
|
||||
const bbox = {
|
||||
minX: extent[0],
|
||||
minY: extent[1],
|
||||
maxX: extent[2],
|
||||
maxY: extent[3]
|
||||
};
|
||||
const items = this.rbush_.search(bbox);
|
||||
return items.map(function(item) {
|
||||
return item.value;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls a callback function with each value in the tree.
|
||||
* If the callback returns a truthy value, this value is returned without
|
||||
* checking the rest of the tree.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
forEach(callback, opt_this) {
|
||||
return this.forEach_(this.getAll(), callback, opt_this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls a callback function with each value in the provided extent.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
forEachInExtent(extent, callback, opt_this) {
|
||||
return this.forEach_(this.getInExtent(extent), callback, opt_this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<T>} values Values.
|
||||
* @param {function(this: S, T): *} callback Callback.
|
||||
* @param {S=} opt_this The object to use as `this` in `callback`.
|
||||
* @private
|
||||
* @return {*} Callback return value.
|
||||
* @template S
|
||||
*/
|
||||
forEach_(values, callback, opt_this) {
|
||||
let result;
|
||||
for (let i = 0, l = values.length; i < l; i++) {
|
||||
result = callback.call(opt_this, values[i]);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
isEmpty() {
|
||||
return isEmpty(this.items_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all values from the RBush.
|
||||
*/
|
||||
clear() {
|
||||
this.rbush_.clear();
|
||||
this.items_ = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/extent~Extent=} opt_extent Extent.
|
||||
* @return {module:ol/extent~Extent} Extent.
|
||||
*/
|
||||
getExtent(opt_extent) {
|
||||
// FIXME add getExtent() to rbush
|
||||
const data = this.rbush_.data;
|
||||
return createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, opt_extent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/structs/RBush} rbush R-Tree.
|
||||
*/
|
||||
concat(rbush) {
|
||||
this.rbush_.load(rbush.rbush_.all());
|
||||
for (const i in rbush.items_) {
|
||||
this.items_[i | 0] = rbush.items_[i | 0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default RBush;
|
||||
|
||||
Reference in New Issue
Block a user