collect-your-stuff 1.3.2 → 2.0.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.
Files changed (34) hide show
  1. package/dist/collections/arrayable/Arrayable.d.ts +2 -2
  2. package/dist/collections/arrayable/Arrayable.js +10 -0
  3. package/dist/collections/arrayable/Arrayable.min.js +1 -1
  4. package/dist/collections/doubly-linked-list/DoublyLinkedList.d.ts +14 -8
  5. package/dist/collections/doubly-linked-list/DoublyLinkedList.js +91 -56
  6. package/dist/collections/doubly-linked-list/DoublyLinkedList.min.js +1 -1
  7. package/dist/collections/linked-list/LinkedList.d.ts +14 -3
  8. package/dist/collections/linked-list/LinkedList.js +76 -32
  9. package/dist/collections/linked-list/LinkedList.min.js +1 -1
  10. package/dist/collections/linked-tree-list/LinkedTreeList.d.ts +9 -3
  11. package/dist/collections/linked-tree-list/LinkedTreeList.js +19 -21
  12. package/dist/collections/linked-tree-list/LinkedTreeList.min.js +1 -1
  13. package/dist/collections/queue/Queue.d.ts +35 -42
  14. package/dist/collections/queue/Queue.js +64 -80
  15. package/dist/collections/queue/Queue.min.js +1 -1
  16. package/dist/collections/queue/TaskQueue.d.ts +68 -0
  17. package/dist/collections/queue/TaskQueue.js +137 -0
  18. package/dist/collections/queue/TaskQueue.min.js +1 -0
  19. package/dist/collections/stack/Stack.d.ts +40 -40
  20. package/dist/collections/stack/Stack.js +73 -52
  21. package/dist/collections/stack/Stack.min.js +1 -1
  22. package/dist/collections/stack/TaskStack.d.ts +65 -0
  23. package/dist/collections/stack/TaskStack.js +107 -0
  24. package/dist/collections/stack/TaskStack.min.js +1 -0
  25. package/dist/main.d.ts +7 -1
  26. package/dist/main.js +16 -0
  27. package/dist/main.min.js +1 -1
  28. package/dist/recipes/IsQueue.d.ts +37 -0
  29. package/dist/recipes/IsQueue.js +5 -0
  30. package/dist/recipes/IsQueue.min.js +1 -0
  31. package/dist/recipes/IsStack.d.ts +36 -0
  32. package/dist/recipes/IsStack.js +5 -0
  33. package/dist/recipes/IsStack.min.js +1 -0
  34. package/package.json +1 -1
@@ -79,14 +79,14 @@ export declare class Arrayable implements IsArrayable<ArrayElement>, Iterable<Ar
79
79
  * @param {ArrayElement} after The existing last node
80
80
  * @returns {Arrayable}
81
81
  */
82
- append(node: ArrayElement | any, after?: ArrayElement): Arrayable;
82
+ append(node: ArrayElement | any, after?: ArrayElement | null): Arrayable;
83
83
  /**
84
84
  * Add a node (or data) before the given (or first) node in the list.
85
85
  * @param {ArrayElement|*} node The new node to add to the start of the list
86
86
  * @param {ArrayElement} before The existing first node
87
87
  * @returns {Arrayable}
88
88
  */
89
- prepend(node: ArrayElement | any, before?: ArrayElement): Arrayable;
89
+ prepend(node: ArrayElement | any, before?: ArrayElement | null): Arrayable;
90
90
  /**
91
91
  * Remove an element from this arrayable.
92
92
  * @param {ArrayElement} node The node we wish to remove (and it will be returned after removal)
@@ -127,6 +127,11 @@ class Arrayable {
127
127
  * @returns {Arrayable}
128
128
  */
129
129
  append (node, after = this.last) {
130
+ if (after === this.last) {
131
+ // Adding to the end does not need to search for where that is
132
+ this.innerList.push(this.elementClass.make(node, this.elementClass))
133
+ return this
134
+ }
130
135
  return this.insertAfter(after, node)
131
136
  }
132
137
 
@@ -137,6 +142,11 @@ class Arrayable {
137
142
  * @returns {Arrayable}
138
143
  */
139
144
  prepend (node, before = this.first) {
145
+ if (before === this.first) {
146
+ // Adding to the start does not need to search for where that is
147
+ this.innerList.unshift(this.elementClass.make(node, this.elementClass))
148
+ return this
149
+ }
140
150
  return this.insertBefore(before, node)
141
151
  }
142
152
 
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Arrayable=void 0;var _ArrayElement=require("./ArrayElement"),_ArrayIterator=require("../../recipes/ArrayIterator");class Arrayable{constructor(e=_ArrayElement.ArrayElement){this.classType=Arrayable,this.innerList=[],this.initialized=!1,this.elementClass=e}indexOfElement(e){const t=this.innerList.indexOf(e);if(t<0)throw new Error("The reference element is not in this list.");return t}initialize(e){return this.initialized?(console.warn("Attempt to initialize non-empty list."),this):(this.initialized=!0,this.innerList=e,this)}get list(){return this.innerList}get first(){return this.length?this.innerList[0]:null}get last(){return this.length?this.innerList[this.length-1]:null}get length(){return this.innerList.length}insertAfter(e,t){const r=null==e?-1:this.indexOfElement(e);return this.innerList.splice(r+1,0,this.elementClass.make(t,this.elementClass)),this}insertBefore(e,t){const r=null==e?this.length:this.indexOfElement(e);return this.innerList.splice(r,0,this.elementClass.make(t,this.elementClass)),this}append(e,t=this.last){return this.insertAfter(t,e)}prepend(e,t=this.first){return this.insertBefore(t,e)}remove(e){const t=this.innerList.indexOf(e);return t<0?null:(this.innerList.splice(t,1),e)}item(e){if(e>=this.length)return null;if(e>=0)return this.innerList[e];const t=this.length+e;return t<0?null:this.innerList[t]}forEach(e,t=this){for(let r=0;r<t.length;++r)e(t.item(r),r,t);return t}[Symbol.iterator](){return new _ArrayIterator.ArrayIterator(this.innerList,0)}}exports.Arrayable=Arrayable,Arrayable.fromArray=(e=[],t=_ArrayElement.ArrayElement,r=Arrayable)=>new r(t).initialize(t.fromArray(e).head);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Arrayable=void 0;var _ArrayElement=require("./ArrayElement"),_ArrayIterator=require("../../recipes/ArrayIterator");class Arrayable{constructor(e=_ArrayElement.ArrayElement){this.classType=Arrayable,this.innerList=[],this.initialized=!1,this.elementClass=e}indexOfElement(e){const t=this.innerList.indexOf(e);if(t<0)throw new Error("The reference element is not in this list.");return t}initialize(e){return this.initialized?(console.warn("Attempt to initialize non-empty list."),this):(this.initialized=!0,this.innerList=e,this)}get list(){return this.innerList}get first(){return this.length?this.innerList[0]:null}get last(){return this.length?this.innerList[this.length-1]:null}get length(){return this.innerList.length}insertAfter(e,t){const i=null==e?-1:this.indexOfElement(e);return this.innerList.splice(i+1,0,this.elementClass.make(t,this.elementClass)),this}insertBefore(e,t){const i=null==e?this.length:this.indexOfElement(e);return this.innerList.splice(i,0,this.elementClass.make(t,this.elementClass)),this}append(e,t=this.last){return t===this.last?(this.innerList.push(this.elementClass.make(e,this.elementClass)),this):this.insertAfter(t,e)}prepend(e,t=this.first){return t===this.first?(this.innerList.unshift(this.elementClass.make(e,this.elementClass)),this):this.insertBefore(t,e)}remove(e){const t=this.innerList.indexOf(e);return t<0?null:(this.innerList.splice(t,1),e)}item(e){if(e>=this.length)return null;if(e>=0)return this.innerList[e];const t=this.length+e;return t<0?null:this.innerList[t]}forEach(e,t=this){for(let i=0;i<t.length;++i)e(t.item(i),i,t);return t}[Symbol.iterator](){return new _ArrayIterator.ArrayIterator(this.innerList,0)}}exports.Arrayable=Arrayable,Arrayable.fromArray=(e=[],t=_ArrayElement.ArrayElement,i=Arrayable)=>new i(t).initialize(t.fromArray(e).head);
@@ -20,6 +20,10 @@ export declare class DoublyLinkedList implements IsArrayable<DoubleLinker>, Iter
20
20
  initialized: boolean;
21
21
  /** The class used to wrap the data given to this list as linkers. */
22
22
  linkerClass: typeof DoubleLinker;
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;
23
27
  /**
24
28
  * Create the new DoublyLinkedList instance.
25
29
  * @param {DoubleLinker} [linkerClass=DoubleLinker] The class used to wrap given data as linkers.
@@ -40,14 +44,15 @@ export declare class DoublyLinkedList implements IsArrayable<DoubleLinker>, Iter
40
44
  * Retrieve the first DoubleLinker in the list.
41
45
  * @returns {DoubleLinker}
42
46
  */
43
- get first(): DoubleLinker;
47
+ get first(): DoubleLinker | null;
44
48
  /**
45
- * Retrieve the last DoubleLinker in the list.
49
+ * Retrieve the last DoubleLinker in the list. The end is remembered, so this does not walk the list.
46
50
  * @returns {DoubleLinker}
47
51
  */
48
- get last(): DoubleLinker;
52
+ get last(): DoubleLinker | null;
49
53
  /**
50
- * 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).
51
56
  * @returns {number}
52
57
  */
53
58
  get length(): number;
@@ -84,12 +89,13 @@ export declare class DoublyLinkedList implements IsArrayable<DoubleLinker>, Iter
84
89
  * @param {DoubleLinker} node The node we wish to remove (and it will be returned after removal)
85
90
  * @return {DoubleLinker}
86
91
  */
87
- remove(node: DoubleLinker): DoubleLinker;
92
+ remove(node: DoubleLinker | null): DoubleLinker | null;
88
93
  /**
89
- * Refresh all references and return head reference.
90
- * @return {DoubleLinker}
94
+ * Refresh all references (the head, the end and the length) by walking the list once, and return the head. The list's
95
+ * own methods keep these up to date, so this is only needed after linkers were changed directly.
96
+ * @return {DoubleLinker|null}
91
97
  */
92
- reset(): DoubleLinker;
98
+ reset(): DoubleLinker | null;
93
99
  /**
94
100
  * Retrieve a DoubleLinker item from this list by numeric index, otherwise return null.
95
101
  * @param {number} index The integer number for retrieving a node by position.
@@ -32,6 +32,10 @@ class DoublyLinkedList {
32
32
  this.innerList = null
33
33
  /** Whether the inner list has been initialized (it can only be initialized once). */
34
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
35
39
  this.linkerClass = linkerClass
36
40
  }
37
41
 
@@ -58,38 +62,45 @@ class DoublyLinkedList {
58
62
  * @returns {DoubleLinker}
59
63
  */
60
64
  get first () {
61
- return this.reset()
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
62
75
  }
63
76
 
64
77
  /**
65
- * 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.
66
79
  * @returns {DoubleLinker}
67
80
  */
68
81
  get last () {
69
- let tail = this.innerList
70
- if (tail === null) {
82
+ if (this.innerList === null) {
71
83
  return null
72
84
  }
73
- let next = tail.next
74
- while (next !== null) {
75
- tail = next
76
- next = tail.next
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
77
89
  }
90
+ this.tailCache = tail
78
91
  return tail
79
92
  }
80
93
 
81
94
  /**
82
- * 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).
83
97
  * @returns {number}
84
98
  */
85
99
  get length () {
86
- let current = this.first
87
- let length = 0
88
- while (current !== null) {
89
- ++length
90
- current = current.next
100
+ if (this.countCache === null) {
101
+ this.reset()
91
102
  }
92
- return length
103
+ return this.countCache
93
104
  }
94
105
 
95
106
  /**
@@ -103,24 +114,31 @@ class DoublyLinkedList {
103
114
  if (node === null || typeof node === 'undefined') {
104
115
  // After nothing means at the start of the list
105
116
  const head = this.first
117
+ newNode.prev = null
106
118
  newNode.next = head
107
119
  if (head) {
108
120
  head.prev = newNode
121
+ } else {
122
+ this.tailCache = newNode
109
123
  }
110
124
  this.innerList = newNode
111
- return this
125
+ } else {
126
+ // Ensure the next reference of this node is assigned to the new node
127
+ newNode.next = node.next
128
+ // Ensure this node is assigned as the prev reference of the new node
129
+ newNode.prev = node
130
+ // Then set this node's next reference to the new node
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
+ }
112
138
  }
113
- // Ensure the next reference of this node is assigned to the new node
114
- newNode.next = node.next
115
- // Ensure this node is assigned as the prev reference of the new node
116
- newNode.prev = node
117
- // Then set this node's next reference to the new node
118
- node.next = newNode
119
- if (newNode.next) {
120
- // Update the next reference to ensure circular reference for prev points to the new node
121
- newNode.next.prev = newNode
139
+ if (this.countCache !== null) {
140
+ ++this.countCache
122
141
  }
123
- this.reset()
124
142
  return this
125
143
  }
126
144
 
@@ -135,26 +153,31 @@ class DoublyLinkedList {
135
153
  if (node === null || typeof node === 'undefined') {
136
154
  // Before nothing means at the end of the list
137
155
  const tail = this.last
156
+ newNode.next = null
157
+ newNode.prev = tail
138
158
  if (tail === null) {
139
159
  this.innerList = newNode
140
160
  } else {
141
161
  tail.next = newNode
142
- newNode.prev = tail
143
162
  }
144
- this.reset()
145
- return this
163
+ this.tailCache = newNode
164
+ } else {
165
+ // The new node will reference this prev node as prev
166
+ newNode.prev = node.prev
167
+ // The new node will reference this node as next
168
+ newNode.next = node
169
+ // This prev will reference the new node
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
+ }
146
177
  }
147
- // The new node will reference this prev node as prev
148
- newNode.prev = node.prev
149
- // The new node will reference this node as next
150
- newNode.next = node
151
- // This prev will reference the new node
152
- node.prev = newNode
153
- if (newNode.prev) {
154
- // Update the prev reference to ensure circular reference for next points to the new node
155
- newNode.prev.next = newNode
178
+ if (this.countCache !== null) {
179
+ ++this.countCache
156
180
  }
157
- this.reset()
158
181
  return this
159
182
  }
160
183
 
@@ -184,7 +207,7 @@ class DoublyLinkedList {
184
207
  * @return {DoubleLinker}
185
208
  */
186
209
  remove (node) {
187
- if (node === null) {
210
+ if (node === null || typeof node === 'undefined') {
188
211
  return null
189
212
  }
190
213
  if (node.prev) {
@@ -200,35 +223,47 @@ class DoublyLinkedList {
200
223
  if (this.innerList === node) {
201
224
  this.innerList = node.next || node.prev || null
202
225
  }
203
- // Update head reference
204
- this.reset()
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
+ }
205
235
  return node
206
236
  }
207
237
 
208
238
  /**
209
- * Refresh all references and return head reference.
210
- * @return {DoubleLinker}
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}
211
242
  */
212
243
  reset () {
213
244
  // Start at the pointer for the list
214
245
  let pointer = this.innerList
215
246
  if (pointer === null) {
247
+ this.countCache = 0
248
+ this.tailCache = null
216
249
  return null
217
250
  }
218
- let next = pointer.next
219
- // Follow references till the end
220
- while (next !== null) {
221
- pointer = next
222
- next = pointer.next
223
- }
224
- let prev = pointer.prev
225
- // From final reference, follow references back to the beginning
226
- while (prev !== null) {
227
- pointer = prev
228
- prev = pointer.prev
251
+ // Follow references back to the beginning
252
+ while (pointer.prev !== null) {
253
+ pointer = pointer.prev
229
254
  }
230
- // All the live references should have been found, and we are pointing to the true head
255
+ // We are pointing to the true head, now count along to the end to find the tail and the length
231
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
232
267
  return pointer
233
268
  }
234
269
 
@@ -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(){return this.reset()}get last(){let e=this.innerList;if(null===e)return null;let t=e.next;for(;null!==t;)e=t,t=e.next;return e}get length(){let e=this.first,t=0;for(;null!==e;)++t,e=e.next;return t}insertAfter(e,t){if(t=this.linkerClass.make(t,this.linkerClass),null==e){const e=this.first;return t.next=e,e&&(e.prev=t),this.innerList=t,this}return t.next=e.next,t.prev=e,e.next=t,t.next&&(t.next.prev=t),this.reset(),this}insertBefore(e,t){if(t=this.linkerClass.make(t,this.linkerClass),null==e){const e=this.last;return null===e?this.innerList=t:(e.next=t,t.prev=e),this.reset(),this}return t.prev=e.prev,t.next=e,e.prev=t,t.prev&&(t.prev.next=t),this.reset(),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.reset(),e)}reset(){let e=this.innerList;if(null===e)return null;let t=e.next;for(;null!==t;)e=t,t=e.next;let r=e.prev;for(;null!==r;)e=r,r=e.prev;return this.innerList=e,e}item(e){if(e>=0){let t=this.first,r=-1;for(;++r<e&&null!==t;)t=t.next;return r===e?t:null}let t=this.last,r=this.length;const i=this.length+e;if(i<0)return null;for(;--r>i&&null!==t;)t=t.prev;return r===i?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,r=DoublyLinkedList)=>_LinkedList.LinkedList.fromArray(e,t,r);
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);
@@ -20,6 +20,10 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
20
20
  initialized: boolean;
21
21
  /** The class used to wrap the data given to this list as linkers. */
22
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;
23
27
  /**
24
28
  * Create the new LinkedList instance.
25
29
  * @param {Linker} [linkerClass=Linker] The class used to wrap given data as linkers.
@@ -42,12 +46,13 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
42
46
  */
43
47
  get first(): Linker;
44
48
  /**
45
- * 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.
46
50
  * @returns {Linker}
47
51
  */
48
- get last(): Linker;
52
+ get last(): Linker | null;
49
53
  /**
50
- * 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).
51
56
  * @returns {number}
52
57
  */
53
58
  get length(): number;
@@ -86,6 +91,12 @@ export declare class LinkedList implements IsArrayable<Linker>, Iterable<Linker>
86
91
  * @return {Linker|null} The removed node, or null when it was not in this list (nothing is removed)
87
92
  */
88
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;
89
100
  /**
90
101
  * Retrieve a Linker item from this list by numeric index, otherwise return null.
91
102
  * @param {number} index The integer number for retrieving a node by position.
@@ -23,6 +23,10 @@ class LinkedList {
23
23
  this.innerList = null
24
24
  /** Whether the inner list has been initialized (it can only be initialized once). */
25
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
26
30
  this.linkerClass = linkerClass
27
31
  }
28
32
 
@@ -53,34 +57,32 @@ class LinkedList {
53
57
  }
54
58
 
55
59
  /**
56
- * 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.
57
61
  * @returns {Linker}
58
62
  */
59
63
  get last () {
60
- let tail = this.innerList
61
- if (tail === null) {
64
+ if (this.innerList === null) {
62
65
  return null
63
66
  }
64
- let next = tail.next
65
- while (next !== null) {
66
- tail = next
67
- next = tail.next
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
68
71
  }
72
+ this.tailCache = tail
69
73
  return tail
70
74
  }
71
75
 
72
76
  /**
73
- * 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).
74
79
  * @returns {number}
75
80
  */
76
81
  get length () {
77
- let current = this.first
78
- let length = 0
79
- while (current !== null) {
80
- ++length
81
- current = current.next
82
+ if (this.countCache === null) {
83
+ this.reset()
82
84
  }
83
- return length
85
+ return this.countCache
84
86
  }
85
87
 
86
88
  /**
@@ -94,11 +96,20 @@ class LinkedList {
94
96
  if (node === null || typeof node === 'undefined') {
95
97
  // After nothing means at the start of the list
96
98
  newNode.next = this.innerList
99
+ if (this.innerList === null) {
100
+ this.tailCache = newNode
101
+ }
97
102
  this.innerList = newNode
98
- return this
103
+ } else {
104
+ newNode.next = node.next
105
+ node.next = newNode
106
+ if (newNode.next === null) {
107
+ this.tailCache = newNode
108
+ }
109
+ }
110
+ if (this.countCache !== null) {
111
+ ++this.countCache
99
112
  }
100
- newNode.next = node.next
101
- node.next = newNode
102
113
  return this
103
114
  }
104
115
 
@@ -114,27 +125,32 @@ class LinkedList {
114
125
  if (node === null || typeof node === 'undefined') {
115
126
  // Before nothing means at the end of the list
116
127
  const tail = this.last
128
+ newNode.next = null
117
129
  if (tail === null) {
118
130
  this.innerList = newNode
119
131
  } else {
120
132
  tail.next = newNode
121
133
  }
122
- return this
123
- }
124
- let prevNode = null
125
- let currentNode = this.first
126
- while (currentNode !== null && currentNode !== node) {
127
- prevNode = currentNode
128
- currentNode = currentNode.next
129
- }
130
- if (currentNode === null) {
131
- throw new Error('The reference node is not in this list.')
132
- }
133
- newNode.next = node
134
- if (prevNode) {
135
- prevNode.next = newNode
134
+ this.tailCache = newNode
136
135
  } else {
137
- this.innerList = newNode
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
+ }
151
+ }
152
+ if (this.countCache !== null) {
153
+ ++this.countCache
138
154
  }
139
155
  return this
140
156
  }
@@ -183,9 +199,37 @@ class LinkedList {
183
199
  } else {
184
200
  this.innerList = node.next
185
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
+ }
186
211
  return node
187
212
  }
188
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
+
189
233
  /**
190
234
  * Retrieve a Linker item from this list by numeric index, otherwise return null.
191
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(){let t=this.innerList;if(null===t)return null;let e=t.next;for(;null!==e;)t=e,e=t.next;return t}get length(){let t=this.first,e=0;for(;null!==t;)++e,t=t.next;return e}insertAfter(t,e){return e=this.linkerClass.make(e,this.linkerClass),null==t?(e.next=this.innerList,this.innerList=e,this):(e.next=t.next,t.next=e,this)}insertBefore(t,e){if(e=this.linkerClass.make(e,this.linkerClass),null==t){const t=this.last;return null===t?this.innerList=e:t.next=e,this}let r=null,i=this.first;for(;null!==i&&i!==t;)r=i,i=i.next;if(null===i)throw new Error("The reference node is not in this list.");return e.next=t,r?r.next=e:this.innerList=e,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,r=this.first;for(;null!==r&&r!==t;)e=r,r=r.next;return null===r?null:(e?e.next=t.next:this.innerList=t.next,t)}item(t){if(t>=0){let e=this.first,r=-1;for(;++r<t&&null!==e;)e=e.next;return r===t?e:null}let e=this.first,r=0;const i=this.length+t;if(i<0)return null;for(;r<i&&null!==e;)e=e.next,++r;return r===i?e:null}forEach(t,e=this){let r=0,i=e.first;for(;null!==i;)t(i,r,e),i=i.next,++r;return e}[Symbol.iterator](){return new _LinkerIterator.LinkerIterator(this.first)}}exports.LinkedList=LinkedList,LinkedList.fromArray=(t=[],e=_Linker.Linker,r=LinkedList)=>new r(e).initialize(e.fromArray(t).head);
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);
@@ -21,6 +21,10 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
21
21
  initialized: boolean;
22
22
  /** The class used to wrap the data given to this list as tree linkers. */
23
23
  linkerClass: typeof TreeLinker;
24
+ /** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
25
+ private tailCache;
26
+ /** 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). */
27
+ private countCache;
24
28
  /**
25
29
  * Create the new LinkedTreeList instance, configure the list class.
26
30
  * @param {TreeLinker} [linkerClass=TreeLinker] The class used to wrap given data as tree linkers.
@@ -43,12 +47,13 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
43
47
  */
44
48
  get first(): TreeLinker;
45
49
  /**
46
- * Retrieve the last TreeLinker in the list.
50
+ * Retrieve the last TreeLinker in the list. The end is remembered, so this does not walk the list.
47
51
  * @returns {TreeLinker}
48
52
  */
49
53
  get last(): TreeLinker;
50
54
  /**
51
- * Return the length of the list.
55
+ * 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
56
+ * (call reset() after linkers were changed directly).
52
57
  * @returns {number}
53
58
  */
54
59
  get length(): number;
@@ -108,7 +113,8 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
108
113
  */
109
114
  remove(node: TreeLinker): TreeLinker;
110
115
  /**
111
- * Refresh all references and return head reference.
116
+ * Refresh all references (the head, the end and the length) by walking the list once, and return the head. The
117
+ * list's own methods keep these up to date, so this is only needed after linkers were changed directly.
112
118
  * @return {TreeLinker}
113
119
  */
114
120
  reset(): TreeLinker;