UNPKG

rx-player

Version:
241 lines (222 loc) 7.08 kB
/** * Copyright 2015 CANAL+ Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import arrayFind from "./array_find"; import arrayIncludes from "./array_includes"; /** * Creates an Array automatically sorted with the sorting function given to the * constructor when the add method is called. * * @example * ```js * const sortedList = new SortedList((a, b) => a.start - b.start); * const element1 = { start: 20 }; * const element2 = { start: 10 }; * const element3 = { start: 15 }; * * sortedList.add(element1, element2); * console.log(sortedList.unwrap()); * // -> [{ start: 10 }, { start : 20 }] * * sortedList.add(element3); * console.log(sortedList.unwrap()); * // -> [{ start: 10 }, { start : 15 }, { start: 20 }] * * sortedList.removeElement(element2); * // -> [{ start: 10 }, { start: 15 }] * ``` * @class SortedList */ export default class SortedList<T> { private readonly _sortingFn: (a: T, b: T) => number; private _array: T[]; /** * @param {Function} sortingFunction */ constructor(sortingFunction: (a: T, b: T) => number) { this._array = []; this._sortingFn = sortingFunction; } /** * Add a new element to the List at the right place for the List to stay * sorted. * * /!\ The added Element will share the same reference than the given * argument, any mutation on your part can lead to an un-sorted SortedList. * You can still re-force the sorting to happen by calling forceSort. * @param {...*} elements */ public add(...elements: T[]): void { elements.sort(this._sortingFn); let j = 0; for (let i = 0; i < elements.length; i++) { const element = elements[i]; let inserted = false; while (!inserted && j < this._array.length) { if (this._sortingFn(element, this._array[j]) < 0) { this._array.splice(j, 0, element); inserted = true; } else { j++; } } if (!inserted) { this._array.push(element); } } } /** * Returns the current length of the list. * @returns {number} */ public length(): number { return this._array.length; } /** * Returns the nth element. Throws if the index does not exist. * * /!\ The returned Element shares the same reference with what is used * internally, any mutation on your part can lead to an un-sorted SortedList. * You can still re-force the sorting to happen by calling forceSort. * @throws Error - Throws if the given index is negative or superior to the * array's length. * @param {number} index * @returns {*} */ public get(index: number): T { if (index < 0 || index >= this._array.length) { throw new Error("Invalid index."); } return this._array[index]; } public toArray(): T[] { return this._array.slice(); } /** * Find the first element corresponding to the given predicate. * * /!\ The returned element shares the same reference with what is used * internally, any mutation on your part can lead to an un-sorted SortedList. * You can still re-force the sorting to happen by calling forceSort. * @param {Function} fn * @returns {*} */ public findFirst(fn: (element: T) => boolean): T | undefined { return arrayFind(this._array, fn); } /** * Returns true if the List contains the given element. * @param {*} element * @returns {Boolean} */ public has(element: T): boolean { return arrayIncludes(this._array, element); } /** * Remove the first occurence of the given element. * Returns the index of the removed element. Undefined if not found. * @returns {number|undefined} */ public removeElement(element: T): number | undefined { const indexOf = this._array.indexOf(element); if (indexOf >= 0) { this._array.splice(indexOf, 1); return indexOf; } return undefined; } /** * Returns the first element. * * /!\ The returned Element shares the same reference with what is used * internally, any mutation on your part can lead to an un-sorted SortedList. * You can still re-force the sorting to happen by calling forceSort. * @returns {*} */ public head(): T | undefined { return this._array[0]; } /** * Returns the last element. * * /!\ The returned Element shares the same reference with what is used * internally, any mutation on your part can lead to an un-sorted SortedList. * You can still re-force the sorting to happen by calling forceSort. * @returns {*} */ public last(): T | undefined { return this._array[this._array.length - 1]; } /** * Remove the first element. * Returns the element removed or undefined if no element were removed. * @returns {*} */ public shift(): T | undefined { return this._array.shift(); } /** * Remove the last element. * Returns the element removed or undefined if no element were removed. * @returns {*} */ public pop(): T | undefined { return this._array.pop(); } /** * Returns true if the wrapped Array is well-sorted. * * You might want to call this function to know if a mutation you've done * yourself impacted the order of elements. * You can then call the forceSort function to sort the list manually. * * @example * ```js * const sortedList = new SortedList((a, b) => a.start - b.start); * const element1 = { start: 20 }; * const element2 = { start: 10 }; * * sortedList.add(element1, element2); * console.log(sortedList.unwrap()); // -> [{ start: 10 }, { start : 20 }] * console.log(sortedList.checkSort()); // -> true * * element2.start = 5; // Mutation impacting the order of elements * console.log(sortedList.unwrap()); // -> [{ start: 10 }, { start : 5 }] * console.log(sortedList.checkSort()); // -> false * * sortedList.forceSort(); * console.log(sortedList.unwrap()); // -> [{ start: 5 }, { start : 10 }] * console.log(sortedList.checkSort()); // -> true * ``` * @returns {Boolean} */ // checkSort() : boolean { // for (let i = 0; i < this._array.length - 1; i++) { // if (this._sortingFn(this._array[i], this._array[i + 1]) > 0) { // return false; // } // } // return true; // } /** * Force the array to be sorted. * * You might want to call this function when you're unsure that a mutation * you've done yourself impacted the order of the elements in the list. */ // forceSort() { // this._array.sort(this._sortingFn); // } }