@fluidframework/merge-tree 2.43.0-343119 → 2.50.0-345060
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +10 -4
- package/dist/client.js.map +1 -1
- package/dist/collections/index.d.ts +0 -1
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/collections/index.js +1 -5
- package/dist/collections/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/localReference.js +10 -10
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +2 -3
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +8 -9
- package/dist/mergeTree.js.map +1 -1
- package/dist/perspective.d.ts +1 -1
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +2 -2
- package/dist/perspective.js.map +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +2 -3
- package/dist/revertibles.js.map +1 -1
- package/dist/segmentGroupCollection.d.ts.map +1 -1
- package/dist/segmentGroupCollection.js +3 -3
- package/dist/segmentGroupCollection.js.map +1 -1
- package/dist/segmentPropertiesManager.d.ts.map +1 -1
- package/dist/segmentPropertiesManager.js +6 -7
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/test/testClient.d.ts +1 -1
- package/dist/test/testClient.d.ts.map +1 -1
- package/dist/test/testClient.js +11 -11
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testClientLogger.js +4 -4
- package/dist/test/testClientLogger.js.map +1 -1
- package/lib/client.d.ts +4 -2
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +12 -6
- package/lib/client.js.map +1 -1
- package/lib/collections/index.d.ts +0 -1
- package/lib/collections/index.d.ts.map +1 -1
- package/lib/collections/index.js +0 -1
- package/lib/collections/index.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/localReference.js +1 -1
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +2 -3
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +5 -6
- package/lib/mergeTree.js.map +1 -1
- package/lib/perspective.d.ts +1 -1
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +2 -2
- package/lib/perspective.js.map +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +1 -2
- package/lib/revertibles.js.map +1 -1
- package/lib/segmentGroupCollection.d.ts.map +1 -1
- package/lib/segmentGroupCollection.js +1 -1
- package/lib/segmentGroupCollection.js.map +1 -1
- package/lib/segmentPropertiesManager.d.ts.map +1 -1
- package/lib/segmentPropertiesManager.js +1 -2
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/test/testClient.d.ts +1 -1
- package/lib/test/testClient.d.ts.map +1 -1
- package/lib/test/testClient.js +1 -1
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testClientLogger.js +1 -1
- package/lib/test/testClientLogger.js.map +1 -1
- package/package.json +18 -18
- package/src/client.ts +29 -10
- package/src/collections/index.ts +0 -7
- package/src/index.ts +0 -3
- package/src/localReference.ts +1 -1
- package/src/mergeTree.ts +11 -6
- package/src/perspective.ts +6 -1
- package/src/revertibles.ts +5 -2
- package/src/segmentGroupCollection.ts +2 -1
- package/src/segmentPropertiesManager.ts +5 -2
- package/dist/collections/list.d.ts +0 -146
- package/dist/collections/list.d.ts.map +0 -1
- package/dist/collections/list.js +0 -317
- package/dist/collections/list.js.map +0 -1
- package/dist/test/collections.list.spec.d.ts +0 -6
- package/dist/test/collections.list.spec.d.ts.map +0 -1
- package/dist/test/collections.list.spec.js +0 -84
- package/dist/test/collections.list.spec.js.map +0 -1
- package/lib/collections/list.d.ts +0 -146
- package/lib/collections/list.d.ts.map +0 -1
- package/lib/collections/list.js +0 -311
- package/lib/collections/list.js.map +0 -1
- package/lib/test/collections.list.spec.d.ts +0 -6
- package/lib/test/collections.list.spec.d.ts.map +0 -1
- package/lib/test/collections.list.spec.js +0 -82
- package/lib/test/collections.list.spec.js.map +0 -1
- package/src/collections/list.ts +0 -400
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Represents a node in a doubly linked list.
|
|
7
|
-
* @internal
|
|
8
|
-
*/
|
|
9
|
-
export interface ListNode<T> {
|
|
10
|
-
/**
|
|
11
|
-
* The list this node belongs to, or undefined if not attached.
|
|
12
|
-
*/
|
|
13
|
-
readonly list: DoublyLinkedList<T> | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* The data value stored in this node.
|
|
16
|
-
*/
|
|
17
|
-
readonly data: T;
|
|
18
|
-
/**
|
|
19
|
-
* The next node in the list, or undefined if this is the last node.
|
|
20
|
-
*/
|
|
21
|
-
readonly next: ListNode<T> | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* The previous node in the list, or undefined if this is the first node.
|
|
24
|
-
*/
|
|
25
|
-
readonly prev: ListNode<T> | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Removes this node from its list.
|
|
28
|
-
* @returns The removed node, or undefined if not in a list.
|
|
29
|
-
*/
|
|
30
|
-
remove(): ListNode<T> | undefined;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Represents a range of nodes in a doubly linked list.
|
|
34
|
-
* @internal
|
|
35
|
-
*/
|
|
36
|
-
export interface ListNodeRange<T> {
|
|
37
|
-
/**
|
|
38
|
-
* The first node in the range.
|
|
39
|
-
*/
|
|
40
|
-
first: ListNode<T>;
|
|
41
|
-
/**
|
|
42
|
-
* The last node in the range.
|
|
43
|
-
*/
|
|
44
|
-
last: ListNode<T>;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* A doubly linked list implementation with array-like methods and node access.
|
|
48
|
-
* @typeParam T - The type of data stored in the list nodes.
|
|
49
|
-
* @internal
|
|
50
|
-
*/
|
|
51
|
-
export declare class DoublyLinkedList<T> implements Iterable<ListNode<T>>, Partial<ListNodeRange<T>>, Pick<ListNode<T>[], "pop" | "shift" | "length" | "includes"> {
|
|
52
|
-
/**
|
|
53
|
-
* Creates a new doubly linked list optionally initialized with values.
|
|
54
|
-
* @param values - Optional iterable of values to populate the list.
|
|
55
|
-
*/
|
|
56
|
-
constructor(values?: Iterable<T>);
|
|
57
|
-
/**
|
|
58
|
-
* Finds the first node matching the predicate.
|
|
59
|
-
* @param predicate - Function to test each node.
|
|
60
|
-
* @returns The first matching node, or undefined if none found.
|
|
61
|
-
*/
|
|
62
|
-
find(predicate: (value: ListNode<T>, obj: DoublyLinkedList<T>) => unknown): ListNode<T> | undefined;
|
|
63
|
-
/**
|
|
64
|
-
* Returns an iterable that maps each node to a new value.
|
|
65
|
-
* @param callbackfn - Function to produce a new value for each node.
|
|
66
|
-
*/
|
|
67
|
-
map<U>(callbackfn: (value: ListNode<T>) => U): Iterable<U>;
|
|
68
|
-
/**
|
|
69
|
-
* Inserts items after the specified node.
|
|
70
|
-
* @param preceding - The node to insert after.
|
|
71
|
-
* @param items - Items to insert.
|
|
72
|
-
* @returns The range of newly inserted nodes.
|
|
73
|
-
*/
|
|
74
|
-
insertAfter(preceding: ListNode<T>, ...items: T[]): ListNodeRange<T>;
|
|
75
|
-
/**
|
|
76
|
-
* Removes and returns the last node in the list.
|
|
77
|
-
* @returns The removed node, or undefined if the list is empty.
|
|
78
|
-
*/
|
|
79
|
-
pop(): ListNode<T> | undefined;
|
|
80
|
-
/**
|
|
81
|
-
* Appends items to the end of the list.
|
|
82
|
-
* @param items - Items to append.
|
|
83
|
-
* @returns The range of newly inserted nodes.
|
|
84
|
-
*/
|
|
85
|
-
push(...items: T[]): ListNodeRange<T>;
|
|
86
|
-
/**
|
|
87
|
-
* Removes and returns the first node in the list.
|
|
88
|
-
* @returns The removed node, or undefined if the list is empty.
|
|
89
|
-
*/
|
|
90
|
-
shift(): ListNode<T> | undefined;
|
|
91
|
-
/**
|
|
92
|
-
* Inserts items at the start of the list.
|
|
93
|
-
* @param items - Items to insert.
|
|
94
|
-
* @returns The range of newly inserted nodes.
|
|
95
|
-
*/
|
|
96
|
-
unshift(...items: T[]): ListNodeRange<T>;
|
|
97
|
-
/**
|
|
98
|
-
* Removes nodes starting at `start` until `end` or `count` is reached.
|
|
99
|
-
* @param start - The node to start removing from.
|
|
100
|
-
* @param countOrEnd - The number of nodes to remove or the end node.
|
|
101
|
-
* @returns A new list containing the removed nodes.
|
|
102
|
-
*/
|
|
103
|
-
splice(start: ListNode<T>, countOrEnd?: ListNode<T> | number): DoublyLinkedList<T>;
|
|
104
|
-
/**
|
|
105
|
-
* Checks if the node is in this list.
|
|
106
|
-
* @param node - The node to check.
|
|
107
|
-
* @returns True if the node is in the list.
|
|
108
|
-
*/
|
|
109
|
-
includes(node: ListNode<T> | undefined): node is ListNode<T>;
|
|
110
|
-
private _includes;
|
|
111
|
-
private _remove;
|
|
112
|
-
/**
|
|
113
|
-
* Removes the specified node from the list.
|
|
114
|
-
* @param node - The node to remove.
|
|
115
|
-
* @returns The removed node, or undefined if not in the list.
|
|
116
|
-
*/
|
|
117
|
-
remove(node: ListNode<T> | undefined): ListNode<T> | undefined;
|
|
118
|
-
[Symbol.iterator](): IterableIterator<ListNode<T>>;
|
|
119
|
-
private _len;
|
|
120
|
-
private readonly headNode;
|
|
121
|
-
/**
|
|
122
|
-
* The number of nodes in the list.
|
|
123
|
-
*/
|
|
124
|
-
get length(): number;
|
|
125
|
-
/**
|
|
126
|
-
* Whether the list is empty.
|
|
127
|
-
*/
|
|
128
|
-
get empty(): boolean;
|
|
129
|
-
/**
|
|
130
|
-
* The first node in the list, or undefined if empty.
|
|
131
|
-
*/
|
|
132
|
-
get first(): ListNode<T> | undefined;
|
|
133
|
-
/**
|
|
134
|
-
* The last node in the list, or undefined if empty.
|
|
135
|
-
*/
|
|
136
|
-
get last(): ListNode<T> | undefined;
|
|
137
|
-
}
|
|
138
|
-
export declare function walkList<T>(list: DoublyLinkedList<T>, visitor: (node: ListNode<T>) => boolean | void, start?: ListNode<T>, forward?: boolean): boolean;
|
|
139
|
-
/**
|
|
140
|
-
* Creates a lazily evaluated iterable which returns values while the predicate returns true,
|
|
141
|
-
* and stops iterating at the first value where the predicate is false.
|
|
142
|
-
* @param start - the node to start the iteration from
|
|
143
|
-
* @param includePredicate - determine if the current value be included in the iteration or stop if iteration
|
|
144
|
-
*/
|
|
145
|
-
export declare function iterateListValuesWhile<T>(start: ListNode<T> | undefined, includePredicate: (n: ListNode<T>) => boolean): Iterable<T>;
|
|
146
|
-
//# sourceMappingURL=list.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/collections/list.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACvC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;OAEG;IACH,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB;;OAEG;IACH,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAClB;AAoED;;;;GAIG;AACH,qBAAa,gBAAgB,CAAC,CAAC,CAC9B,YACC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EACrB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAEzB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IAE7D;;;OAGG;gBACS,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAMhC;;;;OAIG;IACH,IAAI,CACH,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,OAAO,GAClE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS;IAW1B;;;OAGG;IACH,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAkB1D;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC;IAQpE;;;OAGG;IACH,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9B;;;;OAIG;IACH,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC;IAMrC;;;OAGG;IACH,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS;IAIhC;;;;OAIG;IACH,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC;IAKxC;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAyBlF;;;;OAIG;IACI,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC;IAInE,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAYf;;;;OAIG;IACI,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9D,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAkBzD,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiD;IAE1E;;OAEG;IACH,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED;;OAEG;IACH,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED;;OAEG;IACH,IAAW,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAE1C;IAED;;OAEG;IACH,IAAW,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAEzC;CACD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EACzB,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EACzB,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,IAAI,EAC9C,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,OAAO,GAAE,OAAc,GACrB,OAAO,CAqBT;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EACvC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,EAC9B,gBAAgB,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,GAC3C,QAAQ,CAAC,CAAC,CAAC,CAkBb"}
|
package/lib/collections/list.js
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
6
|
-
class HeadNode {
|
|
7
|
-
constructor(list) {
|
|
8
|
-
this._next = this;
|
|
9
|
-
this._prev = this;
|
|
10
|
-
this.headNode = this;
|
|
11
|
-
if (list) {
|
|
12
|
-
this._list = list;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
get next() {
|
|
16
|
-
return this._next === this.headNode ? undefined : this._next;
|
|
17
|
-
}
|
|
18
|
-
get prev() {
|
|
19
|
-
return this._prev === this.headNode ? undefined : this._prev;
|
|
20
|
-
}
|
|
21
|
-
get list() {
|
|
22
|
-
return this.headNode._list;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
// The any is needed for use in the remove function, where the nodes are defined with a generic type.
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
-
const DeadHead = new HeadNode(undefined);
|
|
28
|
-
class DataNode extends HeadNode {
|
|
29
|
-
constructor(headNode, data) {
|
|
30
|
-
super(undefined);
|
|
31
|
-
this.data = data;
|
|
32
|
-
this.headNode = headNode;
|
|
33
|
-
}
|
|
34
|
-
remove() {
|
|
35
|
-
return this.list?.remove(this);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function insertAfter(node, items) {
|
|
39
|
-
let previousNode = node;
|
|
40
|
-
const oldNext = previousNode._next;
|
|
41
|
-
let newRange;
|
|
42
|
-
for (const n of items) {
|
|
43
|
-
const newNode = new DataNode(node.headNode, n);
|
|
44
|
-
if (newRange === undefined) {
|
|
45
|
-
newRange = { first: newNode, last: newNode };
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
newRange.last = newNode;
|
|
49
|
-
}
|
|
50
|
-
newNode._prev = previousNode;
|
|
51
|
-
previousNode._next = newNode;
|
|
52
|
-
previousNode = newNode;
|
|
53
|
-
}
|
|
54
|
-
oldNext._prev = previousNode;
|
|
55
|
-
previousNode._next = oldNext;
|
|
56
|
-
// explicitly prevent newRange from being undefined without casting,
|
|
57
|
-
// and without additional conditionals, as this is used in some perf critical areas.
|
|
58
|
-
// i could have just asserted, but that throws a non-user friendly error,
|
|
59
|
-
// so i went with a more user-friendly error, which describes the
|
|
60
|
-
// only condition that could lead to this being undefined in the current code.
|
|
61
|
-
if (newRange === undefined) {
|
|
62
|
-
throw new UsageError("items must not be empty");
|
|
63
|
-
}
|
|
64
|
-
return newRange;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* A doubly linked list implementation with array-like methods and node access.
|
|
68
|
-
* @typeParam T - The type of data stored in the list nodes.
|
|
69
|
-
* @internal
|
|
70
|
-
*/
|
|
71
|
-
export class DoublyLinkedList {
|
|
72
|
-
/**
|
|
73
|
-
* Creates a new doubly linked list optionally initialized with values.
|
|
74
|
-
* @param values - Optional iterable of values to populate the list.
|
|
75
|
-
*/
|
|
76
|
-
constructor(values) {
|
|
77
|
-
this._len = 0;
|
|
78
|
-
this.headNode = new HeadNode(this);
|
|
79
|
-
if (values !== undefined) {
|
|
80
|
-
this.push(...values);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Finds the first node matching the predicate.
|
|
85
|
-
* @param predicate - Function to test each node.
|
|
86
|
-
* @returns The first matching node, or undefined if none found.
|
|
87
|
-
*/
|
|
88
|
-
find(predicate) {
|
|
89
|
-
let found;
|
|
90
|
-
walkList(this, (node) => {
|
|
91
|
-
if (predicate(node, this)) {
|
|
92
|
-
found = node;
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
return found;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Returns an iterable that maps each node to a new value.
|
|
100
|
-
* @param callbackfn - Function to produce a new value for each node.
|
|
101
|
-
*/
|
|
102
|
-
map(callbackfn) {
|
|
103
|
-
let node = this.first;
|
|
104
|
-
const iterator = {
|
|
105
|
-
next() {
|
|
106
|
-
if (node === undefined) {
|
|
107
|
-
return { done: true, value: undefined };
|
|
108
|
-
}
|
|
109
|
-
const rtn = { value: callbackfn(node), done: false };
|
|
110
|
-
node = node.next;
|
|
111
|
-
return rtn;
|
|
112
|
-
},
|
|
113
|
-
[Symbol.iterator]() {
|
|
114
|
-
return this;
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
return iterator;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Inserts items after the specified node.
|
|
121
|
-
* @param preceding - The node to insert after.
|
|
122
|
-
* @param items - Items to insert.
|
|
123
|
-
* @returns The range of newly inserted nodes.
|
|
124
|
-
*/
|
|
125
|
-
insertAfter(preceding, ...items) {
|
|
126
|
-
if (!this._includes(preceding)) {
|
|
127
|
-
throw new Error("preceding not in list");
|
|
128
|
-
}
|
|
129
|
-
this._len += items.length;
|
|
130
|
-
return insertAfter(preceding, items);
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Removes and returns the last node in the list.
|
|
134
|
-
* @returns The removed node, or undefined if the list is empty.
|
|
135
|
-
*/
|
|
136
|
-
pop() {
|
|
137
|
-
return this.remove(this.last);
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Appends items to the end of the list.
|
|
141
|
-
* @param items - Items to append.
|
|
142
|
-
* @returns The range of newly inserted nodes.
|
|
143
|
-
*/
|
|
144
|
-
push(...items) {
|
|
145
|
-
this._len += items.length;
|
|
146
|
-
const start = this.headNode._prev;
|
|
147
|
-
return insertAfter(start, items);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Removes and returns the first node in the list.
|
|
151
|
-
* @returns The removed node, or undefined if the list is empty.
|
|
152
|
-
*/
|
|
153
|
-
shift() {
|
|
154
|
-
return this.remove(this.first);
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Inserts items at the start of the list.
|
|
158
|
-
* @param items - Items to insert.
|
|
159
|
-
* @returns The range of newly inserted nodes.
|
|
160
|
-
*/
|
|
161
|
-
unshift(...items) {
|
|
162
|
-
this._len += items.length;
|
|
163
|
-
return insertAfter(this.headNode, items);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Removes nodes starting at `start` until `end` or `count` is reached.
|
|
167
|
-
* @param start - The node to start removing from.
|
|
168
|
-
* @param countOrEnd - The number of nodes to remove or the end node.
|
|
169
|
-
* @returns A new list containing the removed nodes.
|
|
170
|
-
*/
|
|
171
|
-
splice(start, countOrEnd) {
|
|
172
|
-
const newList = new DoublyLinkedList();
|
|
173
|
-
walkList(this, (node) => {
|
|
174
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
175
|
-
const removedNode = this._remove(node);
|
|
176
|
-
// whats special here is we preserve the node
|
|
177
|
-
// this allow looking up the old node in the new list
|
|
178
|
-
// when something preserves a reference
|
|
179
|
-
removedNode.headNode = newList.headNode;
|
|
180
|
-
removedNode._next = newList.headNode;
|
|
181
|
-
removedNode._prev = newList.headNode._prev;
|
|
182
|
-
newList.headNode._prev._next = removedNode;
|
|
183
|
-
newList.headNode._prev = removedNode;
|
|
184
|
-
newList._len++;
|
|
185
|
-
if (node === countOrEnd || newList.length === countOrEnd) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
}, start);
|
|
189
|
-
return newList;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Checks if the node is in this list.
|
|
193
|
-
* @param node - The node to check.
|
|
194
|
-
* @returns True if the node is in the list.
|
|
195
|
-
*/
|
|
196
|
-
includes(node) {
|
|
197
|
-
return this._includes(node);
|
|
198
|
-
}
|
|
199
|
-
_includes(node) {
|
|
200
|
-
return node instanceof DataNode && node.headNode === this.headNode;
|
|
201
|
-
}
|
|
202
|
-
_remove(node) {
|
|
203
|
-
if (this._includes(node)) {
|
|
204
|
-
node._prev._next = node._next;
|
|
205
|
-
node._next._prev = node._prev;
|
|
206
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
207
|
-
node.headNode = node._next = node._prev = DeadHead;
|
|
208
|
-
this._len--;
|
|
209
|
-
return node;
|
|
210
|
-
}
|
|
211
|
-
return undefined;
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Removes the specified node from the list.
|
|
215
|
-
* @param node - The node to remove.
|
|
216
|
-
* @returns The removed node, or undefined if not in the list.
|
|
217
|
-
*/
|
|
218
|
-
remove(node) {
|
|
219
|
-
return this._remove(node);
|
|
220
|
-
}
|
|
221
|
-
[Symbol.iterator]() {
|
|
222
|
-
let value = this.first;
|
|
223
|
-
const iterator = {
|
|
224
|
-
next() {
|
|
225
|
-
if (value !== undefined) {
|
|
226
|
-
const rtn = { value, done: false };
|
|
227
|
-
value = value.next;
|
|
228
|
-
return rtn;
|
|
229
|
-
}
|
|
230
|
-
return { value: undefined, done: true };
|
|
231
|
-
},
|
|
232
|
-
[Symbol.iterator]() {
|
|
233
|
-
return this;
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
return iterator;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* The number of nodes in the list.
|
|
240
|
-
*/
|
|
241
|
-
get length() {
|
|
242
|
-
return this._len;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Whether the list is empty.
|
|
246
|
-
*/
|
|
247
|
-
get empty() {
|
|
248
|
-
return this._len === 0;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* The first node in the list, or undefined if empty.
|
|
252
|
-
*/
|
|
253
|
-
get first() {
|
|
254
|
-
return this.headNode.next;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* The last node in the list, or undefined if empty.
|
|
258
|
-
*/
|
|
259
|
-
get last() {
|
|
260
|
-
return this.headNode.prev;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
export function walkList(list, visitor, start, forward = true) {
|
|
264
|
-
let current;
|
|
265
|
-
if (start) {
|
|
266
|
-
if (!list.includes(start)) {
|
|
267
|
-
throw new UsageError("start must be in the provided list");
|
|
268
|
-
}
|
|
269
|
-
current = start;
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
current = forward ? list.first : list.last;
|
|
273
|
-
}
|
|
274
|
-
// cache the next node, incase the visitor mutates the list
|
|
275
|
-
// need this to support splice
|
|
276
|
-
let next = forward ? current?.next : current?.prev;
|
|
277
|
-
while (current !== undefined) {
|
|
278
|
-
if (visitor(current) === false) {
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
current = next;
|
|
282
|
-
next = forward ? next?.next : next?.prev;
|
|
283
|
-
}
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Creates a lazily evaluated iterable which returns values while the predicate returns true,
|
|
288
|
-
* and stops iterating at the first value where the predicate is false.
|
|
289
|
-
* @param start - the node to start the iteration from
|
|
290
|
-
* @param includePredicate - determine if the current value be included in the iteration or stop if iteration
|
|
291
|
-
*/
|
|
292
|
-
export function iterateListValuesWhile(start, includePredicate) {
|
|
293
|
-
let next = start;
|
|
294
|
-
const iterator = {
|
|
295
|
-
next: () => {
|
|
296
|
-
if (next !== undefined) {
|
|
297
|
-
const current = next;
|
|
298
|
-
next = current.next;
|
|
299
|
-
if (includePredicate(current) === true) {
|
|
300
|
-
return { value: current.data, done: false };
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
return { done: true, value: undefined };
|
|
304
|
-
},
|
|
305
|
-
[Symbol.iterator]() {
|
|
306
|
-
return this;
|
|
307
|
-
},
|
|
308
|
-
};
|
|
309
|
-
return iterator;
|
|
310
|
-
}
|
|
311
|
-
//# sourceMappingURL=list.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/collections/list.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\n/**\n * Represents a node in a doubly linked list.\n * @internal\n */\nexport interface ListNode<T> {\n\t/**\n\t * The list this node belongs to, or undefined if not attached.\n\t */\n\treadonly list: DoublyLinkedList<T> | undefined;\n\t/**\n\t * The data value stored in this node.\n\t */\n\treadonly data: T;\n\t/**\n\t * The next node in the list, or undefined if this is the last node.\n\t */\n\treadonly next: ListNode<T> | undefined;\n\t/**\n\t * The previous node in the list, or undefined if this is the first node.\n\t */\n\treadonly prev: ListNode<T> | undefined;\n\t/**\n\t * Removes this node from its list.\n\t * @returns The removed node, or undefined if not in a list.\n\t */\n\tremove(): ListNode<T> | undefined;\n}\n\n/**\n * Represents a range of nodes in a doubly linked list.\n * @internal\n */\nexport interface ListNodeRange<T> {\n\t/**\n\t * The first node in the range.\n\t */\n\tfirst: ListNode<T>;\n\t/**\n\t * The last node in the range.\n\t */\n\tlast: ListNode<T>;\n}\n\nclass HeadNode<T> {\n\tpublic _next: HeadNode<T> | DataNode<T> = this;\n\tpublic _prev: HeadNode<T> | DataNode<T> = this;\n\tpublic headNode: HeadNode<T> = this;\n\tprivate readonly _list?: DoublyLinkedList<T>;\n\tconstructor(list: DoublyLinkedList<T> | undefined) {\n\t\tif (list) {\n\t\t\tthis._list = list;\n\t\t}\n\t}\n\tpublic get next(): DataNode<T> | undefined {\n\t\treturn this._next === this.headNode ? undefined : (this._next as DataNode<T>);\n\t}\n\tpublic get prev(): DataNode<T> | undefined {\n\t\treturn this._prev === this.headNode ? undefined : (this._prev as DataNode<T>);\n\t}\n\tpublic get list(): DoublyLinkedList<T> | undefined {\n\t\treturn this.headNode._list;\n\t}\n}\n\n// The any is needed for use in the remove function, where the nodes are defined with a generic type.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst DeadHead = new HeadNode<any>(undefined);\n\nclass DataNode<T> extends HeadNode<T> implements ListNode<T> {\n\tconstructor(\n\t\theadNode: HeadNode<T>,\n\t\tpublic readonly data: T,\n\t) {\n\t\tsuper(undefined);\n\t\tthis.headNode = headNode;\n\t}\n\tremove(): ListNode<T> | undefined {\n\t\treturn this.list?.remove(this);\n\t}\n}\n\nfunction insertAfter<T>(node: DataNode<T> | HeadNode<T>, items: T[]): ListNodeRange<T> {\n\tlet previousNode = node;\n\tconst oldNext = previousNode._next;\n\tlet newRange: ListNodeRange<T> | undefined;\n\tfor (const n of items) {\n\t\tconst newNode = new DataNode<T>(node.headNode, n);\n\t\tif (newRange === undefined) {\n\t\t\tnewRange = { first: newNode, last: newNode };\n\t\t} else {\n\t\t\tnewRange.last = newNode;\n\t\t}\n\t\tnewNode._prev = previousNode;\n\t\tpreviousNode._next = newNode;\n\t\tpreviousNode = newNode;\n\t}\n\toldNext._prev = previousNode;\n\tpreviousNode._next = oldNext;\n\t// explicitly prevent newRange from being undefined without casting,\n\t// and without additional conditionals, as this is used in some perf critical areas.\n\t// i could have just asserted, but that throws a non-user friendly error,\n\t// so i went with a more user-friendly error, which describes the\n\t// only condition that could lead to this being undefined in the current code.\n\tif (newRange === undefined) {\n\t\tthrow new UsageError(\"items must not be empty\");\n\t}\n\treturn newRange;\n}\n\n/**\n * A doubly linked list implementation with array-like methods and node access.\n * @typeParam T - The type of data stored in the list nodes.\n * @internal\n */\nexport class DoublyLinkedList<T>\n\timplements\n\t\tIterable<ListNode<T>>,\n\t\tPartial<ListNodeRange<T>>,\n\t\t// try to match array signature and semantics where possible\n\t\tPick<ListNode<T>[], \"pop\" | \"shift\" | \"length\" | \"includes\">\n{\n\t/**\n\t * Creates a new doubly linked list optionally initialized with values.\n\t * @param values - Optional iterable of values to populate the list.\n\t */\n\tconstructor(values?: Iterable<T>) {\n\t\tif (values !== undefined) {\n\t\t\tthis.push(...values);\n\t\t}\n\t}\n\n\t/**\n\t * Finds the first node matching the predicate.\n\t * @param predicate - Function to test each node.\n\t * @returns The first matching node, or undefined if none found.\n\t */\n\tfind(\n\t\tpredicate: (value: ListNode<T>, obj: DoublyLinkedList<T>) => unknown,\n\t): ListNode<T> | undefined {\n\t\tlet found: ListNode<T> | undefined;\n\t\twalkList(this, (node) => {\n\t\t\tif (predicate(node, this)) {\n\t\t\t\tfound = node;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\treturn found;\n\t}\n\n\t/**\n\t * Returns an iterable that maps each node to a new value.\n\t * @param callbackfn - Function to produce a new value for each node.\n\t */\n\tmap<U>(callbackfn: (value: ListNode<T>) => U): Iterable<U> {\n\t\tlet node = this.first;\n\t\tconst iterator: IterableIterator<U> = {\n\t\t\tnext(): IteratorResult<U> {\n\t\t\t\tif (node === undefined) {\n\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t}\n\t\t\t\tconst rtn = { value: callbackfn(node), done: false };\n\t\t\t\tnode = node.next;\n\t\t\t\treturn rtn;\n\t\t\t},\n\t\t\t[Symbol.iterator]() {\n\t\t\t\treturn this;\n\t\t\t},\n\t\t};\n\t\treturn iterator;\n\t}\n\n\t/**\n\t * Inserts items after the specified node.\n\t * @param preceding - The node to insert after.\n\t * @param items - Items to insert.\n\t * @returns The range of newly inserted nodes.\n\t */\n\tinsertAfter(preceding: ListNode<T>, ...items: T[]): ListNodeRange<T> {\n\t\tif (!this._includes(preceding)) {\n\t\t\tthrow new Error(\"preceding not in list\");\n\t\t}\n\t\tthis._len += items.length;\n\t\treturn insertAfter(preceding, items);\n\t}\n\n\t/**\n\t * Removes and returns the last node in the list.\n\t * @returns The removed node, or undefined if the list is empty.\n\t */\n\tpop(): ListNode<T> | undefined {\n\t\treturn this.remove(this.last);\n\t}\n\n\t/**\n\t * Appends items to the end of the list.\n\t * @param items - Items to append.\n\t * @returns The range of newly inserted nodes.\n\t */\n\tpush(...items: T[]): ListNodeRange<T> {\n\t\tthis._len += items.length;\n\t\tconst start = this.headNode._prev;\n\t\treturn insertAfter(start, items);\n\t}\n\n\t/**\n\t * Removes and returns the first node in the list.\n\t * @returns The removed node, or undefined if the list is empty.\n\t */\n\tshift(): ListNode<T> | undefined {\n\t\treturn this.remove(this.first);\n\t}\n\n\t/**\n\t * Inserts items at the start of the list.\n\t * @param items - Items to insert.\n\t * @returns The range of newly inserted nodes.\n\t */\n\tunshift(...items: T[]): ListNodeRange<T> {\n\t\tthis._len += items.length;\n\t\treturn insertAfter(this.headNode, items);\n\t}\n\n\t/**\n\t * Removes nodes starting at `start` until `end` or `count` is reached.\n\t * @param start - The node to start removing from.\n\t * @param countOrEnd - The number of nodes to remove or the end node.\n\t * @returns A new list containing the removed nodes.\n\t */\n\tsplice(start: ListNode<T>, countOrEnd?: ListNode<T> | number): DoublyLinkedList<T> {\n\t\tconst newList = new DoublyLinkedList<T>();\n\t\twalkList(\n\t\t\tthis,\n\t\t\t(node) => {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst removedNode = this._remove(node)!;\n\t\t\t\t// whats special here is we preserve the node\n\t\t\t\t// this allow looking up the old node in the new list\n\t\t\t\t// when something preserves a reference\n\t\t\t\tremovedNode.headNode = newList.headNode;\n\t\t\t\tremovedNode._next = newList.headNode;\n\t\t\t\tremovedNode._prev = newList.headNode._prev;\n\t\t\t\tnewList.headNode._prev._next = removedNode;\n\t\t\t\tnewList.headNode._prev = removedNode;\n\t\t\t\tnewList._len++;\n\t\t\t\tif (node === countOrEnd || newList.length === countOrEnd) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tstart,\n\t\t);\n\t\treturn newList;\n\t}\n\n\t/**\n\t * Checks if the node is in this list.\n\t * @param node - The node to check.\n\t * @returns True if the node is in the list.\n\t */\n\tpublic includes(node: ListNode<T> | undefined): node is ListNode<T> {\n\t\treturn this._includes(node);\n\t}\n\n\tprivate _includes(node: ListNode<T> | undefined): node is DataNode<T> {\n\t\treturn node instanceof DataNode && node.headNode === this.headNode;\n\t}\n\n\tprivate _remove(node: ListNode<T> | undefined): DataNode<T> | undefined {\n\t\tif (this._includes(node)) {\n\t\t\tnode._prev._next = node._next;\n\t\t\tnode._next._prev = node._prev;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tnode.headNode = node._next = node._prev = DeadHead;\n\t\t\tthis._len--;\n\t\t\treturn node;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes the specified node from the list.\n\t * @param node - The node to remove.\n\t * @returns The removed node, or undefined if not in the list.\n\t */\n\tpublic remove(node: ListNode<T> | undefined): ListNode<T> | undefined {\n\t\treturn this._remove(node);\n\t}\n\n\tpublic [Symbol.iterator](): IterableIterator<ListNode<T>> {\n\t\tlet value = this.first;\n\t\tconst iterator: IterableIterator<ListNode<T>> = {\n\t\t\tnext(): IteratorResult<ListNode<T>> {\n\t\t\t\tif (value !== undefined) {\n\t\t\t\t\tconst rtn = { value, done: false };\n\t\t\t\t\tvalue = value.next;\n\t\t\t\t\treturn rtn;\n\t\t\t\t}\n\t\t\t\treturn { value: undefined, done: true };\n\t\t\t},\n\t\t\t[Symbol.iterator]() {\n\t\t\t\treturn this;\n\t\t\t},\n\t\t};\n\t\treturn iterator;\n\t}\n\n\tprivate _len: number = 0;\n\tprivate readonly headNode: HeadNode<T> | DataNode<T> = new HeadNode(this);\n\n\t/**\n\t * The number of nodes in the list.\n\t */\n\tpublic get length(): number {\n\t\treturn this._len;\n\t}\n\n\t/**\n\t * Whether the list is empty.\n\t */\n\tpublic get empty(): boolean {\n\t\treturn this._len === 0;\n\t}\n\n\t/**\n\t * The first node in the list, or undefined if empty.\n\t */\n\tpublic get first(): ListNode<T> | undefined {\n\t\treturn this.headNode.next;\n\t}\n\n\t/**\n\t * The last node in the list, or undefined if empty.\n\t */\n\tpublic get last(): ListNode<T> | undefined {\n\t\treturn this.headNode.prev;\n\t}\n}\n\nexport function walkList<T>(\n\tlist: DoublyLinkedList<T>,\n\tvisitor: (node: ListNode<T>) => boolean | void,\n\tstart?: ListNode<T>,\n\tforward: boolean = true,\n): boolean {\n\tlet current: ListNode<T> | undefined;\n\tif (start) {\n\t\tif (!list.includes(start)) {\n\t\t\tthrow new UsageError(\"start must be in the provided list\");\n\t\t}\n\t\tcurrent = start;\n\t} else {\n\t\tcurrent = forward ? list.first : list.last;\n\t}\n\t// cache the next node, incase the visitor mutates the list\n\t// need this to support splice\n\tlet next = forward ? current?.next : current?.prev;\n\twhile (current !== undefined) {\n\t\tif (visitor(current) === false) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrent = next;\n\t\tnext = forward ? next?.next : next?.prev;\n\t}\n\treturn true;\n}\n\n/**\n * Creates a lazily evaluated iterable which returns values while the predicate returns true,\n * and stops iterating at the first value where the predicate is false.\n * @param start - the node to start the iteration from\n * @param includePredicate - determine if the current value be included in the iteration or stop if iteration\n */\nexport function iterateListValuesWhile<T>(\n\tstart: ListNode<T> | undefined,\n\tincludePredicate: (n: ListNode<T>) => boolean,\n): Iterable<T> {\n\tlet next: ListNode<T> | undefined = start;\n\tconst iterator: IterableIterator<T> = {\n\t\tnext: (): IteratorResult<T> => {\n\t\t\tif (next !== undefined) {\n\t\t\t\tconst current = next;\n\t\t\t\tnext = current.next;\n\t\t\t\tif (includePredicate(current) === true) {\n\t\t\t\t\treturn { value: current.data, done: false };\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { done: true, value: undefined };\n\t\t},\n\t\t[Symbol.iterator]() {\n\t\t\treturn this;\n\t\t},\n\t};\n\treturn iterator;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collections.list.spec.d.ts","sourceRoot":"","sources":["../../src/test/collections.list.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { strict as assert } from "node:assert";
|
|
6
|
-
import { DoublyLinkedList, walkList } from "../collections/index.js";
|
|
7
|
-
describe("Collections.DoublyLinkedList", () => {
|
|
8
|
-
const listCount = 5;
|
|
9
|
-
let list;
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
list = new DoublyLinkedList();
|
|
12
|
-
for (let i = 0; i < listCount; i++) {
|
|
13
|
-
list.unshift(i);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
describe(".length", () => {
|
|
17
|
-
it("Should return the total number of items in the list", () => assert.equal(list.length, listCount, "The list count doesn't match the expected count."));
|
|
18
|
-
});
|
|
19
|
-
describe(".first", () => {
|
|
20
|
-
it("Should return the first item in the list", () => assert.equal(list.first?.data, listCount - 1, "first item not expected value"));
|
|
21
|
-
});
|
|
22
|
-
describe(".last", () => {
|
|
23
|
-
it("Should return the last item in the list", () => assert.equal(list.last?.data, 0, "last item not expected value"));
|
|
24
|
-
});
|
|
25
|
-
describe("walkList", () => {
|
|
26
|
-
it("Should walk all items of the list", () => {
|
|
27
|
-
let i = listCount - 1;
|
|
28
|
-
walkList(list, (node) => {
|
|
29
|
-
assert.equal(node.data, i, "elemeted not expected value");
|
|
30
|
-
i--;
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
describe(".iterator", () => {
|
|
35
|
-
it("Should walk all items of the list", () => {
|
|
36
|
-
let i = listCount - 1;
|
|
37
|
-
for (const item of list) {
|
|
38
|
-
assert.equal(item.data, i, "elemeted not expected value");
|
|
39
|
-
i--;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
describe(".unshift", () => {
|
|
44
|
-
it("Should add item to the start of the list", () => {
|
|
45
|
-
list.unshift(99);
|
|
46
|
-
assert.equal(list.first?.data, 99, "first item not expected value");
|
|
47
|
-
assert.equal(list.length, listCount + 1, "The list count doesn't match the expected count.");
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe(".push", () => {
|
|
51
|
-
it("Should add item to the end of the list", () => {
|
|
52
|
-
list.push(99);
|
|
53
|
-
assert.equal(list.last?.data, 99, "last item not expected value");
|
|
54
|
-
assert.equal(list.length, listCount + 1, "The list count doesn't match the expected count.");
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
describe(".splice", () => {
|
|
58
|
-
for (const splicePos of [-1, 0, 1, Math.floor(listCount / 2), listCount, listCount - 1]) {
|
|
59
|
-
it(`splice at position ${splicePos}`, () => {
|
|
60
|
-
const nodesArray = [...list];
|
|
61
|
-
// negative numbers for the start move back from the end
|
|
62
|
-
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice#syntax
|
|
63
|
-
const spliceIndex = splicePos < 0 ? nodesArray.length + splicePos : splicePos;
|
|
64
|
-
// capture the node for the list splice
|
|
65
|
-
const spliceNode = nodesArray[spliceIndex];
|
|
66
|
-
const arraySplice = nodesArray.splice(spliceIndex);
|
|
67
|
-
const listSplice = spliceNode === undefined ? new DoublyLinkedList() : list.splice(spliceNode);
|
|
68
|
-
assert.equal(list.length, nodesArray.length, "remaining lengths don't match");
|
|
69
|
-
assert.equal(listSplice.length, arraySplice.length, "spliced lengths don't match");
|
|
70
|
-
const listNodes = [...list];
|
|
71
|
-
for (let i = 0; i < listNodes.length; i++) {
|
|
72
|
-
assert.equal(listNodes[i], nodesArray[i], `remaining node mismatch at pos ${i}`);
|
|
73
|
-
}
|
|
74
|
-
const listSpliceNodes = [...listSplice];
|
|
75
|
-
for (let i = 0; i < listSpliceNodes.length; i++) {
|
|
76
|
-
assert.equal(listSpliceNodes[i], arraySplice[i], `splice node mismatch at pos ${i}`);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
//# sourceMappingURL=collections.list.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collections.list.spec.js","sourceRoot":"","sources":["../../src/test/collections.list.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { DoublyLinkedList, walkList } from \"../collections/index.js\";\n\ndescribe(\"Collections.DoublyLinkedList\", () => {\n\tconst listCount = 5;\n\tlet list: DoublyLinkedList<number>;\n\n\tbeforeEach(() => {\n\t\tlist = new DoublyLinkedList<number>();\n\t\tfor (let i = 0; i < listCount; i++) {\n\t\t\tlist.unshift(i);\n\t\t}\n\t});\n\n\tdescribe(\".length\", () => {\n\t\tit(\"Should return the total number of items in the list\", () =>\n\t\t\tassert.equal(\n\t\t\t\tlist.length,\n\t\t\t\tlistCount,\n\t\t\t\t\"The list count doesn't match the expected count.\",\n\t\t\t));\n\t});\n\n\tdescribe(\".first\", () => {\n\t\tit(\"Should return the first item in the list\", () =>\n\t\t\tassert.equal(list.first?.data, listCount - 1, \"first item not expected value\"));\n\t});\n\n\tdescribe(\".last\", () => {\n\t\tit(\"Should return the last item in the list\", () =>\n\t\t\tassert.equal(list.last?.data, 0, \"last item not expected value\"));\n\t});\n\n\tdescribe(\"walkList\", () => {\n\t\tit(\"Should walk all items of the list\", () => {\n\t\t\tlet i = listCount - 1;\n\t\t\twalkList(list, (node) => {\n\t\t\t\tassert.equal(node.data, i, \"elemeted not expected value\");\n\t\t\t\ti--;\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\".iterator\", () => {\n\t\tit(\"Should walk all items of the list\", () => {\n\t\t\tlet i = listCount - 1;\n\t\t\tfor (const item of list) {\n\t\t\t\tassert.equal(item.data, i, \"elemeted not expected value\");\n\t\t\t\ti--;\n\t\t\t}\n\t\t});\n\t});\n\n\tdescribe(\".unshift\", () => {\n\t\tit(\"Should add item to the start of the list\", () => {\n\t\t\tlist.unshift(99);\n\t\t\tassert.equal(list.first?.data, 99, \"first item not expected value\");\n\t\t\tassert.equal(\n\t\t\t\tlist.length,\n\t\t\t\tlistCount + 1,\n\t\t\t\t\"The list count doesn't match the expected count.\",\n\t\t\t);\n\t\t});\n\t});\n\tdescribe(\".push\", () => {\n\t\tit(\"Should add item to the end of the list\", () => {\n\t\t\tlist.push(99);\n\t\t\tassert.equal(list.last?.data, 99, \"last item not expected value\");\n\t\t\tassert.equal(\n\t\t\t\tlist.length,\n\t\t\t\tlistCount + 1,\n\t\t\t\t\"The list count doesn't match the expected count.\",\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe(\".splice\", () => {\n\t\tfor (const splicePos of [-1, 0, 1, Math.floor(listCount / 2), listCount, listCount - 1]) {\n\t\t\tit(`splice at position ${splicePos}`, () => {\n\t\t\t\tconst nodesArray = [...list];\n\t\t\t\t// negative numbers for the start move back from the end\n\t\t\t\t// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice#syntax\n\t\t\t\tconst spliceIndex = splicePos < 0 ? nodesArray.length + splicePos : splicePos;\n\t\t\t\t// capture the node for the list splice\n\t\t\t\tconst spliceNode = nodesArray[spliceIndex];\n\t\t\t\tconst arraySplice = nodesArray.splice(spliceIndex);\n\n\t\t\t\tconst listSplice =\n\t\t\t\t\tspliceNode === undefined ? new DoublyLinkedList() : list.splice(spliceNode);\n\n\t\t\t\tassert.equal(list.length, nodesArray.length, \"remaining lengths don't match\");\n\t\t\t\tassert.equal(listSplice.length, arraySplice.length, \"spliced lengths don't match\");\n\n\t\t\t\tconst listNodes = [...list];\n\t\t\t\tfor (let i = 0; i < listNodes.length; i++) {\n\t\t\t\t\tassert.equal(listNodes[i], nodesArray[i], `remaining node mismatch at pos ${i}`);\n\t\t\t\t}\n\n\t\t\t\tconst listSpliceNodes = [...listSplice];\n\t\t\t\tfor (let i = 0; i < listSpliceNodes.length; i++) {\n\t\t\t\t\tassert.equal(listSpliceNodes[i], arraySplice[i], `splice node mismatch at pos ${i}`);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t});\n});\n"]}
|