|
@@ -2,17 +2,9 @@
|
|
|
// Distributed under the terms of the Modified BSD License.
|
|
|
|
|
|
import {
|
|
|
- EmptyIterator, IIterator, IIterable, IterableOrArrayLike, iter, each
|
|
|
+ EmptyIterator, IIterator, IterableOrArrayLike, iter, each
|
|
|
} from 'phosphor/lib/algorithm/iteration';
|
|
|
|
|
|
-import {
|
|
|
- move
|
|
|
-} from 'phosphor/lib/algorithm/mutation';
|
|
|
-
|
|
|
-import {
|
|
|
- indexOf
|
|
|
-} from 'phosphor/lib/algorithm/searching';
|
|
|
-
|
|
|
import {
|
|
|
Vector
|
|
|
} from 'phosphor/lib/collections/vector';
|
|
@@ -27,241 +19,106 @@ import {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * The change types which occur on an observable list.
|
|
|
+ * A vector which can be observed for changes.
|
|
|
*/
|
|
|
export
|
|
|
-type ListChangeType =
|
|
|
- /**
|
|
|
- * An item was added to the list.
|
|
|
- */
|
|
|
- 'add' |
|
|
|
-
|
|
|
+interface IObservableVector<T> extends Vector<T>, IDisposable {
|
|
|
/**
|
|
|
- * Items were assigned or cleared in the list.
|
|
|
+ * A signal emitted when the vector has changed.
|
|
|
*/
|
|
|
- 'assign' |
|
|
|
+ changed: ISignal<IObservableVector<T>, ObservableVector.IChangedArgs<T>>;
|
|
|
|
|
|
/**
|
|
|
- * An item was moved within the list.
|
|
|
- */
|
|
|
- 'move' |
|
|
|
-
|
|
|
- /**
|
|
|
- * An item was removed from the list.
|
|
|
- */
|
|
|
- 'remove' |
|
|
|
-
|
|
|
- /**
|
|
|
- * An item was set in the list.
|
|
|
- */
|
|
|
- 'set';
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * The changed args object which is emitted by an observable list.
|
|
|
- */
|
|
|
-export
|
|
|
-interface IListChangedArgs<T> {
|
|
|
- /**
|
|
|
- * The type of change undergone by the list.
|
|
|
- */
|
|
|
- type: ListChangeType;
|
|
|
-
|
|
|
- /**
|
|
|
- * The new index associated with the change.
|
|
|
- *
|
|
|
- * The semantics of this value depend upon the change type:
|
|
|
- * - `Add`: The index of the added item.
|
|
|
- * - `Assign`: Always `-1`.
|
|
|
- * - `Move`: The new index of the item.
|
|
|
- * - `Remove`: Always `-1`.
|
|
|
- * - `Assign`: Always `-1`.
|
|
|
- * - `Set`: The index of the set item.
|
|
|
- */
|
|
|
- newIndex: number;
|
|
|
-
|
|
|
- /**
|
|
|
- * The new value associated with the change.
|
|
|
- *
|
|
|
- * The semantics of this value depend upon the change type:
|
|
|
- * - `Add`: The item which was added.
|
|
|
- * - `Assign`: The new items.
|
|
|
- * - `Move`: The item which was moved.
|
|
|
- * - `Remove`: Always `undefined`.
|
|
|
- * - `Set`: The new item at the index.
|
|
|
- */
|
|
|
- newValue: T | IIterator<T>;
|
|
|
-
|
|
|
- /**
|
|
|
- * The old index associated with the change.
|
|
|
- *
|
|
|
- * The semantics of this value depend upon the change type:
|
|
|
- * - `Add`: Always `-1`.
|
|
|
- * - `Assign`: Always `-1`.
|
|
|
- * - `Move`: The old index of the item.
|
|
|
- * - `Remove`: The index of the removed item.
|
|
|
- * - `Set`: The index of the set item.
|
|
|
- */
|
|
|
- oldIndex: number;
|
|
|
-
|
|
|
- /**
|
|
|
- * The old value associated with the change.
|
|
|
- *
|
|
|
- * The semantics of this value depend upon the change type:
|
|
|
- * - `Add`: Always `undefined`.
|
|
|
- * - `Assign`: The old items.
|
|
|
- * - `Move`: The item which was moved.
|
|
|
- * - `Remove`: The item which was removed.
|
|
|
- * - `Set`: The old item at the index.
|
|
|
- */
|
|
|
- oldValue: T | IIterator<T>;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * A sequence container which can be observed for changes.
|
|
|
- */
|
|
|
-export
|
|
|
-interface IObservableList<T> extends IDisposable, IIterable<T> {
|
|
|
- /**
|
|
|
- * A signal emitted when the list has changed.
|
|
|
- */
|
|
|
- changed: ISignal<IObservableList<T>, IListChangedArgs<T>>;
|
|
|
-
|
|
|
- /**
|
|
|
- * The number of items in the list.
|
|
|
- */
|
|
|
- readonly length: number;
|
|
|
-
|
|
|
- /**
|
|
|
- * Get the item at a specific index in the list.
|
|
|
+ * Move a value from one index to another.
|
|
|
*
|
|
|
- * @param index - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * @parm fromIndex - The index of the element to move.
|
|
|
*
|
|
|
- * @returns The item at the specified index, or `undefined` if the
|
|
|
- * index is out of range.
|
|
|
- */
|
|
|
- at(index: number): T;
|
|
|
-
|
|
|
- /**
|
|
|
- * Set the item at a specific index.
|
|
|
+ * @param toIndex - The index to move the element to.
|
|
|
*
|
|
|
- * @param index - The index of interest. If this is negative, it is
|
|
|
- * offset from the end of the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
*
|
|
|
- * @param item - The item to set at the index.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing at the lesser of the `fromIndex` and the `toIndex`
|
|
|
+ * and beyond are invalidated.
|
|
|
*
|
|
|
- * @returns The item which occupied the index, or `undefined` if the
|
|
|
- * index is out of range.
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * A `fromIndex` or a `toIndex` which is non-integral.
|
|
|
*/
|
|
|
- set(index: number, item: T): T;
|
|
|
+ move(fromIndex: number, toIndex: number): void;
|
|
|
|
|
|
/**
|
|
|
- * Add an item to the end of the list.
|
|
|
+ * Push a set of values to the back of the vector.
|
|
|
*
|
|
|
- * @param item - The item to add to the list.
|
|
|
+ * @param values - An iterable or array-like set of values to add.
|
|
|
*
|
|
|
* @returns The new length of the vector.
|
|
|
- */
|
|
|
- pushBack(item: T): number;
|
|
|
-
|
|
|
- /**
|
|
|
- * Insert an item into the list at a specific index.
|
|
|
*
|
|
|
- * @param index - The index at which to insert the item. If this is
|
|
|
- * negative, it is offset from the end of the list. In all cases,
|
|
|
- * it is clamped to the bounds of the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
*
|
|
|
- * @param item - The item to insert into the list.
|
|
|
- *
|
|
|
- * @returns The the new length of the vector.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*/
|
|
|
- insert(index: number, item: T): number;
|
|
|
+ pushAll(values: IterableOrArrayLike<T>): number;
|
|
|
|
|
|
/**
|
|
|
- * Move an item from one index to another.
|
|
|
+ * Insert a set of items into the vector at the specified index.
|
|
|
*
|
|
|
- * @param fromIndex - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * @param index - The index at which to insert the values.
|
|
|
*
|
|
|
- * @param toIndex - The desired index for the item. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * @param values - The values to insert at the specified index.
|
|
|
*
|
|
|
- * @returns `true` if the item was moved, `false` otherwise.
|
|
|
- */
|
|
|
- move(fromIndex: number, toIndex: number): boolean;
|
|
|
-
|
|
|
- /**
|
|
|
- * Remove the first occurrence of a specific item from the list.
|
|
|
+ * @returns The new length of the vector.
|
|
|
*
|
|
|
- * @param item - The item to remove from the list.
|
|
|
+ * #### Complexity.
|
|
|
+ * Linear.
|
|
|
*
|
|
|
- * @return The index occupied by the item, or `-1` if the item is
|
|
|
- * not contained in the list.
|
|
|
- */
|
|
|
- remove(item: T): number;
|
|
|
-
|
|
|
- /**
|
|
|
- * Remove the item at a specific index.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*
|
|
|
- * @param index - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * #### Notes
|
|
|
+ * The `index` will be clamped to the bounds of the vector.
|
|
|
*
|
|
|
- * @returns The item at the specified index, or `undefined` if the
|
|
|
- * index is out of range.
|
|
|
+ * #### Undefined Behavior.
|
|
|
+ * An `index` which is non-integral.
|
|
|
*/
|
|
|
- removeAt(index: number): T;
|
|
|
+ insertAll(index: number, values: IterableOrArrayLike<T>): number;
|
|
|
|
|
|
/**
|
|
|
- * Assign the items in the list.
|
|
|
+ * Remove a range of items from the list.
|
|
|
*
|
|
|
- * @param items - The items to assign.
|
|
|
+ * @param startIndex - The start index of the range to remove (inclusive).
|
|
|
*
|
|
|
- * @returns An iterator for of the items in the existing list.
|
|
|
- */
|
|
|
- assign(items: IterableOrArrayLike<T>): IIterator<T>;
|
|
|
-
|
|
|
- /**
|
|
|
- * Remove all items from the list.
|
|
|
+ * @param endIndex - The end index of the range to remove (exclusive).
|
|
|
+ *
|
|
|
+ * @returns The new length of the vector.
|
|
|
*
|
|
|
- * @returns An iterator for the items removed from the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
*
|
|
|
- * #### Notes
|
|
|
- * This is equivalent to `list.assign([])`.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing to the first removed value and beyond are invalid.
|
|
|
+ *
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * A `startIndex` or `endIndex` which is non-integral.
|
|
|
*/
|
|
|
- clear(): IIterator<T>;
|
|
|
+ removeRange(startIndex: number, endIndex: number): number;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * A concrete implementation of [[IObservableList]].
|
|
|
+ * A concrete implementation of [[IObservableVector]].
|
|
|
*/
|
|
|
export
|
|
|
-class ObservableList<T> implements IObservableList<T> {
|
|
|
- /**
|
|
|
- * Construct a new observable list.
|
|
|
- *
|
|
|
- * @param items - The initial items for the list.
|
|
|
- */
|
|
|
- constructor(items?: IterableOrArrayLike<T>) {
|
|
|
- this.internal = new Vector<T>(items);
|
|
|
- }
|
|
|
-
|
|
|
+class ObservableVector<T> implements IObservableVector<T> extends Vector {
|
|
|
/**
|
|
|
* A signal emitted when the list has changed.
|
|
|
*
|
|
|
* #### Notes
|
|
|
* This is a pure delegate to the [[changedSignal]].
|
|
|
*/
|
|
|
- changed: ISignal<ObservableList<T>, IListChangedArgs<T>>;
|
|
|
-
|
|
|
- /**
|
|
|
- * The number of items in the list.
|
|
|
- */
|
|
|
- get length(): number {
|
|
|
- return this.internal.length;
|
|
|
- }
|
|
|
+ changed: ISignal<ObservableVector<T>, IListChangedArgs<T>>;
|
|
|
|
|
|
/**
|
|
|
* Test whether the list has been disposed.
|
|
@@ -283,323 +140,413 @@ class ObservableList<T> implements IObservableList<T> {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Create an iterator over the values in the list.
|
|
|
+ * Set the value at the specified index.
|
|
|
*
|
|
|
- * @returns A new iterator starting at the front of the list.
|
|
|
- */
|
|
|
- iter(): IIterator<T> {
|
|
|
- return this.internal.iter();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Get the item at a specific index in the list.
|
|
|
+ * @param index - The positive integer index of interest.
|
|
|
*
|
|
|
- * @param index - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * @param value - The value to set at the specified index.
|
|
|
*
|
|
|
- * @returns The item at the specified index, or `undefined` if the
|
|
|
- * index is out of range.
|
|
|
- */
|
|
|
- at(index: number): T {
|
|
|
- return this.internal.at(this._norm(index));
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Get the index of the first occurence of an item in the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
*
|
|
|
- * @param item - The item of interest.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*
|
|
|
- * @returns The index of the specified item or `-1` if the item is
|
|
|
- * not contained in the list.
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * An `index` which is non-integral or out of range.
|
|
|
*/
|
|
|
- indexOf(item: T): number {
|
|
|
- return indexOf(this.internal, item);
|
|
|
+ set(index: number, item: T): T {
|
|
|
+ let oldValues = iter([this.at(index)]);
|
|
|
+ super.set(index, number);
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'set',
|
|
|
+ oldIndex: index,
|
|
|
+ newIndex: index,
|
|
|
+ oldValues,
|
|
|
+ newValues = iter([item])
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Set the item at a specific index.
|
|
|
+ * Add a value to the back of the vector.
|
|
|
*
|
|
|
- * @param index - The index of interest. If this is negative, it is
|
|
|
- * offset from the end of the list.
|
|
|
+ * @param value - The value to add to the back of the vector.
|
|
|
*
|
|
|
- * @param item - The item to set at the index.
|
|
|
+ * @returns The new length of the vector.
|
|
|
*
|
|
|
- * @returns The item which occupied the index, or `undefined` if the
|
|
|
- * index is out of range.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
+ *
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*/
|
|
|
- set(index: number, item: T): T {
|
|
|
- let i = this._norm(index);
|
|
|
- if (!this._check(i)) {
|
|
|
- return void 0;
|
|
|
- }
|
|
|
- return this.setItem(i, item);
|
|
|
+ pushBack(value: T): number {
|
|
|
+ let num = super.pushBack(value);
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'add',
|
|
|
+ oldIndex: -1,
|
|
|
+ newIndex: this.length - 1,
|
|
|
+ oldValues: EmptyIterator.instance,
|
|
|
+ newValues: iter(value)
|
|
|
+ });
|
|
|
+ return num;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Add an item to the end of the list.
|
|
|
+ * 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.
|
|
|
*
|
|
|
- * @param item - The item to add to the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
*
|
|
|
- * @returns The index at which the item was added.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing at the removed value are invalidated.
|
|
|
*/
|
|
|
- pushBack(item: T): number {
|
|
|
- return this.addItem(this.internal.length, item);
|
|
|
+ popBack(): T {
|
|
|
+ let value = super.popBack();
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex: this.length,
|
|
|
+ newIndex: -1,
|
|
|
+ oldValues: iter(value),
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Insert an item into the list at a specific index.
|
|
|
+ * Insert a value into the vector at a specific index.
|
|
|
*
|
|
|
- * @param index - The index at which to insert the item. If this is
|
|
|
- * negative, it is offset from the end of the list. In all cases,
|
|
|
- * it is clamped to the bounds of the list.
|
|
|
+ * @param index - The index at which to insert the value.
|
|
|
*
|
|
|
- * @param item - The item to insert into the list.
|
|
|
+ * @param value - The value to set at the specified index.
|
|
|
*
|
|
|
- * @returns The index at which the item was inserted.
|
|
|
- */
|
|
|
- insert(index: number, item: T): number {
|
|
|
- return this.addItem(this._clamp(index), item);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Move an item from one index to another.
|
|
|
+ * @returns The new length of the vector.
|
|
|
*
|
|
|
- * @param fromIndex - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
*
|
|
|
- * @param toIndex - The desired index for the item. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
+ *
|
|
|
+ * #### Notes
|
|
|
+ * The `index` will be clamped to the bounds of the vector.
|
|
|
*
|
|
|
- * @returns `true` if the item was moved, `false` otherwise.
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * An `index` which is non-integral.
|
|
|
*/
|
|
|
- move(fromIndex: number, toIndex: number): boolean {
|
|
|
- let i = this._norm(fromIndex);
|
|
|
- if (!this._check(i)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- let j = this._norm(toIndex);
|
|
|
- if (!this._check(j)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- return this.moveItem(i, j);
|
|
|
+ insert(index: number, value: T): number {
|
|
|
+ let num = super.insert(index, value);
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'add',
|
|
|
+ oldIndex: -1,
|
|
|
+ newIndex: index,
|
|
|
+ oldValues: EmptyIterator.instance,
|
|
|
+ newValues: iter(value)
|
|
|
+ });
|
|
|
+ return num;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Remove the first occurrence of a specific item from the list.
|
|
|
+ * 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.
|
|
|
*
|
|
|
- * @param item - The item to remove from the list.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing at the removed value and beyond are invalidated.
|
|
|
*
|
|
|
- * @return The index occupied by the item, or `-1` if the item is
|
|
|
- * not contained in the list.
|
|
|
+ * #### Notes
|
|
|
+ * Comparison is performed using strict `===` equality.
|
|
|
*/
|
|
|
- remove(item: T): number {
|
|
|
- let i = indexOf(this.internal, item);
|
|
|
- if (i !== -1) {
|
|
|
- this.removeItem(i);
|
|
|
- }
|
|
|
- return i;
|
|
|
+ remove(value: T): number {
|
|
|
+ let oldIndex = this.indexOf(value);
|
|
|
+ let num = super.remove(value);
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex,
|
|
|
+ newIndex: -1,
|
|
|
+ oldValues: iter(value),
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
+ });
|
|
|
+ return num;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Remove the item at a specific index.
|
|
|
+ * Remove and return the value at a specific index.
|
|
|
*
|
|
|
- * @param index - The index of the item of interest. If this is
|
|
|
- * negative, it is offset from the end of the list.
|
|
|
+ * @param index - The index of the value of interest.
|
|
|
*
|
|
|
- * @returns The item at the specified index, or `undefined` if the
|
|
|
+ * @returns The value at the specified index, or `undefined` if the
|
|
|
* index is out of range.
|
|
|
- */
|
|
|
- removeAt(index: number): T {
|
|
|
- let i = this._norm(index);
|
|
|
- if (!this._check(i)) {
|
|
|
- return void 0;
|
|
|
- }
|
|
|
- return this.removeItem(i);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Assign the items in the list.
|
|
|
*
|
|
|
- * @param items - The items to assign.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
+ *
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing at the removed value and beyond are invalidated.
|
|
|
*
|
|
|
- * @returns An iterator for of the items in the existing list.
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * An `index` which is non-integral.
|
|
|
*/
|
|
|
- assign(items: IterableOrArrayLike<T>): IIterator<T> {
|
|
|
- let old: T[] = [];
|
|
|
- while (!this.internal.isEmpty) {
|
|
|
- old.push(this.internal.removeAt(0));
|
|
|
- }
|
|
|
- let newValue = iter(items);
|
|
|
- let oldValue = iter(old);
|
|
|
-
|
|
|
- each(newValue, item => {
|
|
|
- this.internal.pushBack(item);
|
|
|
- });
|
|
|
-
|
|
|
+ removeAt(index: number): T {
|
|
|
+ let value = super.removeAt(index);
|
|
|
this.changed.emit({
|
|
|
- type: 'assign',
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex: index,
|
|
|
newIndex: -1,
|
|
|
- newValue,
|
|
|
- oldIndex: -1,
|
|
|
- oldValue
|
|
|
+ oldValues: iter(value),
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
});
|
|
|
- return oldValue;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Remove all items from the list.
|
|
|
+ * Remove all values from the vector.
|
|
|
*
|
|
|
- * @returns An iterator for the items removed from the list.
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
*
|
|
|
- * #### Notes
|
|
|
- * This is equivalent to `list.assign([])`.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * All current iterators are invalidated.
|
|
|
*/
|
|
|
- clear(): IIterator<T> {
|
|
|
- return this.assign(EmptyIterator.instance);
|
|
|
+ clear(): void {
|
|
|
+ let values = [];
|
|
|
+ each(this, value => { values.push(value); });
|
|
|
+ super.clear();
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex: 0,
|
|
|
+ newIndex: -1,
|
|
|
+ oldValues: iter(values),
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The protected internal array of items for the list.
|
|
|
- *
|
|
|
- * #### Notes
|
|
|
- * Subclasses may access this array directly as needed.
|
|
|
- */
|
|
|
- protected internal: Vector<T>;
|
|
|
-
|
|
|
- /**
|
|
|
- * Add an item to the list at the specified index.
|
|
|
- *
|
|
|
- * @param index - The index at which to add the item. This must be
|
|
|
- * an integer in the range `[0, internal.length]`.
|
|
|
+ * Swap the contents of the vector with the contents of another.
|
|
|
*
|
|
|
- * @param item - The item to add at the specified index.
|
|
|
+ * @param other - The other vector holding the contents to swap.
|
|
|
*
|
|
|
- * @returns The index at which the item was added.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
*
|
|
|
- * #### Notes
|
|
|
- * This may be reimplemented by subclasses to customize the behavior.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * All current iterators remain valid, but will now point to the
|
|
|
+ * contents of the other vector involved in the swap.
|
|
|
*/
|
|
|
- protected addItem(index: number, item: T): number {
|
|
|
- let value = this.internal.insert(index, item);
|
|
|
+ swap(other: Vector<T>): void {
|
|
|
+ let oldValues = this.iter();
|
|
|
+ super.swap(other);
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex: 0,
|
|
|
+ newIndex: -1,
|
|
|
+ oldValues,
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
+ });
|
|
|
this.changed.emit({
|
|
|
type: 'add',
|
|
|
- newIndex: index,
|
|
|
- newValue: item,
|
|
|
oldIndex: -1,
|
|
|
- oldValue: void 0,
|
|
|
+ newIndex: 0,
|
|
|
+ oldValues: EmptyIterator.instance,
|
|
|
+ newValues: this.iter()
|
|
|
});
|
|
|
- return value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Move an item in the list from one index to another.
|
|
|
+ * Move a value from one index to another.
|
|
|
*
|
|
|
- * @param fromIndex - The initial index of the item. This must be
|
|
|
- * an integer in the range `[0, internal.length)`.
|
|
|
+ * @parm fromIndex - The index of the element to move.
|
|
|
*
|
|
|
- * @param toIndex - The desired index for the item. This must be
|
|
|
- * an integer in the range `[0, internal.length)`.
|
|
|
+ * @param toIndex - The index to move the element to.
|
|
|
*
|
|
|
- * @returns `true` if the item was moved, `false` otherwise.
|
|
|
+ * #### Complexity
|
|
|
+ * Constant.
|
|
|
*
|
|
|
- * #### Notes
|
|
|
- * This may be reimplemented by subclasses to customize the behavior.
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing at the lesser of the `fromIndex` and the `toIndex`
|
|
|
+ * and beyond are invalidated.
|
|
|
+ *
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * A `fromIndex` or a `toIndex` which is non-integral.
|
|
|
*/
|
|
|
- protected moveItem(fromIndex: number, toIndex: number): boolean {
|
|
|
- let before = this.internal.at(toIndex);
|
|
|
- move(this.internal, fromIndex, toIndex);
|
|
|
- let after = this.internal.at(toIndex);
|
|
|
- if (before === after) {
|
|
|
- return;
|
|
|
+ move(fromIndex: number, toIndex: number): void {
|
|
|
+ let value = this.at(fromIndex);
|
|
|
+ let it = iter(value);
|
|
|
+ super.removeAt(fromIndex);
|
|
|
+ if (toIndex < fromIndex) {
|
|
|
+ toIndex -= 1;
|
|
|
}
|
|
|
+ super.insert(toIndex, value);
|
|
|
this.changed.emit({
|
|
|
type: 'move',
|
|
|
- newIndex: toIndex,
|
|
|
- newValue: after,
|
|
|
oldIndex: fromIndex,
|
|
|
- oldValue: after,
|
|
|
+ newIndex: toIndex,
|
|
|
+ oldValues: it
|
|
|
+ newValues: it
|
|
|
});
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Remove the item from the list at the specified index.
|
|
|
+ * Push a set of values to the back of the vector.
|
|
|
*
|
|
|
- * @param index - The index of the item to remove. This must be
|
|
|
- * an integer in the range `[0, internal.length)`.
|
|
|
+ * @param values - An iterable or array-like set of values to add.
|
|
|
*
|
|
|
- * @returns The item removed from the list.
|
|
|
+ * @returns The new length of the vector.
|
|
|
*
|
|
|
- * #### Notes
|
|
|
- * This may be reimplemented by subclasses to customize the behavior.
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
+ *
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*/
|
|
|
- protected removeItem(index: number): T {
|
|
|
- let item = this.internal.removeAt(index);
|
|
|
+ pushAll(values: IterableOrArrayLike<T>): number {
|
|
|
+ let newIndex = this.length;
|
|
|
+ each(values, value => { super.pushBack(value); });
|
|
|
this.changed.emit({
|
|
|
- type: 'remove',
|
|
|
- newIndex: -1,
|
|
|
- newValue: void 0,
|
|
|
- oldIndex: index,
|
|
|
- oldValue: item,
|
|
|
+ type: 'add',
|
|
|
+ oldIndex: -1,
|
|
|
+ newIndex,
|
|
|
+ oldValues: EmptyIterator.instance,
|
|
|
+ newValues = iter(values)
|
|
|
});
|
|
|
- return item;
|
|
|
+ return this.length;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Set the item at a specific index in the list.
|
|
|
+ * Insert a set of items into the vector at the specified index.
|
|
|
*
|
|
|
- * @param index - The index of interest. This must be an integer in
|
|
|
- * the range `[0, internal.length)`.
|
|
|
+ * @param index - The index at which to insert the values.
|
|
|
*
|
|
|
- * @param item - The item to set at the index.
|
|
|
+ * @param values - The values to insert at the specified index.
|
|
|
*
|
|
|
- * @returns The item which previously occupied the specified index.
|
|
|
+ * @returns The new length of the vector.
|
|
|
+ *
|
|
|
+ * #### Complexity.
|
|
|
+ * Linear.
|
|
|
+ *
|
|
|
+ * #### Iterator Validity
|
|
|
+ * No changes.
|
|
|
*
|
|
|
* #### Notes
|
|
|
- * This may be reimplemented by subclasses to customize the behavior.
|
|
|
+ * The `index` will be clamped to the bounds of the vector.
|
|
|
+ *
|
|
|
+ * #### Undefined Behavior.
|
|
|
+ * An `index` which is non-integral.
|
|
|
*/
|
|
|
- protected setItem(index: number, item: T): T {
|
|
|
- let old = this.internal.at(index);
|
|
|
- this.internal.set(index, item);
|
|
|
+ insertAll(index: number, values: IterableOrArrayLike<T>): number {
|
|
|
+ each(values, value => { super.insert(index++, value); });
|
|
|
this.changed.emit({
|
|
|
- type: 'set',
|
|
|
+ type: 'add',
|
|
|
+ oldIndex: -1,
|
|
|
newIndex: index,
|
|
|
- newValue: item,
|
|
|
- oldIndex: index,
|
|
|
- oldValue: old,
|
|
|
+ oldValues: EmptyIterator.instance,
|
|
|
+ newValues: iter(values)
|
|
|
});
|
|
|
- return old;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Normalize an index and offset negative values from the list end.
|
|
|
- */
|
|
|
- private _norm(i: number): number {
|
|
|
- return i < 0 ? Math.floor(i) + this.internal.length : Math.floor(i);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Check whether a normalized index is in range.
|
|
|
+ * Remove a range of items from the list.
|
|
|
+ *
|
|
|
+ * @param startIndex - The start index of the range to remove (inclusive).
|
|
|
+ *
|
|
|
+ * @param endIndex - The end index of the range to remove (exclusive).
|
|
|
+ *
|
|
|
+ * @returns The new length of the vector.
|
|
|
+ *
|
|
|
+ * #### Complexity
|
|
|
+ * Linear.
|
|
|
+ *
|
|
|
+ * #### Iterator Validity
|
|
|
+ * Iterators pointing to the first removed value and beyond are invalid.
|
|
|
+ *
|
|
|
+ * #### Undefined Behavior
|
|
|
+ * A `startIndex` or `endIndex` which is non-integral.
|
|
|
*/
|
|
|
- private _check(i: number): boolean {
|
|
|
- return i >= 0 && i < this.internal.length;
|
|
|
+ removeRange(startIndex: number, endIndex: number): number {
|
|
|
+ let oldValues: T[] = [];
|
|
|
+ for (let i = startIndex; i < endIndex; i++) {
|
|
|
+ oldValues.push(super.removeAt(startIndex));
|
|
|
+ }
|
|
|
+ this.changed.emit({
|
|
|
+ type: 'remove',
|
|
|
+ oldIndex: startIndex,
|
|
|
+ newIndex: -1,
|
|
|
+ oldValues: iter(oldValues),
|
|
|
+ newValues: EmptyIterator.instance
|
|
|
+ });
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /**
|
|
|
- * Normalize and clamp an index to the list bounds.
|
|
|
- */
|
|
|
- private _clamp(i: number): number {
|
|
|
- return Math.max(0, Math.min(this._norm(i), this.internal.length));
|
|
|
- }
|
|
|
|
|
|
- /**
|
|
|
- * Normalize and limit a count to the length of the list.
|
|
|
- */
|
|
|
- private _limit(c: number): number {
|
|
|
- return Math.max(0, Math.min(Math.floor(c), this.internal.length));
|
|
|
+/**
|
|
|
+ * The namespace for `ObservableVector` class statics.
|
|
|
+ */
|
|
|
+export
|
|
|
+namespace ObservableVector {
|
|
|
+ /**
|
|
|
+ * The change types which occur on an observable list.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ type ChangeType =
|
|
|
+ /**
|
|
|
+ * An item was added to the list.
|
|
|
+ */
|
|
|
+ 'add' |
|
|
|
+
|
|
|
+ /**
|
|
|
+ * An item was moved within the list.
|
|
|
+ */
|
|
|
+ 'move' |
|
|
|
+
|
|
|
+ /**
|
|
|
+ * An item was removed from the list.
|
|
|
+ */
|
|
|
+ 'remove' |
|
|
|
+
|
|
|
+ /**
|
|
|
+ * An item was set in the list.
|
|
|
+ */
|
|
|
+ 'set';
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The changed args object which is emitted by an observable list.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ interface IChangedArgs<T> {
|
|
|
+ /**
|
|
|
+ * The type of change undergone by the list.
|
|
|
+ */
|
|
|
+ type: ChangeType;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The new index associated with the change.
|
|
|
+ */
|
|
|
+ newIndex: number;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The new values associated with the change.
|
|
|
+ */
|
|
|
+ newValues: IIterator<T>;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The old index associated with the change.
|
|
|
+ */
|
|
|
+ oldIndex: number;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The old values associated with the change.
|
|
|
+ */
|
|
|
+ oldValues: IIterator<T>;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
-// Define the signals for the `ObservableList` class.
|
|
|
-defineSignal(ObservableList.prototype, 'changed');
|
|
|
+// Define the signals for the `ObservableVector` class.
|
|
|
+defineSignal(ObservableVector.prototype, 'changed');
|