@quenty/observablecollection 12.20.0 → 12.20.1

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.
@@ -1,3 +1,4 @@
1
+ --!strict
1
2
  --[=[
2
3
  Used by [ObservableSortedList] to maintain a red-black binary search tree.
3
4
 
@@ -9,31 +10,44 @@ local require = require(script.Parent.loader).load(script)
9
10
  local ListIndexUtils = require("ListIndexUtils")
10
11
  local DuckTypeUtils = require("DuckTypeUtils")
11
12
  local Table = require("Table")
13
+ local SortedNodeValue = require("SortedNodeValue")
14
+ local _SortFunctionUtils = require("SortFunctionUtils")
12
15
 
13
16
  local DEBUG_ASSERTION_SLOW = false
14
17
 
18
+ export type SortedNodeColor = "BLACK" | "RED"
19
+
20
+ export type SortedNodeColorMap = {
21
+ BLACK: "BLACK",
22
+ RED: "RED",
23
+ }
24
+
15
25
  local Color = Table.readonly({
16
- BLACK = "BLACK";
17
- RED = "RED";
18
- })
26
+ BLACK = "BLACK",
27
+ RED = "RED",
28
+ } :: SortedNodeColorMap)
19
29
 
20
30
  local SortedNode = {}
21
31
  SortedNode.ClassName = "SortedNode"
22
32
  SortedNode.__index = SortedNode
23
33
 
24
- export type SortedNode<T> = typeof(setmetatable({
25
- left = nil :: SortedNode<T>?,
26
- right = nil :: SortedNode<T>?,
27
- color = nil :: "B" | "R";
28
- value = nil :: number,
29
- descendantCount = nil :: number,
30
- data = nil :: T
31
- }, SortedNode))
32
-
33
- function SortedNode.new(data): SortedNode<T>
34
+ export type SortedNode<T> = typeof(setmetatable(
35
+ {} :: {
36
+ left: SortedNode<T>?,
37
+ right: SortedNode<T>?,
38
+ parent: SortedNode<T>?,
39
+ color: SortedNodeColor,
40
+ value: number?, -- Actually SortedNodeValue too, but we treat as number
41
+ descendantCount: number,
42
+ data: T,
43
+ },
44
+ SortedNode
45
+ ))
46
+
47
+ function SortedNode.new<T>(data: T): SortedNode<T>
34
48
  assert(data ~= nil, "Bad data")
35
49
 
36
- local self = setmetatable({}, SortedNode)
50
+ local self: SortedNode<T> = setmetatable({} :: any, SortedNode)
37
51
 
38
52
  self.data = data
39
53
  self.color = Color.RED
@@ -42,14 +56,14 @@ function SortedNode.new(data): SortedNode<T>
42
56
  return self
43
57
  end
44
58
 
45
- function SortedNode.isSortedNode(value)
59
+ function SortedNode.isSortedNode(value: any): boolean
46
60
  return DuckTypeUtils.isImplementation(SortedNode, value)
47
61
  end
48
62
 
49
- function SortedNode:IterateNodes()
63
+ function SortedNode.IterateNodes<T>(self: SortedNode<T>): _SortFunctionUtils.WrappedIterator<number, SortedNode<T>>
50
64
  return coroutine.wrap(function()
51
- local stack = {}
52
- local current = self
65
+ local stack: { SortedNode<T> } = {}
66
+ local current: any? = self
53
67
  local index = 1
54
68
 
55
69
  while current or #stack > 0 do
@@ -62,15 +76,15 @@ function SortedNode:IterateNodes()
62
76
  current = table.remove(stack)
63
77
  coroutine.yield(index, current)
64
78
  index += 1
65
- current = current.right
79
+ current = (current :: any).right
66
80
  end
67
- end)
81
+ end) :: any
68
82
  end
69
83
 
70
- function SortedNode:IterateData()
84
+ function SortedNode.IterateData<T>(self: SortedNode<T>): _SortFunctionUtils.WrappedIterator<number, T>
71
85
  return coroutine.wrap(function()
72
- local stack = {}
73
- local current = self
86
+ local stack: { SortedNode<T> } = {}
87
+ local current: any = self
74
88
  local index = 1
75
89
 
76
90
  while current or #stack > 0 do
@@ -80,12 +94,12 @@ function SortedNode:IterateData()
80
94
  current = current.left
81
95
  end
82
96
 
83
- current = table.remove(stack)
84
- coroutine.yield(index, current.data)
97
+ local removed: SortedNode<T> = assert(table.remove(stack), "Must have entry")
98
+ coroutine.yield(index, removed.data)
85
99
  index += 1
86
- current = current.right
100
+ current = removed.right
87
101
  end
88
- end)
102
+ end) :: any
89
103
  end
90
104
 
91
105
  --[=[
@@ -96,7 +110,11 @@ end
96
110
  @param finish number
97
111
  @return (T) -> ((T, nextIndex: any) -> ...any, T?)
98
112
  ]=]
99
- function SortedNode:IterateNodesRange(start, finish)
113
+ function SortedNode.IterateNodesRange<T>(
114
+ self: SortedNode<T>,
115
+ start: number,
116
+ finish: number
117
+ ): _SortFunctionUtils.WrappedIterator<number, SortedNode<T>>
100
118
  assert(type(start) == "number", "Bad start")
101
119
  assert(type(finish) == "number" or finish == nil, "Bad finish")
102
120
  assert(self.parent == nil, "Should only be called on root")
@@ -106,16 +124,16 @@ function SortedNode:IterateNodesRange(start, finish)
106
124
  end
107
125
 
108
126
  return coroutine.wrap(function()
109
- local target = ListIndexUtils.toPositiveIndex(self.descendantCount, start)
110
- local endTarget = ListIndexUtils.toPositiveIndex(self.descendantCount, finish or -1)
111
- local current = self:FindNodeAtIndex(target)
127
+ local target: number = ListIndexUtils.toPositiveIndex(self.descendantCount, start)
128
+ local endTarget: number = ListIndexUtils.toPositiveIndex(self.descendantCount, finish or -1)
129
+ local current: any? = self:FindNodeAtIndex(target)
112
130
 
113
131
  -- We're out of range
114
132
  if not current then
115
133
  return
116
134
  end
117
135
 
118
- local index = target
136
+ local index: number = target
119
137
 
120
138
  while current do
121
139
  coroutine.yield(index, current)
@@ -144,10 +162,12 @@ function SortedNode:IterateNodesRange(start, finish)
144
162
 
145
163
  current = current.parent
146
164
  end
147
- end)
165
+
166
+ return
167
+ end) :: any
148
168
  end
149
169
 
150
- function SortedNode:FindNodeAtIndex(searchIndex)
170
+ function SortedNode.FindNodeAtIndex<T>(self: SortedNode<T>, searchIndex: number): SortedNode<T>?
151
171
  assert(type(searchIndex) == "number", "Bad searchIndex")
152
172
  assert(self.parent == nil, "Should only be called on root")
153
173
 
@@ -156,7 +176,7 @@ function SortedNode:FindNodeAtIndex(searchIndex)
156
176
  return nil
157
177
  end
158
178
 
159
- local current = self
179
+ local current: any = self
160
180
  local index = 1
161
181
  if self.left then
162
182
  index += self.left.descendantCount
@@ -183,7 +203,7 @@ function SortedNode:FindNodeAtIndex(searchIndex)
183
203
  return nil
184
204
  end
185
205
 
186
- function SortedNode:FindNodeIndex(node)
206
+ function SortedNode.FindNodeIndex<T>(self: SortedNode<T>, node: SortedNode<T>): number?
187
207
  assert(SortedNode.isSortedNode(node), "Bad node")
188
208
  assert(self.parent == nil, "Should only be called on root")
189
209
 
@@ -195,7 +215,7 @@ function SortedNode:FindNodeIndex(node)
195
215
  end
196
216
  end
197
217
 
198
- function SortedNode:GetIndex(): number
218
+ function SortedNode.GetIndex<T>(self: SortedNode<T>): number
199
219
  local index = 1
200
220
 
201
221
  if self.left then
@@ -207,8 +227,8 @@ function SortedNode:GetIndex(): number
207
227
  if current == current.parent.right then
208
228
  index += 1
209
229
 
210
- if current.parent.left then
211
- index += current.parent.left.descendantCount
230
+ if (current :: any).parent.left then
231
+ index += (current :: any).parent.left.descendantCount
212
232
  end
213
233
  end
214
234
 
@@ -218,7 +238,7 @@ function SortedNode:GetIndex(): number
218
238
  return index
219
239
  end
220
240
 
221
- function SortedNode:FindFirstNodeForData(data)
241
+ function SortedNode.FindFirstNodeForData<T>(self: SortedNode<T>, data: T): SortedNode<T>?
222
242
  -- TODO: This is a linear search, very bad
223
243
 
224
244
  for _, current in self:IterateNodes() do
@@ -230,7 +250,7 @@ function SortedNode:FindFirstNodeForData(data)
230
250
  return nil
231
251
  end
232
252
 
233
- function SortedNode:NeedsToMove(root, newValue)
253
+ function SortedNode.NeedsToMove<T>(self: SortedNode<T>, root: SortedNode<T>?, newValue: number): boolean
234
254
  assert(newValue ~= nil, "Bad newValue")
235
255
 
236
256
  if self.parent ~= nil then
@@ -263,10 +283,10 @@ end
263
283
  --[=[
264
284
  Returns true if the node is contained within the parent node
265
285
  ]=]
266
- function SortedNode:ContainsNode(node: SortedNode): boolean
286
+ function SortedNode.ContainsNode<T>(self: SortedNode<T>, node: SortedNode<T>): boolean
267
287
  assert(SortedNode.isSortedNode(node), "Bad SortedNode")
268
288
 
269
- local current = node
289
+ local current: any = node
270
290
  while current do
271
291
  if current == self then
272
292
  return true
@@ -278,11 +298,11 @@ function SortedNode:ContainsNode(node: SortedNode): boolean
278
298
  return false
279
299
  end
280
300
 
281
- function SortedNode:MarkBlack()
301
+ function SortedNode.MarkBlack<T>(self: SortedNode<T>)
282
302
  self.color = Color.BLACK
283
303
  end
284
304
 
285
- function SortedNode:InsertNode(node): SortedNode<T>
305
+ function SortedNode.InsertNode<T>(self: SortedNode<T>, node: SortedNode<T>): SortedNode<T>
286
306
  assert(SortedNode.isSortedNode(node), "Bad SortedNode")
287
307
  assert(self.parent == nil, "Should only be called on root")
288
308
  assert(node.parent == nil, "Already parented")
@@ -294,8 +314,8 @@ function SortedNode:InsertNode(node): SortedNode<T>
294
314
 
295
315
  node.color = Color.RED
296
316
 
297
- local parent = nil
298
- local current = root
317
+ local parent: SortedNode<T>? = nil
318
+ local current: any = root
299
319
 
300
320
  while current ~= nil do
301
321
  parent = current
@@ -329,7 +349,7 @@ function SortedNode:InsertNode(node): SortedNode<T>
329
349
  return root
330
350
  end
331
351
 
332
- function SortedNode:_leftRotate(root, node): SortedNode<T>
352
+ function SortedNode._leftRotate<T>(_self: SortedNode<T>, root, node): SortedNode<T>
333
353
  assert(root, "No root")
334
354
  assert(node, "No node")
335
355
 
@@ -352,7 +372,7 @@ function SortedNode:_leftRotate(root, node): SortedNode<T>
352
372
  return root
353
373
  end
354
374
 
355
- function SortedNode:_rightRotate(root, node): SortedNode<T>
375
+ function SortedNode._rightRotate<T>(_self: SortedNode<T>, root, node): SortedNode<T>
356
376
  assert(root, "No root")
357
377
  assert(node, "No node")
358
378
 
@@ -375,19 +395,19 @@ function SortedNode:_rightRotate(root, node): SortedNode<T>
375
395
  return root
376
396
  end
377
397
 
378
- function SortedNode:_swapColors(other)
398
+ function SortedNode._swapColors<T>(self: SortedNode<T>, other: SortedNode<T>)
379
399
  self.color, other.color = other.color, self.color
380
400
  end
381
401
 
382
- function SortedNode:_fixDoubleRed(root, node): SortedNode
402
+ function SortedNode._fixDoubleRed<T>(self: SortedNode<T>, root: SortedNode<T>, node: SortedNode<T>): SortedNode<T>
383
403
  if node == root then
384
404
  node.color = Color.BLACK
385
405
  return root
386
406
  end
387
407
 
388
- local parent = node.parent
389
- local grandparent = node.parent and node.parent.parent
390
- local uncle = node:_uncle()
408
+ local parent: any = assert(node.parent, "Must have node parent")
409
+ local grandparent: any = node.parent and node.parent.parent
410
+ local uncle: any = node:_uncle()
391
411
 
392
412
  if not grandparent then
393
413
  return root
@@ -435,7 +455,7 @@ function SortedNode:_fixDoubleRed(root, node): SortedNode
435
455
  return root
436
456
  end
437
457
 
438
- function SortedNode:_setLeft(node: SortedNode)
458
+ function SortedNode._setLeft<T>(self: SortedNode<T>, node: SortedNode<T>?)
439
459
  assert(node ~= self, "Cannot assign to self")
440
460
 
441
461
  if self.left == node then
@@ -453,20 +473,19 @@ function SortedNode:_setLeft(node: SortedNode)
453
473
  end
454
474
 
455
475
  self.left = node
456
- self.left.parent = self
476
+ node.parent = self
457
477
  end
458
478
 
459
479
  self:_updateAllParentDescendantCount()
460
480
  end
461
481
 
462
- function SortedNode:_setRight(node: SortedNode)
482
+ function SortedNode._setRight<T>(self: SortedNode<T>, node: SortedNode<T>?)
463
483
  assert(node ~= self, "Cannot assign to self")
464
484
 
465
485
  if self.right == node then
466
486
  return
467
487
  end
468
488
 
469
-
470
489
  if self.right then
471
490
  self.right.parent = nil
472
491
  self.right = nil
@@ -478,14 +497,14 @@ function SortedNode:_setRight(node: SortedNode)
478
497
  end
479
498
 
480
499
  self.right = node
481
- self.right.parent = self
500
+ node.parent = self
482
501
  end
483
502
 
484
503
  self:_updateAllParentDescendantCount()
485
504
  end
486
505
 
487
- function SortedNode:_updateAllParentDescendantCount()
488
- local current = self
506
+ function SortedNode._updateAllParentDescendantCount<T>(self: SortedNode<T>)
507
+ local current: any = self
489
508
  while current do
490
509
  local descendantCount = 1
491
510
  local left = current.left
@@ -502,7 +521,7 @@ function SortedNode:_updateAllParentDescendantCount()
502
521
  end
503
522
  end
504
523
 
505
- function SortedNode:RemoveNode(node: SortedNode): SortedNode
524
+ function SortedNode.RemoveNode<T>(self: SortedNode<T>, node: SortedNode<T>): SortedNode<T>
506
525
  assert(SortedNode.isSortedNode(node), "Bad SortedNode")
507
526
  assert(self.parent == nil, "Should only be called on root")
508
527
 
@@ -534,7 +553,12 @@ function SortedNode:RemoveNode(node: SortedNode): SortedNode
534
553
  return root
535
554
  end
536
555
 
537
- function SortedNode:_removeNodeHelper(root, node, depth)
556
+ function SortedNode._removeNodeHelper<T>(
557
+ self: SortedNode<T>,
558
+ root: SortedNode<T>?,
559
+ node: SortedNode<T>?,
560
+ depth: number?
561
+ ): SortedNode<T>
538
562
  assert(root, "Bad root")
539
563
  assert(node, "Bad node")
540
564
  depth = (depth or 0) + 1
@@ -572,7 +596,7 @@ function SortedNode:_removeNodeHelper(root, node, depth)
572
596
  root = self:_swapNodes(root, node, replacement)
573
597
  root = self:_removeNodeHelper(root, node, depth)
574
598
  else
575
- assert(node.parent, "Node must have parent")
599
+ assert(parent, "Node must have parent")
576
600
 
577
601
  if node:_isOnLeft() then
578
602
  parent:_setLeft(replacement)
@@ -609,7 +633,12 @@ function SortedNode:_removeNodeHelper(root, node, depth)
609
633
  return root
610
634
  end
611
635
 
612
- function SortedNode:_swapNodes(root, node, replacement)
636
+ function SortedNode._swapNodes<T>(
637
+ _self: SortedNode<T>,
638
+ root: SortedNode<T>,
639
+ node: SortedNode<T>,
640
+ replacement: SortedNode<T>
641
+ ): SortedNode<T>?
613
642
  assert(root, "No root")
614
643
  assert(node, "No node")
615
644
  assert(replacement, "No replacement")
@@ -628,12 +657,12 @@ function SortedNode:_swapNodes(root, node, replacement)
628
657
  local nodeLeft = node.left
629
658
  local nodeRight = node.right
630
659
  local nodeOnLeft = nodeParent and node:_isOnLeft()
631
- local nodeColor = node.color
660
+ local nodeColor: SortedNodeColor = node.color
632
661
  local replacementLeft = replacement.left
633
662
  local replacementRight = replacement.right
634
663
  local replacementParent = replacement.parent
635
664
  local replacementOnLeft = replacement:_isOnLeft()
636
- local replacementColor = replacement.color
665
+ local replacementColor: SortedNodeColor = replacement.color
637
666
 
638
667
  if replacement.parent == node then
639
668
  node:_unparent()
@@ -718,7 +747,7 @@ function SortedNode:_swapNodes(root, node, replacement)
718
747
  return root
719
748
  end
720
749
 
721
- function SortedNode:_findReplacement(node)
750
+ function SortedNode._findReplacement<T>(_self: SortedNode<T>, node: SortedNode<T>): SortedNode<T>?
722
751
  if node.left and node.right then
723
752
  return node.right:_successor()
724
753
  end
@@ -734,7 +763,7 @@ function SortedNode:_findReplacement(node)
734
763
  end
735
764
  end
736
765
 
737
- function SortedNode:_successor()
766
+ function SortedNode._successor<T>(self: SortedNode<T>): SortedNode<T>
738
767
  local node = self
739
768
  while node.left ~= nil do
740
769
  node = node.left
@@ -745,7 +774,7 @@ end
745
774
  --[[
746
775
  https://www.geeksforgeeks.org/deletion-in-red-black-tree/?ref=oin_asr9
747
776
  ]]
748
- function SortedNode:_fixDoubleBlack(root, node)
777
+ function SortedNode._fixDoubleBlack<T>(self: SortedNode<T>, root: SortedNode<T>, node: SortedNode<T>): SortedNode<T>
749
778
  assert(root, "No root")
750
779
  assert(node, "No node")
751
780
 
@@ -798,13 +827,13 @@ function SortedNode:_fixDoubleBlack(root, node)
798
827
  else
799
828
  if sibling:_isOnLeft() then
800
829
  -- Left-right
801
- sibling.right.color = parent.color
830
+ (sibling :: any).right.color = parent.color
802
831
  parent.color = Color.BLACK -- This should be true, but the guide I'm following doesn't specify this?
803
832
  root = self:_leftRotate(root, sibling)
804
833
  root = self:_rightRotate(root, parent)
805
834
  else
806
835
  -- Right-right
807
- sibling.right.color = sibling.color
836
+ (sibling :: any).right.color = sibling.color
808
837
  sibling.color = parent.color
809
838
  parent.color = Color.BLACK -- This should be true, but the guide I'm following doesn't specify this?
810
839
  root = self:_leftRotate(root, parent)
@@ -826,19 +855,19 @@ function SortedNode:_fixDoubleBlack(root, node)
826
855
  return root
827
856
  end
828
857
 
829
- function SortedNode:_isOnLeft()
858
+ function SortedNode._isOnLeft<T>(self: SortedNode<T>): boolean
830
859
  assert(self.parent, "Must have parent to invoke this method")
831
860
 
832
861
  return self.parent.left == self
833
862
  end
834
863
 
835
- function SortedNode:_isOnRight()
864
+ function SortedNode._isOnRight<T>(self: SortedNode<T>): boolean
836
865
  assert(self.parent, "Must have parent to invoke this method")
837
866
 
838
867
  return self.parent.right == self
839
868
  end
840
869
 
841
- function SortedNode:_hasRedChild()
870
+ function SortedNode._hasRedChild<T>(self: SortedNode<T>): boolean
842
871
  if self.left and self.left.color == Color.RED then
843
872
  return true
844
873
  end
@@ -850,20 +879,20 @@ function SortedNode:_hasRedChild()
850
879
  return false
851
880
  end
852
881
 
853
- function SortedNode:_unparent()
854
- if not self.parent then
882
+ function SortedNode._unparent<T>(self: SortedNode<T>)
883
+ local parent = self.parent
884
+ if not parent then
855
885
  return
856
- elseif self.parent.left == self then
857
- self.parent:_setLeft(nil)
858
- elseif self.parent.right == self then
859
- self.parent:_setRight(nil)
886
+ elseif parent.left == self then
887
+ parent:_setLeft(nil)
888
+ elseif parent.right == self then
889
+ parent:_setRight(nil)
860
890
  else
861
891
  error("Bad state")
862
892
  end
863
893
  end
864
894
 
865
-
866
- function SortedNode:_uncle()
895
+ function SortedNode._uncle<T>(self: SortedNode<T>): SortedNode<T>?
867
896
  local grandparent = self:_grandparent()
868
897
  if not grandparent then
869
898
  return nil
@@ -878,12 +907,13 @@ function SortedNode:_uncle()
878
907
  end
879
908
  end
880
909
 
881
- function SortedNode:_sibling()
882
- if self.parent then
883
- if self == self.parent.left then
884
- return self.parent.right
885
- elseif self == self.parent.right then
886
- return self.parent.left
910
+ function SortedNode._sibling<T>(self: SortedNode<T>): SortedNode<T>?
911
+ local parent = self.parent
912
+ if parent then
913
+ if self == parent.left then
914
+ return parent.right
915
+ elseif self == parent.right then
916
+ return parent.left
887
917
  else
888
918
  error("Bad state")
889
919
  end
@@ -892,7 +922,7 @@ function SortedNode:_sibling()
892
922
  end
893
923
  end
894
924
 
895
- function SortedNode:_grandparent()
925
+ function SortedNode._grandparent<T>(self: SortedNode<T>)
896
926
  if self.parent then
897
927
  return self.parent.parent
898
928
  else
@@ -900,20 +930,26 @@ function SortedNode:_grandparent()
900
930
  end
901
931
  end
902
932
 
903
- function SortedNode:__tostring()
904
- local result
933
+ type SortedNodeTostringStackEntry<T> = {
934
+ node: SortedNode<T>?,
935
+ indent: string,
936
+ isLeft: boolean,
937
+ }
938
+
939
+ function SortedNode.__tostring<T>(self: SortedNode<T>): string
940
+ local result: string
905
941
  if self.parent == nil then
906
942
  result = "BinarySearchTree\n"
907
943
  else
908
944
  result = "SortedNode\n"
909
945
  end
910
946
 
911
- local stack = {} -- Stack to hold nodes and their details
947
+ local stack: { SortedNodeTostringStackEntry<T> } = {} -- Stack to hold nodes and their details
912
948
  local seen = {}
913
949
  table.insert(stack, { node = self, indent = "", isLeft = false })
914
950
 
915
951
  while #stack > 0 do
916
- local current = table.remove(stack) -- Pop from the stack
952
+ local current: SortedNodeTostringStackEntry<T> = assert(table.remove(stack), "Must have entry") -- Pop from the stack
917
953
  local wasSeen
918
954
 
919
955
  if current.node then
@@ -938,11 +974,13 @@ function SortedNode:__tostring()
938
974
  end
939
975
 
940
976
  if node then
941
- local text = string.format("SortedNode { index=%d, value=%s, descendants=%d, color=%s }",
977
+ local text = string.format(
978
+ "SortedNode { index=%d, value=%s, descendants=%d, color=%s }",
942
979
  node:GetIndex(),
943
980
  tostring(node.value),
944
981
  node.descendantCount,
945
- node.color)
982
+ node.color
983
+ )
946
984
 
947
985
  if wasSeen then
948
986
  result = result .. "<LOOPED> "
@@ -964,7 +1002,7 @@ function SortedNode:__tostring()
964
1002
  return result
965
1003
  end
966
1004
 
967
- function SortedNode:_childCount()
1005
+ function SortedNode._childCount<T>(self: SortedNode<T>): number
968
1006
  if self.left == nil and self.right == nil then
969
1007
  return 0
970
1008
  elseif self.left and self.right then
@@ -974,7 +1012,7 @@ function SortedNode:_childCount()
974
1012
  end
975
1013
  end
976
1014
 
977
- function SortedNode:_debugGetRoot()
1015
+ function SortedNode._debugGetRoot<T>(self: SortedNode<T>): SortedNode<T>
978
1016
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
979
1017
 
980
1018
  local seen = {}
@@ -992,7 +1030,7 @@ function SortedNode:_debugGetRoot()
992
1030
  return root
993
1031
  end
994
1032
 
995
- function SortedNode:_assertRedBlackIntegrity()
1033
+ function SortedNode._assertRedBlackIntegrity<T>(self: SortedNode<T>)
996
1034
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
997
1035
 
998
1036
  -- https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
@@ -1000,37 +1038,67 @@ function SortedNode:_assertRedBlackIntegrity()
1000
1038
  -- Check adjacency
1001
1039
  if self.left then
1002
1040
  if self.left.color == Color.RED then
1003
- error(string.format("A red node should not have a red child %s\n%s", tostring(self:_debugGetRoot()), tostring(self)))
1041
+ error(
1042
+ string.format(
1043
+ "A red node should not have a red child %s\n%s",
1044
+ tostring(self:_debugGetRoot()),
1045
+ tostring(self)
1046
+ )
1047
+ )
1004
1048
  end
1005
1049
  end
1006
1050
 
1007
1051
  if self.right then
1008
1052
  if self.right.color == Color.RED then
1009
- error(string.format("A red node should not have a red child %s\n%s", tostring(self:_debugGetRoot()), tostring(self)))
1053
+ error(
1054
+ string.format(
1055
+ "A red node should not have a red child %s\n%s",
1056
+ tostring(self:_debugGetRoot()),
1057
+ tostring(self)
1058
+ )
1059
+ )
1010
1060
  end
1011
1061
  end
1012
1062
 
1013
1063
  if self.parent then
1014
1064
  if self.parent.color == Color.RED then
1015
- error(string.format("A red node should not be have a red parent %s\n%s", tostring(self:_debugGetRoot()), tostring(self)))
1065
+ error(
1066
+ string.format(
1067
+ "A red node should not be have a red parent %s\n%s",
1068
+ tostring(self:_debugGetRoot()),
1069
+ tostring(self)
1070
+ )
1071
+ )
1016
1072
  end
1017
1073
  end
1018
1074
  end
1019
1075
 
1020
1076
  if self.left ~= nil and self.right == nil then
1021
1077
  if self.left.color ~= Color.RED then
1022
- error(string.format("Any node with 1 child must be red %s\n%s", tostring(self:_debugGetRoot()), tostring(self)))
1078
+ error(
1079
+ string.format(
1080
+ "Any node with 1 child must be red %s\n%s",
1081
+ tostring(self:_debugGetRoot()),
1082
+ tostring(self)
1083
+ )
1084
+ )
1023
1085
  end
1024
1086
  end
1025
1087
 
1026
1088
  if self.left == nil and self.right ~= nil then
1027
1089
  if self.right.color ~= Color.RED then
1028
- error(string.format("Any node with 1 child must be red %s\n%s", tostring(self:_debugGetRoot()), tostring(self)))
1090
+ error(
1091
+ string.format(
1092
+ "Any node with 1 child must be red %s\n%s",
1093
+ tostring(self:_debugGetRoot()),
1094
+ tostring(self)
1095
+ )
1096
+ )
1029
1097
  end
1030
1098
  end
1031
1099
  end
1032
1100
 
1033
- function SortedNode:_assertRedBlackFullIntegritySlow()
1101
+ function SortedNode._assertRedBlackFullIntegritySlow<T>(self: SortedNode<T>)
1034
1102
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
1035
1103
 
1036
1104
  local root = self:_debugGetRoot()
@@ -1042,7 +1110,7 @@ function SortedNode:_assertRedBlackFullIntegritySlow()
1042
1110
  local seen = {}
1043
1111
 
1044
1112
  local maxDepth = nil
1045
- local function recurse(node, ancestorBlackCount)
1113
+ local function recurse(node: SortedNode<T>, ancestorBlackCount: number)
1046
1114
  if seen[node] then
1047
1115
  error("Loop in nodes")
1048
1116
  end
@@ -1059,7 +1127,13 @@ function SortedNode:_assertRedBlackFullIntegritySlow()
1059
1127
  if maxDepth == nil then
1060
1128
  maxDepth = ancestorBlackCount
1061
1129
  elseif maxDepth ~= ancestorBlackCount then
1062
- error(string.format("Leaf nodes must all pass through the same amount (%d) of black nodes to root, but we are at %d", maxDepth, ancestorBlackCount))
1130
+ error(
1131
+ string.format(
1132
+ "Leaf nodes must all pass through the same amount (%d) of black nodes to root, but we are at %d",
1133
+ maxDepth,
1134
+ ancestorBlackCount
1135
+ )
1136
+ )
1063
1137
  end
1064
1138
  end
1065
1139
 
@@ -1069,7 +1143,13 @@ function SortedNode:_assertRedBlackFullIntegritySlow()
1069
1143
  if maxDepth == nil then
1070
1144
  maxDepth = ancestorBlackCount
1071
1145
  elseif maxDepth ~= ancestorBlackCount then
1072
- error(string.format("Leaf nodes must all pass through the same amount (%d) of black nodes to root but we are at %d", maxDepth, ancestorBlackCount))
1146
+ error(
1147
+ string.format(
1148
+ "Leaf nodes must all pass through the same amount (%d) of black nodes to root but we are at %d",
1149
+ maxDepth,
1150
+ ancestorBlackCount
1151
+ )
1152
+ )
1073
1153
  end
1074
1154
  end
1075
1155
  end
@@ -1078,7 +1158,7 @@ function SortedNode:_assertRedBlackFullIntegritySlow()
1078
1158
  recurse(root, 0)
1079
1159
  end
1080
1160
 
1081
- function SortedNode:_assertIntegrity()
1161
+ function SortedNode._assertIntegrity<T>(self: SortedNode<T>)
1082
1162
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
1083
1163
  assert(self.left ~= self, "Node cannot be parented to self")
1084
1164
  assert(self.right ~= self, "Node cannot be parented to self")
@@ -1090,13 +1170,25 @@ function SortedNode:_assertIntegrity()
1090
1170
 
1091
1171
  if parent.left == self then
1092
1172
  if self.value > parent.value then
1093
- error(string.format("self.parent.left.value %0.2f >= parent.value %0.2f", self.value, parent.value))
1173
+ error(
1174
+ string.format(
1175
+ "self.parent.left.value %s >= parent.value %s",
1176
+ self:_valueToHumanReadable(),
1177
+ parent:_valueToHumanReadable()
1178
+ )
1179
+ )
1094
1180
  end
1095
1181
  end
1096
1182
 
1097
1183
  if parent.right == self then
1098
1184
  if self.value < parent.value then
1099
- error(string.format("self.parent.right.value %0.2f <= parent.value %0.2f", self.value, parent.value))
1185
+ error(
1186
+ string.format(
1187
+ "self.parent.right.value %s <= parent.value %s",
1188
+ self:_valueToHumanReadable(),
1189
+ parent:_valueToHumanReadable()
1190
+ )
1191
+ )
1100
1192
  end
1101
1193
  end
1102
1194
  end
@@ -1107,7 +1199,13 @@ function SortedNode:_assertIntegrity()
1107
1199
  assert(left.parent == self, "Left parent is not set to us")
1108
1200
 
1109
1201
  if left.value > self.value then
1110
- error(string.format("left.value %0.2f > self.value %0.2f", left.value, self.value))
1202
+ error(
1203
+ string.format(
1204
+ "left.value %s > self.value %s",
1205
+ left:_valueToHumanReadable(),
1206
+ self:_valueToHumanReadable()
1207
+ )
1208
+ )
1111
1209
  end
1112
1210
 
1113
1211
  descendantCount += left.descendantCount
@@ -1118,7 +1216,13 @@ function SortedNode:_assertIntegrity()
1118
1216
  assert(right.parent == self, "Right parent is not set to us")
1119
1217
 
1120
1218
  if right.value < self.value then
1121
- error(string.format("right.value %0.2f <= self.value %0.2f", right.value, self.value))
1219
+ error(
1220
+ string.format(
1221
+ "right.value %s <= self.value %s",
1222
+ right:_valueToHumanReadable(),
1223
+ self:_valueToHumanReadable()
1224
+ )
1225
+ )
1122
1226
  end
1123
1227
 
1124
1228
  descendantCount += right.descendantCount
@@ -1129,7 +1233,18 @@ function SortedNode:_assertIntegrity()
1129
1233
  end
1130
1234
  end
1131
1235
 
1132
- function SortedNode:_assertFullIntegritySlow()
1236
+ function SortedNode._valueToHumanReadable<T>(self: SortedNode<T>): string
1237
+ local value: any = self.value
1238
+ if type(value) == "number" then
1239
+ return string.format("%0.2f", value)
1240
+ elseif SortedNodeValue.isSortedNodeValue(value) then
1241
+ return tostring(value)
1242
+ else
1243
+ error(string.format("Bad value %s", tostring(value)))
1244
+ end
1245
+ end
1246
+
1247
+ function SortedNode._assertFullIntegritySlow<T>(self: SortedNode<T>)
1133
1248
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
1134
1249
 
1135
1250
  local root = self:_debugGetRoot()
@@ -1154,13 +1269,13 @@ function SortedNode:_assertFullIntegritySlow()
1154
1269
  end
1155
1270
  end
1156
1271
 
1157
- function SortedNode:_assertRootIntegrity()
1272
+ function SortedNode._assertRootIntegrity<T>(self: SortedNode<T>)
1158
1273
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
1159
1274
  assert(self.parent == nil, "Root should not have a parent")
1160
1275
  assert(self.color == Color.BLACK, "Root should be black")
1161
1276
  end
1162
1277
 
1163
- function SortedNode:_assertDescendantCount(expected)
1278
+ function SortedNode._assertDescendantCount<T>(self: SortedNode<T>, expected: number)
1164
1279
  assert(DEBUG_ASSERTION_SLOW, "Must have debug enabled")
1165
1280
 
1166
1281
  if self.descendantCount ~= expected then