// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { ArrayIterator, IIterator, IterableOrArrayLike, each } from '@phosphor/algorithm'; /** * A generic vector data structure. */ export class Vector { /** * Construct a new vector. * * @param values - The initial values for the vector. */ constructor(values?: IterableOrArrayLike) { if (values) { each(values, value => { this.pushBack(value); }); } } /** * Test whether the vector is empty. * * @returns `true` if the vector is empty, `false` otherwise. * * #### Notes * This is a read-only property. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ get isEmpty(): boolean { return this._array.length === 0; } /** * Get the length of the vector. * * @return The number of values in the vector. * * #### Notes * This is a read-only property. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ get length(): number { return this._array.length; } /** * Get the value at the front of the vector. * * @returns The value at the front of the vector, or `undefined` if * the vector is empty. * * #### Notes * This is a read-only property. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ get front(): T { return this._array[0]; } /** * Get the value at the back of the vector. * * @returns The value at the back of the vector, or `undefined` if * the vector is empty. * * #### Notes * This is a read-only property. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ get back(): T { return this._array[this._array.length - 1]; } /** * Create an iterator over the values in the vector. * * @returns A new iterator starting at the front of the vector. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ iter(): IIterator { return new ArrayIterator(this._array); } /** * Get the value at the specified index. * * @param index - The positive integer index of interest. * * @returns The value at the specified index. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. * * #### Undefined Behavior * An `index` which is non-integral or out of range. */ at(index: number): T { return this._array[index]; } /** * Set the value at the specified index. * * @param index - The positive integer index of interest. * * @param value - The value to set at the specified index. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. * * #### Undefined Behavior * An `index` which is non-integral or out of range. */ set(index: number, value: T): void { this._array[index] = value; } /** * Add a value to the back of the vector. * * @param value - The value to add to the back of the vector. * * @returns The new length of the vector. * * #### Complexity * Constant. * * #### Iterator Validity * No changes. */ pushBack(value: T): number { return this._array.push(value); } /** * Remove and return the value at the back of the vector. * * @returns The value at the back of the vector, or `undefined` if * the vector is empty. * * #### Complexity * Constant. * * #### Iterator Validity * Iterators pointing at the removed value are invalidated. */ popBack(): T { return this._array.pop(); } /** * Insert a value into the vector at a specific index. * * @param index - The index at which to insert the value. * * @param value - The value to set at the specified index. * * @returns The new length of the vector. * * #### Complexity * Linear. * * #### Iterator Validity * No changes. * * #### Notes * The `index` will be clamped to the bounds of the vector. * * #### Undefined Behavior * An `index` which is non-integral. */ insert(index: number, value: T): number { let array = this._array; let n = array.length; index = Math.max(0, Math.min(index, n)); for (let i = n; i > index; --i) { array[i] = array[i - 1]; } array[index] = value; return n + 1; } /** * Remove the first occurrence of a value from the vector. * * @param value - The value of interest. * * @returns The index of the removed value, or `-1` if the value * is not contained in the vector. * * #### Complexity * Linear. * * #### Iterator Validity * Iterators pointing at the removed value and beyond are invalidated. * * #### Notes * Comparison is performed using strict `===` equality. */ remove(value: T): number { let index = this._array.indexOf(value); if (index !== -1) this.removeAt(index); return index; } /** * Remove and return the value at a specific index. * * @param index - The index of the value of interest. * * @returns The value at the specified index, or `undefined` if the * index is out of range. * * #### Complexity * Constant. * * #### Iterator Validity * Iterators pointing at the removed value and beyond are invalidated. * * #### Undefined Behavior * An `index` which is non-integral. */ removeAt(index: number): T { let array = this._array; let n = array.length; if (index < 0 || index >= n) { return void 0; } let value = array[index]; for (let i = index + 1; i < n; ++i) { array[i - 1] = array[i]; } array.length = n - 1; return value; } /** * Remove all values from the vector. * * #### Complexity * Linear. * * #### Iterator Validity * All current iterators are invalidated. */ clear(): void { this._array.length = 0; } /** * Swap the contents of the vector with the contents of another. * * @param other - The other vector holding the contents to swap. * * #### Complexity * Constant. * * #### Iterator Validity * All current iterators remain valid, but will now point to the * contents of the other vector involved in the swap. */ swap(other: Vector): void { let array = other._array; other._array = this._array; this._array = array; } private _array: T[] = []; }