/** * libjass * * https://github.com/Arnavion/libjass * * Copyright 2013 Arnav Singh * * 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. */ /** * Set implementation for browsers that don't support it. Only supports Number and String elements. * * Elements are stored as properties of an object, with names derived from their type. * * @param {!Array.=} iterable Only an array of values is supported. */ class SimpleSet implements Set { private _elements: { [key: string]: T }; private _size: number; constructor(iterable?: T[]) { this.clear(); if (iterable === undefined) { return; } if (!Array.isArray(iterable)) { throw new Error("Non-array iterables are not supported by the SimpleSet constructor."); } for (const value of iterable) { this.add(value); } } /** * @param {T} value * @return {libjass.Set.} This set */ add(value: T): this { const property = toProperty(value); if (property === null) { throw new Error("This Set implementation only supports Number and String values."); } if (!(property in this._elements)) { this._size++; } this._elements[property] = value; return this; } /** */ clear(): void { this._elements = Object.create(null); this._size = 0; } /** * @param {T} value * @return {boolean} */ has(value: T): boolean { const property = toProperty(value); if (property === null) { return false; } return property in this._elements; } /** * @param {function(T, T, libjass.Set.)} callbackfn A function that is called with each value in the set. * @param {*} thisArg */ forEach(callbackfn: (value: T, index: T, set: this) => void, thisArg?: any): void { for (const property of Object.keys(this._elements)) { const element = this._elements[property]; callbackfn.call(thisArg, element, element, this); } } /** * @type {number} */ get size(): number { return this._size; } } /* tslint:disable:variable-name */ /** * Set to the global implementation of Set if the environment has one, else set to {@link ./utility/set.SimpleSet} * * Can be set to a value using {@link libjass.configure} * * Set it to null to force {@link ./utility/set.SimpleSet} to be used even if a global Set is present. * * @type {function(new:Set, !Array.=)} */ export let Set: { new (iterable?: T[]): Set; /* tslint:disable-next-line:member-ordering */ prototype: Set; } = (() => { const globalSet = global.Set; if (globalSet === undefined) { return SimpleSet; } if (typeof globalSet.prototype.forEach !== "function") { return SimpleSet; } try { if ((new globalSet([1, 2])).size !== 2) { return SimpleSet; } } catch (ex) { return SimpleSet; } return globalSet as any; })(); /* tslint:enable:variable-name */ /** * Sets the Set implementation used by libjass to the provided one. If null, {@link ./utility/set.SimpleSet} is used. * * @param {?function(new:Set, !Array.=)} value */ export function setImplementation(value: typeof Set | null): void { if (value !== null) { Set = value; } else { Set = SimpleSet; } } /** * Converts the given value into a property name for the internal map. * * @param {*} value * @return {?string} */ function toProperty(value: any): string | null { if (typeof value === "number") { return `#${ value }`; } if (typeof value === "string") { return `'${ value }`; } return null; }