metaapi.cloud-sdk
Version:
SDK for MetaApi, a professional cloud forex API which includes MetaTrader REST API and MetaTrader websocket API. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). CopyFactory copy trading API included. (https://metaapi.cloud)
235 lines (214 loc) • 5.13 kB
text/typescript
'use strict';
/**
* Implements a queue structure
* @template T Queue values type
*/
export default class Queue<T> {
private _length: number;
private _start: any;
private _end: any;
/**
* Creates a queue from array
* @param {Array<V>} array Array to create the queue from
* @return {Queue<V>} Queue created from the array
* @deprecated Use constructor instead
*/
static fromArray<V>(array: V[]) {
let queue = new Queue<V>();
array.forEach(item => queue.push(item));
return queue;
}
/**
* Constructs instance
* @param {Iterable<T>} [items] Initial items to add to the queue
*/
constructor(items?: Iterable<T>) {
for (let item of items || []) {
this.push(item);
}
this._length = 0;
}
/**
* Returns the queue size
* @return {Number} Queue size
*/
get length() {
return this._length;
}
/**
* Iterates by queue items
*/
*[Symbol.iterator](): Iterator<T> {
let current = this._start;
while (current) {
yield current.value;
current = current.next;
}
}
/**
* Returns the first element or undefined if the queue is empty
* @return {T} The first value
*/
front(): T | undefined {
return this._start?.value;
}
/**
* Returns the last element or undefined if the queue is empty
* @return {T} The last value
*/
back(): T | undefined {
return this._end?.value;
}
/**
* Pushes new elements to the end of the queue
* @param {T[]} values Values to push
*/
push(...values: T[]) {
for (let value of values) {
if (this._end) {
this._end.next = {value, prev: this._end};
this._end = this._end.next;
} else {
this._start = this._end = {value};
}
this._length++;
}
}
/**
* Removes the last element from the queue
* @return {T} The value removed or undefined
*/
pop(): T | undefined {
if (this._end) {
let result = this._end;
this._remove(this._end);
return result.value;
}
}
/**
* Inserts new elements to the front of the queue
* @param {T} value Values to unshift
*/
unshift(value: T) {
if (this._start) {
this._start = {value, next: this._start};
this._start.next.prev = this._start;
} else {
this._start = this._end = {value};
}
this._length++;
}
/**
* Removes the first element from the queue
* @return {T} The value removed or undefined
*/
shift(): T | undefined {
if (this._start) {
let result = this._start;
this._remove(this._start);
return result.value;
}
}
/**
* Finds an element in the queue by the predicate
* @param {(value: T) => boolean} predicate Predicate to use
* @return {T} Element value found or undefined
*/
find(predicate: (value: T) => boolean): T | undefined {
let current = this._start;
while (current) {
if (predicate(current.value)) {
return current.value;
}
current = current.next;
}
}
/**
* Iterates over the queue
* @param {(value: T, index: Number) => any} callable Iterator callable
*/
forEach(callable: (value: T, index: number) => any) {
let current = this._start;
let index = 0;
while (current) {
callable(current.value, index++);
current = current.next;
}
}
/**
* Removes elements iterating them and matching by predicate
* @param {(value: T) => boolean|null} predicate Returns true for values to remove. If returns null, iteration stops
*/
remove(predicate: (value: T) => boolean | null) {
let current = this._start;
while (current) {
let remove = predicate(current.value);
if (remove === null) {
break;
}
if (remove === true) {
this._remove(current);
}
current = current.next;
}
}
/**
* Removes the first occurence of element matched by predicate
* @param predicate returns true for value to removed
*/
removeOne(predicate: (value: T) => boolean) {
let removed = false;
this.remove(item => {
if (removed) {
return null;
}
if (predicate(item)) {
removed = true;
return true;
}
});
}
/**
* Creates a new queue from this one in reversed order
* @return {Queue<T>} Reversed queue
*/
reversed(): Queue<T> {
let result = new Queue<T>();
let current = this._end;
while (current) {
result.push(current.value);
current = current.prev;
}
return result;
}
/**
* Creates an array from the queue
* @return {Array<T>} Array created
*/
toArray(): T[] {
let result = [];
this.forEach(value => result.push(value));
return result;
}
/**
* Clears the queue
*/
clear() {
delete this._start;
delete this._end;
this._length = 0;
}
private _remove(node) {
if (node.prev) {
node.prev.next = node.next;
} else {
this._start = node.next;
}
if (node.next) {
node.next.prev = node.prev;
} else {
this._end = node.prev;
}
this._length--;
}
}