collect-your-stuff 1.3.0 → 1.4.0
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/README.md +802 -77
- package/dist/collections/arrayable/ArrayElement.d.ts +2 -0
- package/dist/collections/arrayable/ArrayElement.js +4 -2
- package/dist/collections/arrayable/ArrayElement.min.js +1 -1
- package/dist/collections/arrayable/Arrayable.d.ts +27 -13
- package/dist/collections/arrayable/Arrayable.js +47 -12
- package/dist/collections/arrayable/Arrayable.min.js +1 -1
- package/dist/collections/doubly-linked-list/DoubleLinker.d.ts +5 -1
- package/dist/collections/doubly-linked-list/DoubleLinker.js +5 -1
- package/dist/collections/doubly-linked-list/DoublyLinkedList.d.ts +25 -13
- package/dist/collections/doubly-linked-list/DoublyLinkedList.js +106 -53
- package/dist/collections/doubly-linked-list/DoublyLinkedList.min.js +1 -1
- package/dist/collections/linked-list/LinkedList.d.ts +27 -10
- package/dist/collections/linked-list/LinkedList.js +106 -43
- package/dist/collections/linked-list/LinkedList.min.js +1 -1
- package/dist/collections/linked-list/Linker.d.ts +5 -2
- package/dist/collections/linked-list/Linker.js +9 -5
- package/dist/collections/linked-list/Linker.min.js +1 -1
- package/dist/collections/linked-tree-list/LinkedTreeList.d.ts +16 -4
- package/dist/collections/linked-tree-list/LinkedTreeList.js +25 -22
- package/dist/collections/linked-tree-list/LinkedTreeList.min.js +1 -1
- package/dist/collections/linked-tree-list/TreeLinker.d.ts +7 -1
- package/dist/collections/linked-tree-list/TreeLinker.js +7 -1
- package/dist/collections/queue/Queue.d.ts +6 -3
- package/dist/collections/queue/Queue.js +23 -18
- package/dist/collections/queue/Queue.min.js +1 -1
- package/dist/collections/queue/Queueable.d.ts +10 -4
- package/dist/collections/queue/Queueable.js +11 -6
- package/dist/collections/queue/Queueable.min.js +1 -1
- package/dist/collections/stack/Stack.d.ts +4 -3
- package/dist/collections/stack/Stack.js +4 -4
- package/dist/collections/stack/Stack.min.js +1 -1
- package/dist/collections/stack/Stackable.d.ts +4 -1
- package/dist/collections/stack/Stackable.js +7 -5
- package/dist/collections/stack/Stackable.min.js +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/recipes/ArrayIterator.d.ts +10 -0
- package/dist/recipes/ArrayIterator.js +10 -0
- package/dist/recipes/DoubleLinkerIterator.d.ts +9 -0
- package/dist/recipes/DoubleLinkerIterator.js +9 -0
- package/dist/recipes/LinkerIterator.d.ts +9 -0
- package/dist/recipes/LinkerIterator.js +9 -0
- package/dist/recipes/Runnable.d.ts +3 -2
- package/dist/recipes/Runnable.js +3 -2
- package/dist/recipes/TreeLinkerIterator.d.ts +9 -0
- package/dist/recipes/TreeLinkerIterator.js +9 -0
- package/package.json +2 -1
|
@@ -23,11 +23,19 @@ var _LinkedList = require('../linked-list/LinkedList')
|
|
|
23
23
|
class DoublyLinkedList {
|
|
24
24
|
/**
|
|
25
25
|
* Create the new DoublyLinkedList instance.
|
|
26
|
+
* @param {DoubleLinker} [linkerClass=DoubleLinker] The class used to wrap given data as linkers.
|
|
26
27
|
*/
|
|
27
28
|
constructor (linkerClass = _DoubleLinker.DoubleLinker) {
|
|
29
|
+
/** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
|
|
28
30
|
this.classType = DoublyLinkedList
|
|
31
|
+
/** A linker of the list (null when the list is empty); the head is found by walking back from it. */
|
|
29
32
|
this.innerList = null
|
|
33
|
+
/** Whether the inner list has been initialized (it can only be initialized once). */
|
|
30
34
|
this.initialized = false
|
|
35
|
+
/** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
|
|
36
|
+
this.tailCache = null
|
|
37
|
+
/** The number of linkers, kept up to date by the list's own methods so that the length does not need to walk the whole list (null when not known yet). */
|
|
38
|
+
this.countCache = null
|
|
31
39
|
this.linkerClass = linkerClass
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -37,11 +45,12 @@ class DoublyLinkedList {
|
|
|
37
45
|
* @return {DoublyLinkedList}
|
|
38
46
|
*/
|
|
39
47
|
initialize (initialList) {
|
|
48
|
+
// Borrowed from LinkedList, which types its return as a LinkedList although it returns whatever list called it
|
|
40
49
|
return _LinkedList.LinkedList.prototype.initialize.call(this, initialList)
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/**
|
|
44
|
-
* Retrieve
|
|
53
|
+
* Retrieve the innerList used (the list itself, not a copy).
|
|
45
54
|
* @returns {DoubleLinker}
|
|
46
55
|
*/
|
|
47
56
|
get list () {
|
|
@@ -53,91 +62,122 @@ class DoublyLinkedList {
|
|
|
53
62
|
* @returns {DoubleLinker}
|
|
54
63
|
*/
|
|
55
64
|
get first () {
|
|
56
|
-
|
|
65
|
+
let head = this.innerList
|
|
66
|
+
if (head === null) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
// innerList is normally the head already, walking back also finds anything linked on before it outside of this list
|
|
70
|
+
while (head.prev !== null) {
|
|
71
|
+
head = head.prev
|
|
72
|
+
}
|
|
73
|
+
this.innerList = head
|
|
74
|
+
return head
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
/**
|
|
60
|
-
* Retrieve the last DoubleLinker in the list.
|
|
78
|
+
* Retrieve the last DoubleLinker in the list. The end is remembered, so this does not walk the list.
|
|
61
79
|
* @returns {DoubleLinker}
|
|
62
80
|
*/
|
|
63
81
|
get last () {
|
|
64
|
-
|
|
65
|
-
if (tail === null) {
|
|
82
|
+
if (this.innerList === null) {
|
|
66
83
|
return null
|
|
67
84
|
}
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
let tail = this.tailCache !== null ? this.tailCache : this.innerList
|
|
86
|
+
// The remembered tail is normally the end already, walking on from it also finds anything linked on outside of this list
|
|
87
|
+
while (tail.next !== null) {
|
|
88
|
+
tail = tail.next
|
|
72
89
|
}
|
|
90
|
+
this.tailCache = tail
|
|
73
91
|
return tail
|
|
74
92
|
}
|
|
75
93
|
|
|
76
94
|
/**
|
|
77
|
-
* Return the length of the list.
|
|
95
|
+
* Return the length of the list. It is kept up to date by the list's own methods, so this does not walk the list
|
|
96
|
+
* (call reset() after linkers were changed directly).
|
|
78
97
|
* @returns {number}
|
|
79
98
|
*/
|
|
80
99
|
get length () {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
while (current !== null) {
|
|
84
|
-
++length
|
|
85
|
-
current = current.next
|
|
100
|
+
if (this.countCache === null) {
|
|
101
|
+
this.reset()
|
|
86
102
|
}
|
|
87
|
-
return
|
|
103
|
+
return this.countCache
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
/**
|
|
91
107
|
* Insert a new node (or data) after a node.
|
|
92
|
-
* @param {DoubleLinker|*} node The existing node as reference
|
|
108
|
+
* @param {DoubleLinker|*} node The existing node as reference (which must be in this list, this is not checked), or null to insert at the start of the list
|
|
93
109
|
* @param {DoubleLinker|*} newNode The new node to go after the existing node
|
|
94
110
|
* @returns {DoublyLinkedList}
|
|
95
111
|
*/
|
|
96
112
|
insertAfter (node, newNode) {
|
|
97
|
-
newNode = this.linkerClass.make(newNode)
|
|
98
|
-
if (node
|
|
113
|
+
newNode = this.linkerClass.make(newNode, this.linkerClass)
|
|
114
|
+
if (node === null || typeof node === 'undefined') {
|
|
115
|
+
// After nothing means at the start of the list
|
|
116
|
+
const head = this.first
|
|
117
|
+
newNode.prev = null
|
|
118
|
+
newNode.next = head
|
|
119
|
+
if (head) {
|
|
120
|
+
head.prev = newNode
|
|
121
|
+
} else {
|
|
122
|
+
this.tailCache = newNode
|
|
123
|
+
}
|
|
124
|
+
this.innerList = newNode
|
|
125
|
+
} else {
|
|
99
126
|
// Ensure the next reference of this node is assigned to the new node
|
|
100
127
|
newNode.next = node.next
|
|
101
128
|
// Ensure this node is assigned as the prev reference of the new node
|
|
102
129
|
newNode.prev = node
|
|
103
130
|
// Then set this node's next reference to the new node
|
|
104
131
|
node.next = newNode
|
|
132
|
+
if (newNode.next) {
|
|
133
|
+
// Update the next reference to ensure circular reference for prev points to the new node
|
|
134
|
+
newNode.next.prev = newNode
|
|
135
|
+
} else {
|
|
136
|
+
this.tailCache = newNode
|
|
137
|
+
}
|
|
105
138
|
}
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
newNode.next.prev = newNode
|
|
139
|
+
if (this.countCache !== null) {
|
|
140
|
+
++this.countCache
|
|
109
141
|
}
|
|
110
|
-
if (!this.length) {
|
|
111
|
-
this.innerList = newNode
|
|
112
|
-
}
|
|
113
|
-
this.reset()
|
|
114
142
|
return this
|
|
115
143
|
}
|
|
116
144
|
|
|
117
145
|
/**
|
|
118
146
|
* Insert a new node (or data) before a node.
|
|
119
|
-
* @param {DoubleLinker|*} node The existing node as reference
|
|
147
|
+
* @param {DoubleLinker|*} node The existing node as reference (which must be in this list, this is not checked), or null to insert at the end of the list
|
|
120
148
|
* @param {DoubleLinker|*} newNode The new node to go before the existing node
|
|
121
149
|
* @returns {DoublyLinkedList}
|
|
122
150
|
*/
|
|
123
151
|
insertBefore (node, newNode) {
|
|
124
|
-
newNode = this.linkerClass.make(newNode)
|
|
125
|
-
if (node
|
|
152
|
+
newNode = this.linkerClass.make(newNode, this.linkerClass)
|
|
153
|
+
if (node === null || typeof node === 'undefined') {
|
|
154
|
+
// Before nothing means at the end of the list
|
|
155
|
+
const tail = this.last
|
|
156
|
+
newNode.next = null
|
|
157
|
+
newNode.prev = tail
|
|
158
|
+
if (tail === null) {
|
|
159
|
+
this.innerList = newNode
|
|
160
|
+
} else {
|
|
161
|
+
tail.next = newNode
|
|
162
|
+
}
|
|
163
|
+
this.tailCache = newNode
|
|
164
|
+
} else {
|
|
126
165
|
// The new node will reference this prev node as prev
|
|
127
166
|
newNode.prev = node.prev
|
|
128
167
|
// The new node will reference this node as next
|
|
129
168
|
newNode.next = node
|
|
130
169
|
// This prev will reference the new node
|
|
131
170
|
node.prev = newNode
|
|
171
|
+
if (newNode.prev) {
|
|
172
|
+
// Update the prev reference to ensure circular reference for next points to the new node
|
|
173
|
+
newNode.prev.next = newNode
|
|
174
|
+
} else {
|
|
175
|
+
this.innerList = newNode
|
|
176
|
+
}
|
|
132
177
|
}
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
newNode.prev.next = newNode
|
|
136
|
-
}
|
|
137
|
-
if (!this.length) {
|
|
138
|
-
this.innerList = newNode
|
|
178
|
+
if (this.countCache !== null) {
|
|
179
|
+
++this.countCache
|
|
139
180
|
}
|
|
140
|
-
this.reset()
|
|
141
181
|
return this
|
|
142
182
|
}
|
|
143
183
|
|
|
@@ -167,7 +207,7 @@ class DoublyLinkedList {
|
|
|
167
207
|
* @return {DoubleLinker}
|
|
168
208
|
*/
|
|
169
209
|
remove (node) {
|
|
170
|
-
if (node === null) {
|
|
210
|
+
if (node === null || typeof node === 'undefined') {
|
|
171
211
|
return null
|
|
172
212
|
}
|
|
173
213
|
if (node.prev) {
|
|
@@ -183,35 +223,47 @@ class DoublyLinkedList {
|
|
|
183
223
|
if (this.innerList === node) {
|
|
184
224
|
this.innerList = node.next || node.prev || null
|
|
185
225
|
}
|
|
186
|
-
|
|
187
|
-
|
|
226
|
+
if (this.tailCache === node) {
|
|
227
|
+
this.tailCache = node.prev
|
|
228
|
+
}
|
|
229
|
+
if (this.innerList === null) {
|
|
230
|
+
this.tailCache = null
|
|
231
|
+
}
|
|
232
|
+
if (this.countCache !== null) {
|
|
233
|
+
--this.countCache
|
|
234
|
+
}
|
|
188
235
|
return node
|
|
189
236
|
}
|
|
190
237
|
|
|
191
238
|
/**
|
|
192
|
-
* Refresh all references and return head
|
|
193
|
-
*
|
|
239
|
+
* Refresh all references (the head, the end and the length) by walking the list once, and return the head. The list's
|
|
240
|
+
* own methods keep these up to date, so this is only needed after linkers were changed directly.
|
|
241
|
+
* @return {DoubleLinker|null}
|
|
194
242
|
*/
|
|
195
243
|
reset () {
|
|
196
244
|
// Start at the pointer for the list
|
|
197
245
|
let pointer = this.innerList
|
|
198
246
|
if (pointer === null) {
|
|
247
|
+
this.countCache = 0
|
|
248
|
+
this.tailCache = null
|
|
199
249
|
return null
|
|
200
250
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
pointer = next
|
|
205
|
-
next = pointer.next
|
|
206
|
-
}
|
|
207
|
-
let prev = pointer.prev
|
|
208
|
-
// From final reference, follow references back to the beginning
|
|
209
|
-
while (prev !== null) {
|
|
210
|
-
pointer = prev
|
|
211
|
-
prev = pointer.prev
|
|
251
|
+
// Follow references back to the beginning
|
|
252
|
+
while (pointer.prev !== null) {
|
|
253
|
+
pointer = pointer.prev
|
|
212
254
|
}
|
|
213
|
-
//
|
|
255
|
+
// We are pointing to the true head, now count along to the end to find the tail and the length
|
|
214
256
|
this.innerList = pointer
|
|
257
|
+
let count = 0
|
|
258
|
+
let tail = pointer
|
|
259
|
+
let current = pointer
|
|
260
|
+
while (current !== null) {
|
|
261
|
+
++count
|
|
262
|
+
tail = current
|
|
263
|
+
current = current.next
|
|
264
|
+
}
|
|
265
|
+
this.countCache = count
|
|
266
|
+
this.tailCache = tail
|
|
215
267
|
return pointer
|
|
216
268
|
}
|
|
217
269
|
|
|
@@ -247,6 +299,7 @@ class DoublyLinkedList {
|
|
|
247
299
|
* Be able to run forEach on this DoublyLinkedList to iterate over the DoubleLinker Items.
|
|
248
300
|
* @param {forEachCallback} callback The function to call for-each double linker
|
|
249
301
|
* @param {DoublyLinkedList} thisArg Optional, 'this' reference
|
|
302
|
+
* @return {DoublyLinkedList} The list which was iterated.
|
|
250
303
|
*/
|
|
251
304
|
forEach (callback, thisArg = this) {
|
|
252
305
|
return _LinkedList.LinkedList.prototype.forEach.call(this, callback, thisArg)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DoublyLinkedList=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.for-each.js");var _DoubleLinker=require("./DoubleLinker"),_DoubleLinkerIterator=require("../../recipes/DoubleLinkerIterator"),_LinkedList=require("../linked-list/LinkedList");class DoublyLinkedList{constructor(e=_DoubleLinker.DoubleLinker){this.classType=DoublyLinkedList,this.innerList=null,this.initialized=!1,this.linkerClass=e}initialize(e){return _LinkedList.LinkedList.prototype.initialize.call(this,e)}get list(){return this.innerList}get first(){
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DoublyLinkedList=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.for-each.js");var _DoubleLinker=require("./DoubleLinker"),_DoubleLinkerIterator=require("../../recipes/DoubleLinkerIterator"),_LinkedList=require("../linked-list/LinkedList");class DoublyLinkedList{constructor(e=_DoubleLinker.DoubleLinker){this.classType=DoublyLinkedList,this.innerList=null,this.initialized=!1,this.tailCache=null,this.countCache=null,this.linkerClass=e}initialize(e){return _LinkedList.LinkedList.prototype.initialize.call(this,e)}get list(){return this.innerList}get first(){let e=this.innerList;if(null===e)return null;for(;null!==e.prev;)e=e.prev;return this.innerList=e,e}get last(){if(null===this.innerList)return null;let e=null!==this.tailCache?this.tailCache:this.innerList;for(;null!==e.next;)e=e.next;return this.tailCache=e,e}get length(){return null===this.countCache&&this.reset(),this.countCache}insertAfter(e,t){if(t=this.linkerClass.make(t,this.linkerClass),null==e){const e=this.first;t.prev=null,t.next=e,e?e.prev=t:this.tailCache=t,this.innerList=t}else t.next=e.next,t.prev=e,e.next=t,t.next?t.next.prev=t:this.tailCache=t;return null!==this.countCache&&++this.countCache,this}insertBefore(e,t){if(t=this.linkerClass.make(t,this.linkerClass),null==e){const e=this.last;t.next=null,t.prev=e,null===e?this.innerList=t:e.next=t,this.tailCache=t}else t.prev=e.prev,t.next=e,e.prev=t,t.prev?t.prev.next=t:this.innerList=t;return null!==this.countCache&&++this.countCache,this}append(e,t=this.last){return this.insertAfter(t,e)}prepend(e,t=this.first){return this.insertBefore(t,e)}remove(e){return null==e?null:(e.prev&&(e.prev.next=e.next),e.next&&(e.next.prev=e.prev),this.innerList===e&&(this.innerList=e.next||e.prev||null),this.tailCache===e&&(this.tailCache=e.prev),null===this.innerList&&(this.tailCache=null),null!==this.countCache&&--this.countCache,e)}reset(){let e=this.innerList;if(null===e)return this.countCache=0,this.tailCache=null,null;for(;null!==e.prev;)e=e.prev;this.innerList=e;let t=0,i=e,n=e;for(;null!==n;)++t,i=n,n=n.next;return this.countCache=t,this.tailCache=i,e}item(e){if(e>=0){let t=this.first,i=-1;for(;++i<e&&null!==t;)t=t.next;return i===e?t:null}let t=this.last,i=this.length;const n=this.length+e;if(n<0)return null;for(;--i>n&&null!==t;)t=t.prev;return i===n?t:null}forEach(e,t=this){return _LinkedList.LinkedList.prototype.forEach.call(this,e,t)}[Symbol.iterator](){let e=this.first;return new _DoubleLinkerIterator.DoubleLinkerIterator(e)}}exports.DoublyLinkedList=DoublyLinkedList,DoublyLinkedList.fromArray=(e=[],t=_DoubleLinker.DoubleLinker,i=DoublyLinkedList)=>_LinkedList.LinkedList.fromArray(e,t,i);
|
|
@@ -12,12 +12,21 @@ import { Linker } from './Linker';
|
|
|
12
12
|
* @extends Arrayable
|
|
13
13
|
*/
|
|
14
14
|
export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker> {
|
|
15
|
+
/** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
|
|
15
16
|
readonly classType: typeof LinkedList;
|
|
17
|
+
/** The first linker of the list (null when the list is empty), from which the whole list is reached. */
|
|
16
18
|
innerList: Linker;
|
|
19
|
+
/** Whether the inner list has been initialized (it can only be initialized once). */
|
|
17
20
|
initialized: boolean;
|
|
21
|
+
/** The class used to wrap the data given to this list as linkers. */
|
|
18
22
|
linkerClass: typeof Linker;
|
|
23
|
+
/** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
|
|
24
|
+
private tailCache;
|
|
25
|
+
/** The number of linkers, kept up to date by the list's own methods so that the length does not need to walk the whole list (null when not known yet). */
|
|
26
|
+
private countCache;
|
|
19
27
|
/**
|
|
20
28
|
* Create the new LinkedList instance.
|
|
29
|
+
* @param {Linker} [linkerClass=Linker] The class used to wrap given data as linkers.
|
|
21
30
|
*/
|
|
22
31
|
constructor(linkerClass?: typeof Linker);
|
|
23
32
|
/**
|
|
@@ -27,7 +36,7 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
|
|
|
27
36
|
*/
|
|
28
37
|
initialize(initialList: Linker): LinkedList;
|
|
29
38
|
/**
|
|
30
|
-
* Retrieve
|
|
39
|
+
* Retrieve the innerList used (the list itself, not a copy).
|
|
31
40
|
* @returns {Linker}
|
|
32
41
|
*/
|
|
33
42
|
get list(): IsLinker;
|
|
@@ -37,29 +46,31 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
|
|
|
37
46
|
*/
|
|
38
47
|
get first(): Linker;
|
|
39
48
|
/**
|
|
40
|
-
* Retrieve the last Linker in the list.
|
|
49
|
+
* Retrieve the last Linker in the list. The end is remembered, so this does not walk the list.
|
|
41
50
|
* @returns {Linker}
|
|
42
51
|
*/
|
|
43
|
-
get last(): Linker;
|
|
52
|
+
get last(): Linker | null;
|
|
44
53
|
/**
|
|
45
|
-
* Return the length of the list.
|
|
54
|
+
* Return the length of the list. It is kept up to date by the list's own methods, so this does not walk the list
|
|
55
|
+
* (call reset() after linkers were changed directly).
|
|
46
56
|
* @returns {number}
|
|
47
57
|
*/
|
|
48
58
|
get length(): number;
|
|
49
59
|
/**
|
|
50
60
|
* Insert a new node (or data) after a node.
|
|
51
|
-
* @param {Linker|*} node The existing node as reference
|
|
61
|
+
* @param {Linker|*} node The existing node as reference, or null to insert at the start of the list
|
|
52
62
|
* @param {Linker|*} newNode The new node to go after the existing node
|
|
53
63
|
* @returns {LinkedList}
|
|
54
64
|
*/
|
|
55
|
-
insertAfter(node: IsLinker, newNode: Linker | any): LinkedList;
|
|
65
|
+
insertAfter(node: IsLinker | null, newNode: Linker | any): LinkedList;
|
|
56
66
|
/**
|
|
57
67
|
* Insert a new node (or data) before a node.
|
|
58
|
-
* @param {Linker|*} node The existing node as reference
|
|
68
|
+
* @param {Linker|*} node The existing node as reference, or null to insert at the end of the list
|
|
59
69
|
* @param {Linker|*} newNode The new node to go before the existing node
|
|
60
70
|
* @returns {LinkedList}
|
|
71
|
+
* @throws {Error} When the reference node is not in this list
|
|
61
72
|
*/
|
|
62
|
-
insertBefore(node: IsLinker, newNode: Linker | any): LinkedList;
|
|
73
|
+
insertBefore(node: IsLinker | null, newNode: Linker | any): LinkedList;
|
|
63
74
|
/**
|
|
64
75
|
* Add a node (or data) after the given (or last) node in the list.
|
|
65
76
|
* @param {Linker|*} node The new node to add to the end of the list
|
|
@@ -77,9 +88,15 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
|
|
|
77
88
|
/**
|
|
78
89
|
* Remove a linker from this linked list.
|
|
79
90
|
* @param {Linker} node The node we wish to remove (and it will be returned after removal)
|
|
80
|
-
* @return {Linker}
|
|
91
|
+
* @return {Linker|null} The removed node, or null when it was not in this list (nothing is removed)
|
|
81
92
|
*/
|
|
82
|
-
remove(node: Linker): Linker;
|
|
93
|
+
remove(node: Linker | null): Linker | null;
|
|
94
|
+
/**
|
|
95
|
+
* Refresh the remembered end and length of the list by walking it once. The list's own methods keep these up to date,
|
|
96
|
+
* so this is only needed after linkers were changed directly (for example by setting next on a linker).
|
|
97
|
+
* @return {Linker|null} The first linker of the list
|
|
98
|
+
*/
|
|
99
|
+
reset(): Linker | null;
|
|
83
100
|
/**
|
|
84
101
|
* Retrieve a Linker item from this list by numeric index, otherwise return null.
|
|
85
102
|
* @param {number} index The integer number for retrieving a node by position.
|
|
@@ -14,11 +14,19 @@ var _Arrayable = require('../arrayable/Arrayable')
|
|
|
14
14
|
class LinkedList {
|
|
15
15
|
/**
|
|
16
16
|
* Create the new LinkedList instance.
|
|
17
|
+
* @param {Linker} [linkerClass=Linker] The class used to wrap given data as linkers.
|
|
17
18
|
*/
|
|
18
19
|
constructor (linkerClass = _Linker.Linker) {
|
|
20
|
+
/** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
|
|
19
21
|
this.classType = LinkedList
|
|
22
|
+
/** The first linker of the list (null when the list is empty), from which the whole list is reached. */
|
|
20
23
|
this.innerList = null
|
|
24
|
+
/** Whether the inner list has been initialized (it can only be initialized once). */
|
|
21
25
|
this.initialized = false
|
|
26
|
+
/** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
|
|
27
|
+
this.tailCache = null
|
|
28
|
+
/** The number of linkers, kept up to date by the list's own methods so that the length does not need to walk the whole list (null when not known yet). */
|
|
29
|
+
this.countCache = null
|
|
22
30
|
this.linkerClass = linkerClass
|
|
23
31
|
}
|
|
24
32
|
|
|
@@ -28,11 +36,12 @@ class LinkedList {
|
|
|
28
36
|
* @return {LinkedList}
|
|
29
37
|
*/
|
|
30
38
|
initialize (initialList) {
|
|
39
|
+
// Borrowed from Arrayable, which types its return as an Arrayable although it returns whatever list called it
|
|
31
40
|
return _Arrayable.Arrayable.prototype.initialize.call(this, initialList)
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
/**
|
|
35
|
-
* Retrieve
|
|
44
|
+
* Retrieve the innerList used (the list itself, not a copy).
|
|
36
45
|
* @returns {Linker}
|
|
37
46
|
*/
|
|
38
47
|
get list () {
|
|
@@ -48,78 +57,100 @@ class LinkedList {
|
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
/**
|
|
51
|
-
* Retrieve the last Linker in the list.
|
|
60
|
+
* Retrieve the last Linker in the list. The end is remembered, so this does not walk the list.
|
|
52
61
|
* @returns {Linker}
|
|
53
62
|
*/
|
|
54
63
|
get last () {
|
|
55
|
-
|
|
56
|
-
if (tail === null) {
|
|
64
|
+
if (this.innerList === null) {
|
|
57
65
|
return null
|
|
58
66
|
}
|
|
59
|
-
let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
let tail = this.tailCache !== null ? this.tailCache : this.innerList
|
|
68
|
+
// The remembered tail is normally the end already, walking on from it also finds anything linked on outside of this list
|
|
69
|
+
while (tail.next !== null) {
|
|
70
|
+
tail = tail.next
|
|
63
71
|
}
|
|
72
|
+
this.tailCache = tail
|
|
64
73
|
return tail
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
/**
|
|
68
|
-
* Return the length of the list.
|
|
77
|
+
* Return the length of the list. It is kept up to date by the list's own methods, so this does not walk the list
|
|
78
|
+
* (call reset() after linkers were changed directly).
|
|
69
79
|
* @returns {number}
|
|
70
80
|
*/
|
|
71
81
|
get length () {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
while (current !== null) {
|
|
75
|
-
++length
|
|
76
|
-
current = current.next
|
|
82
|
+
if (this.countCache === null) {
|
|
83
|
+
this.reset()
|
|
77
84
|
}
|
|
78
|
-
return
|
|
85
|
+
return this.countCache
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
/**
|
|
82
89
|
* Insert a new node (or data) after a node.
|
|
83
|
-
* @param {Linker|*} node The existing node as reference
|
|
90
|
+
* @param {Linker|*} node The existing node as reference, or null to insert at the start of the list
|
|
84
91
|
* @param {Linker|*} newNode The new node to go after the existing node
|
|
85
92
|
* @returns {LinkedList}
|
|
86
93
|
*/
|
|
87
94
|
insertAfter (node, newNode) {
|
|
88
|
-
newNode = this.linkerClass.make(newNode)
|
|
89
|
-
if (node
|
|
90
|
-
//
|
|
95
|
+
newNode = this.linkerClass.make(newNode, this.linkerClass)
|
|
96
|
+
if (node === null || typeof node === 'undefined') {
|
|
97
|
+
// After nothing means at the start of the list
|
|
98
|
+
newNode.next = this.innerList
|
|
99
|
+
if (this.innerList === null) {
|
|
100
|
+
this.tailCache = newNode
|
|
101
|
+
}
|
|
102
|
+
this.innerList = newNode
|
|
103
|
+
} else {
|
|
91
104
|
newNode.next = node.next
|
|
92
|
-
// Then set this node's next reference to the new node
|
|
93
105
|
node.next = newNode
|
|
106
|
+
if (newNode.next === null) {
|
|
107
|
+
this.tailCache = newNode
|
|
108
|
+
}
|
|
94
109
|
}
|
|
95
|
-
if (
|
|
96
|
-
this.
|
|
110
|
+
if (this.countCache !== null) {
|
|
111
|
+
++this.countCache
|
|
97
112
|
}
|
|
98
113
|
return this
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
/**
|
|
102
117
|
* Insert a new node (or data) before a node.
|
|
103
|
-
* @param {Linker|*} node The existing node as reference
|
|
118
|
+
* @param {Linker|*} node The existing node as reference, or null to insert at the end of the list
|
|
104
119
|
* @param {Linker|*} newNode The new node to go before the existing node
|
|
105
120
|
* @returns {LinkedList}
|
|
121
|
+
* @throws {Error} When the reference node is not in this list
|
|
106
122
|
*/
|
|
107
123
|
insertBefore (node, newNode) {
|
|
108
|
-
newNode = this.linkerClass.make(newNode)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
newNode = this.linkerClass.make(newNode, this.linkerClass)
|
|
125
|
+
if (node === null || typeof node === 'undefined') {
|
|
126
|
+
// Before nothing means at the end of the list
|
|
127
|
+
const tail = this.last
|
|
128
|
+
newNode.next = null
|
|
129
|
+
if (tail === null) {
|
|
130
|
+
this.innerList = newNode
|
|
131
|
+
} else {
|
|
132
|
+
tail.next = newNode
|
|
133
|
+
}
|
|
134
|
+
this.tailCache = newNode
|
|
135
|
+
} else {
|
|
136
|
+
let prevNode = null
|
|
137
|
+
let currentNode = this.first
|
|
138
|
+
while (currentNode !== null && currentNode !== node) {
|
|
139
|
+
prevNode = currentNode
|
|
140
|
+
currentNode = currentNode.next
|
|
141
|
+
}
|
|
142
|
+
if (currentNode === null) {
|
|
143
|
+
throw new Error('The reference node is not in this list.')
|
|
144
|
+
}
|
|
145
|
+
newNode.next = node
|
|
146
|
+
if (prevNode) {
|
|
147
|
+
prevNode.next = newNode
|
|
148
|
+
} else {
|
|
149
|
+
this.innerList = newNode
|
|
150
|
+
}
|
|
120
151
|
}
|
|
121
|
-
if (
|
|
122
|
-
this.
|
|
152
|
+
if (this.countCache !== null) {
|
|
153
|
+
++this.countCache
|
|
123
154
|
}
|
|
124
155
|
return this
|
|
125
156
|
}
|
|
@@ -147,26 +178,58 @@ class LinkedList {
|
|
|
147
178
|
/**
|
|
148
179
|
* Remove a linker from this linked list.
|
|
149
180
|
* @param {Linker} node The node we wish to remove (and it will be returned after removal)
|
|
150
|
-
* @return {Linker}
|
|
181
|
+
* @return {Linker|null} The removed node, or null when it was not in this list (nothing is removed)
|
|
151
182
|
*/
|
|
152
183
|
remove (node) {
|
|
184
|
+
if (node === null || typeof node === 'undefined') {
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
153
187
|
let prevNode = null
|
|
154
188
|
let currentNode = this.first
|
|
155
|
-
while (currentNode !== node) {
|
|
189
|
+
while (currentNode !== null && currentNode !== node) {
|
|
156
190
|
prevNode = currentNode
|
|
157
191
|
currentNode = currentNode.next
|
|
158
192
|
}
|
|
193
|
+
if (currentNode === null) {
|
|
194
|
+
// The node is not in this list, so there is nothing to remove
|
|
195
|
+
return null
|
|
196
|
+
}
|
|
159
197
|
if (prevNode) {
|
|
160
|
-
// Ensure the next reference of the previous node skips over the removed node
|
|
161
198
|
prevNode.next = node.next
|
|
162
|
-
}
|
|
163
|
-
if (node === this.first && node !== null) {
|
|
164
|
-
// Update list head to point to next if it was this node
|
|
199
|
+
} else {
|
|
165
200
|
this.innerList = node.next
|
|
166
201
|
}
|
|
202
|
+
if (this.tailCache === node) {
|
|
203
|
+
this.tailCache = prevNode
|
|
204
|
+
}
|
|
205
|
+
if (this.innerList === null) {
|
|
206
|
+
this.tailCache = null
|
|
207
|
+
}
|
|
208
|
+
if (this.countCache !== null) {
|
|
209
|
+
--this.countCache
|
|
210
|
+
}
|
|
167
211
|
return node
|
|
168
212
|
}
|
|
169
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Refresh the remembered end and length of the list by walking it once. The list's own methods keep these up to date,
|
|
216
|
+
* so this is only needed after linkers were changed directly (for example by setting next on a linker).
|
|
217
|
+
* @return {Linker|null} The first linker of the list
|
|
218
|
+
*/
|
|
219
|
+
reset () {
|
|
220
|
+
let count = 0
|
|
221
|
+
let tail = null
|
|
222
|
+
let current = this.innerList
|
|
223
|
+
while (current !== null) {
|
|
224
|
+
++count
|
|
225
|
+
tail = current
|
|
226
|
+
current = current.next
|
|
227
|
+
}
|
|
228
|
+
this.countCache = count
|
|
229
|
+
this.tailCache = tail
|
|
230
|
+
return this.innerList
|
|
231
|
+
}
|
|
232
|
+
|
|
170
233
|
/**
|
|
171
234
|
* Retrieve a Linker item from this list by numeric index, otherwise return null.
|
|
172
235
|
* @param {number} index The integer number for retrieving a node by position.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LinkedList=void 0;var _Linker=require("./Linker"),_LinkerIterator=require("../../recipes/LinkerIterator"),_Arrayable=require("../arrayable/Arrayable");class LinkedList{constructor(t=_Linker.Linker){this.classType=LinkedList,this.innerList=null,this.initialized=!1,this.linkerClass=t}initialize(t){return _Arrayable.Arrayable.prototype.initialize.call(this,t)}get list(){return this.innerList}get first(){return this.innerList}get last(){
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LinkedList=void 0;var _Linker=require("./Linker"),_LinkerIterator=require("../../recipes/LinkerIterator"),_Arrayable=require("../arrayable/Arrayable");class LinkedList{constructor(t=_Linker.Linker){this.classType=LinkedList,this.innerList=null,this.initialized=!1,this.tailCache=null,this.countCache=null,this.linkerClass=t}initialize(t){return _Arrayable.Arrayable.prototype.initialize.call(this,t)}get list(){return this.innerList}get first(){return this.innerList}get last(){if(null===this.innerList)return null;let t=null!==this.tailCache?this.tailCache:this.innerList;for(;null!==t.next;)t=t.next;return this.tailCache=t,t}get length(){return null===this.countCache&&this.reset(),this.countCache}insertAfter(t,e){return e=this.linkerClass.make(e,this.linkerClass),null==t?(e.next=this.innerList,null===this.innerList&&(this.tailCache=e),this.innerList=e):(e.next=t.next,t.next=e,null===e.next&&(this.tailCache=e)),null!==this.countCache&&++this.countCache,this}insertBefore(t,e){if(e=this.linkerClass.make(e,this.linkerClass),null==t){const t=this.last;e.next=null,null===t?this.innerList=e:t.next=e,this.tailCache=e}else{let i=null,n=this.first;for(;null!==n&&n!==t;)i=n,n=n.next;if(null===n)throw new Error("The reference node is not in this list.");e.next=t,i?i.next=e:this.innerList=e}return null!==this.countCache&&++this.countCache,this}append(t,e=this.last){return this.insertAfter(e,t)}prepend(t,e=this.first){return this.insertBefore(e,t)}remove(t){if(null==t)return null;let e=null,i=this.first;for(;null!==i&&i!==t;)e=i,i=i.next;return null===i?null:(e?e.next=t.next:this.innerList=t.next,this.tailCache===t&&(this.tailCache=e),null===this.innerList&&(this.tailCache=null),null!==this.countCache&&--this.countCache,t)}reset(){let t=0,e=null,i=this.innerList;for(;null!==i;)++t,e=i,i=i.next;return this.countCache=t,this.tailCache=e,this.innerList}item(t){if(t>=0){let e=this.first,i=-1;for(;++i<t&&null!==e;)e=e.next;return i===t?e:null}let e=this.first,i=0;const n=this.length+t;if(n<0)return null;for(;i<n&&null!==e;)e=e.next,++i;return i===n?e:null}forEach(t,e=this){let i=0,n=e.first;for(;null!==n;)t(n,i,e),n=n.next,++i;return e}[Symbol.iterator](){return new _LinkerIterator.LinkerIterator(this.first)}}exports.LinkedList=LinkedList,LinkedList.fromArray=(t=[],e=_Linker.Linker,i=LinkedList)=>new i(e).initialize(e.fromArray(t).head);
|
|
@@ -10,12 +10,15 @@ import { IsLinker } from '../../recipes/IsLinker';
|
|
|
10
10
|
* @extends ArrayElement
|
|
11
11
|
*/
|
|
12
12
|
export declare class Linker implements IsLinker {
|
|
13
|
+
/** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
|
|
13
14
|
readonly classType: typeof Linker;
|
|
15
|
+
/** The data stored in this linker. */
|
|
14
16
|
data: any;
|
|
17
|
+
/** The linker after this one, or null when this is the last. */
|
|
15
18
|
next: Linker | null;
|
|
16
19
|
/**
|
|
17
20
|
* Create the new Linker instance, provide the data and optionally give the next Linker.
|
|
18
|
-
* @param {Object} [nodeData={}]
|
|
21
|
+
* @param {Object} [nodeData={}] The settings for the new linker.
|
|
19
22
|
* @param {*} [nodeData.data=null] The data to be stored in this linker
|
|
20
23
|
* @param {Linker|null} [nodeData.next=null] The reference to the next linker if any
|
|
21
24
|
*/
|
|
@@ -36,7 +39,7 @@ export declare class Linker implements IsLinker {
|
|
|
36
39
|
* @param {IsLinker} [classType=Linker] Provide the type of IsLinker to use.
|
|
37
40
|
* @returns {{head: Linker, tail: Linker}}
|
|
38
41
|
*/
|
|
39
|
-
static fromArray: (values
|
|
42
|
+
static fromArray: (values?: Array<any>, classType?: any) => {
|
|
40
43
|
head: IsLinker;
|
|
41
44
|
tail: IsLinker;
|
|
42
45
|
};
|