-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathArrays.cls
More file actions
169 lines (142 loc) · 4.9 KB
/
Arrays.cls
File metadata and controls
169 lines (142 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Arrays"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Option Explicit
Option Base 0 ' Default
Private Declare Sub GetMem2 Lib "msvbvm60" (src As Any, dest As Any)
Public Sub sort(ByRef arr As Variant, Optional sortOrder As sortOrder = ascending)
Variants.verifyArray arr
Dim length As Integer
length = UBound(arr) - LBound(arr) + 1
If length <= 0 Then
Exit Sub
End If
If Not Variants.isComparable(arr(LBound(arr))) Then
Err.Raise E_ARGUMENTOUTOFRANGE, "Arrays.Sort()", "Array must be Variants.IsComparable() for sorting to work."
End If
Dim isRef As Boolean
isRef = IsObject(arr(LBound(arr)))
Dim a, b As Variant
a = arr
ReDim b(LBound(a) To UBound(a))
Dim aHasTheData As Boolean
aHasTheData = True
Dim chunkSize As Integer
chunkSize = 1
While chunkSize < length
Dim sortPos As Integer
sortPos = LBound(a)
While sortPos <= UBound(a)
If aHasTheData Then
Merge a, b, sortPos, Math.min(sortPos + chunkSize, UBound(a) + 1), Math.min(sortPos + 2 * chunkSize, UBound(a) + 1), isRef, sortOrder
Else
Merge b, a, sortPos, Math.min(sortPos + chunkSize, UBound(a) + 1), Math.min(sortPos + 2 * chunkSize, UBound(a) + 1), isRef, sortOrder
End If
sortPos = sortPos + 2 * chunkSize
Wend
aHasTheData = Not aHasTheData
chunkSize = chunkSize * 2
Wend
' Copy the result over to the input array.
Dim sourceArray As Variant
sourceArray = IIf(aHasTheData, a, b)
Dim runner As Integer
For runner = LBound(sourceArray) To UBound(sourceArray)
If isRef Then
Set arr(runner) = sourceArray(runner)
Else
arr(runner) = sourceArray(runner)
End If
Next
End Sub
Private Sub Merge(source As Variant, ByRef target As Variant, leftStart As Integer, rightStart As Integer, rightEnd As Integer, isRef As Boolean, sortOrder As sortOrder)
Dim targetRunner, lRunner, rRunner As Integer
lRunner = leftStart
rRunner = rightStart
For targetRunner = leftStart To rightEnd - 1
' If we have stuff in the left chunk left
' and we either don't have stuff in the right chunk anymore
' or left is smaller or equal to right (We want to be stable!)
' -> then take the left element.
Dim takeLeft As Boolean
takeLeft = False
If lRunner < rightStart Then
If rRunner >= rightEnd Then
takeLeft = True
Else
If sortOrder = ascending And Math.cmp(source(lRunner), source(rRunner)) <= 0 _
Or sortOrder = descending And Math.cmp(source(lRunner), source(rRunner)) >= 0 Then
takeLeft = True
End If
End If
End If
If takeLeft Then
' -> Take the left element.
If isRef Then
Set target(targetRunner) = source(lRunner)
Else
target(targetRunner) = source(lRunner)
End If
lRunner = lRunner + 1
Else
' -> Take the right element.
If isRef Then
Set target(targetRunner) = source(rRunner)
Else
target(targetRunner) = source(rRunner)
End If
rRunner = rRunner + 1
End If
Next
End Sub
Public Function emptyVariantArray() As Variant()
emptyVariantArray = Array()
End Function
Public Function emptyIntegerArray() As Integer()
' Taken from http://stackoverflow.com/a/21290864/1975049
Dim i() As Integer
Dim v As Variant
v = Array()
Dim NewTypeCode As Integer
NewTypeCode = vbArray Or vbInteger
GetMem2 NewTypeCode, v
i = v
emptyIntegerArray = i
End Function
Public Function emptyByteArray() As Byte()
' Taken from http://stackoverflow.com/a/21290864/1975049
Dim b() As Byte
Dim v As Variant
v = Array()
Dim NewTypeCode As Integer
NewTypeCode = vbArray Or vbByte
GetMem2 NewTypeCode, v
b = v
emptyByteArray = b
End Function
Public Function elems(arr As Variant) As Long
elems = UBound(arr) - LBound(arr) + 1
End Function
Public Function toVariantArray(arr As Variant) As Variant()
Dim varArr() As Variant
If elems(arr) = 0 Then
toVariantArray = emptyVariantArray
Else
ReDim varArr(LBound(arr) To UBound(arr))
Dim runner As Long
For runner = LBound(arr) To UBound(arr)
If IsObject(arr(runner)) Then
Set varArr(runner) = arr(runner)
Else
varArr(runner) = arr(runner)
End If
Next
toVariantArray = varArr
End If
End Function