Skip to content

Instantly share code, notes, and snippets.

@jferard
Last active August 19, 2022 20:36
Show Gist options
  • Save jferard/16d7f05965efa3f1a91a368e0e8101fe to your computer and use it in GitHub Desktop.
Save jferard/16d7f05965efa3f1a91a368e0e8101fe to your computer and use it in GitHub Desktop.
Collections For LibreOffice Basic (WIP)
REM Collections For LibreOffice Basic
REM Copyright (C) 2022 J. Férard <https://github.com/jferard>
REM
REM Trying to create a sane API for collections in Basic. This is a work in progress.
REM
Option Explicit
REM
REM Helpers
REM
Sub Raise(Optional message As String)
MsgBox message
Error(1004)
End Sub
Sub AssertEq(actual As Variant, expected As Variant)
If actual <> expected Then Raise("Value " & actual & " is different from expected : " & expected)
End Sub
Sub AssertArrayEq(actual() As Variant, expected() As Variant)
Dim i As Long
If LBound(actual) <> LBound(expected) Or UBound(actual) <> UBound(expected) Then
Raise("Arrays have different sizes")
Else
For i=LBound(actual) To UBound(actual)
If actual(i) <> expected(i) Then Raise("Arrays differ at index " & i & ": " & actual(i) & " is different from expected : " & expected(i))
Next i
End If
End Sub
Sub AssertRaises(funcName As String, parameters() As Variant)
Dim script As Object
On Error GoTo ok
script = ThisComponent.scriptProvider.getScript("vnd.sun.star.script:Standard.Collections." & funcName & "?language=Basic&location=document")
script.invoke(parameters, Array(), Array())
On Error GoTo 0
Raise("Call " & funcName & "(" & ArrayToString(parameters) & ") did not raise any error")
ok:
End Sub
Sub AssertTests()
AssertEq("ABC", UCase("abc"))
AssertArrayEq(Array(), Array())
AssertArrayEq(Array(1, 2), Array(1, 2))
AssertRaises("Arrai", Array(1, 2))
End Sub
REM
REM Enums Helpers
REM
''
'' Make an Array out of an XEnumeration
''
Function EnumToArray(e As com.sun.star.container.XEnumeration) As Variant
Dim arr(8) As Variant
Dim i As Long
If Not e.hasMoreElements() Then
EnumToArray = Array()
Exit Function
End If
i = 0
Do While e.hasMoreElements()
arr(i) = e.nextElement()
i = i + 1
If i > UBound(arr) Then
ReDim Preserve arr(i * 2)
End If
Loop
ReDim Preserve arr(i - 1)
EnumToArray = arr
End Function
''
'' Find the size of an XEnumeration
''
Function GetEnumSize(e As com.sun.star.container.XEnumeration) As Long
Dim i As Long
i = 0
Do While e.hasMoreElements()
e.nextElement()
i = i + 1
Loop
GetEnumSize = i
End Function
REM
REM Arrays
REM
''
'' Copy an array
''
Function CopyArray(arr() As Variant) As Variant
Dim newArr() As Variant
newArr = arr
ReDim Preserve newArr(LBound(arr) To Ubound(arr))
CopyArray = newArr
End Function
''
'' Return the reversed array
''
Function ReversedArray(arr() As Variant) As Variant
Dim i, j As Variant
If UBound(arr) < LBound(arr) Then
ReversedArray = Array()
Exit Function
End If
Dim reversed(LBound(arr) To UBound(arr)) As Variant
i = LBound(arr)
j = UBound(arr)
Do While i <= j
reversed(i) = arr(j)
reversed(j) = arr(i)
i = i + 1
j = j - 1
Loop
ReversedArray = reversed
End Function
''
'' Return the array sorted (merge sort algorithm)
''
Function SortedArray(arr() As Variant) As Variant
Dim size As Long
Dim i, j, n As Long
Dim cur, other, temp As Variant
size = UBound(arr) - LBound(arr) + 1
If size <= 0 Then
ReversedArray = Array()
Exit Function
End If
Dim arr1 As Variant
Dim arr2(LBound(arr) To UBound(arr)) As Variant
arr1 = _CopySwap(arr)
n = 2
cur = arr1
other = arr2
Do While n <= size
For i = LBound(arr) To UBound(arr) Step 2 * n
_Merge(cur, i, n, other)
Next i
n = n * 2
temp = cur
cur = other
other = temp
Loop
SortedArray = cur
End Function
' prepare the first copy : swap pairs if necessary
Function _CopySwap(arr As Variant) As Variant
Dim arr1(LBound(arr) To UBound(arr)) As Variant
Dim i As Long
arr1(UBound(arr)) = arr(UBound(arr))
For i=LBound(arr) To UBound(arr) - 1 Step 2
If arr(i) < arr(i+1) Then
arr1(i) = arr(i)
arr1(i + 1) = arr(i + 1)
Else
arr1(i) = arr(i + 1)
arr1(i + 1) = arr(i)
End If
Next i
_CopySwap = arr1
End Function
' merge two sorted sequences
Sub _Merge(cur As Variant, i As Long, n As Long, other As Variant)
Dim a, b, c, s As Long
s = i + 2 * n
If s > UBound(other) + 1 Then s = UBound(other) + 1
c = i
a = i
b = i + n
If b >= s Then
Do While c < s
other(c) = cur(a)
c = c + 1
a = a + 1
Loop
Exit Sub
End If
Do While True
If cur(a) < cur(b) Then
other(c) = cur(a)
c = c + 1
If c = s Then Exit Sub
a = a + 1
If a = i + n Then
' flush b
Do While c < s
other(c) = cur(b)
c = c + 1
b = b + 1
Loop
Exit Sub
End If
Else
other(c) = cur(b)
c = c + 1
If c = s Then Exit Sub
b = b + 1
If b = s Then
' flush a
Do While c < s
other(c) = cur(a)
c = c + 1
a = a + 1
Loop
Exit Sub
End If
End If
Loop
End Sub
''
'' Sort the array in place.
''
Sub SortArrayInPlace(ByRef arr() As Variant)
_QuickSort(arr, LBound(arr), UBound(arr))
End Sub
Sub _QuickSort(ByRef arr() As Variant, p As Long, r As Long)
If p >= r Then Exit Sub
Dim q As Long
q = _Partition(arr, p, r)
_QuickSort(arr, p, q - 1)
_QuickSort(arr, q + 1, r)
End Sub
Function _Partition(ByRef arr() As Variant, p As Long, r As Long) As Long
Dim x, temp As Variant
Dim i, j As Long
i = Int(Rnd() * (r - p + 1)) + p ' 0 <= Rnd() < 1 => p <= i < (r - p + 1) + p = r + 1
x = arr(i)
arr(i) = arr(r)
i = p - 1
For j = p To r - 1
If arr(j) <= x Then
i = i + 1 ' p <= i <= j, swap j
temp = arr(j)
arr(j) = arr(i)
arr(i) = temp
End If
Next j
arr(r) = arr(i + 1)
arr(i + 1) = x
_Partition = i + 1
End Function
''
'' Return the array shuffled (Fisher Yates shuffle, a.k.a Knuth)
''
Function ShuffledArray(arr() As Variant) As Variant
If UBound(arr) < LBound(arr) Then
ShuffledArray = Array()
Exit Function
End If
Dim i, j As Long
Dim temp, newArr() As Variant
newArr = copyArray(arr)
For i = LBound(newArr) To UBound(newArr) - 1
j = i + Int(Rnd() * (UBound(newArr) - i + 1)) ' i <= j < i + UBound(arr) - i + 1 = UBound(arr) + 1
temp = newArr(i)
newArr(i) = newArr(j)
newArr(j) = temp
Next i
ShuffledArray = newArr
End Function
''
'' Return a representation of this array
''
Function ArrayToString(arr() As Variant) As String
Dim i As Long
Dim newArr(LBound(arr) To UBound(arr)) As String
For i=LBound(arr) To UBound(arr)
newArr(i) = UnoValueToString(arr(i))
Next i
ArrayToString = Join(newArr, ", ")
End Function
''
'' Return a String of a UNOValue
''
Function UnoValueToString(value As Variant) As String
Select Case VarType(value)
Case V_STRING
UnoValueToString = """" & value & """"
Case 11
If value Then
UnoValueToString = "True"
Else
UnoValueToString = "False"
End If
Case 9
UnoValueToString = "<obj>"
Case Else
UnoValueToString = CStr(value)
End Select
End Function
Sub ArrayTests
AssertEq(ArrayToString(Array(4, False, "x", ThisComponent)), "4, False, ""x"", <obj>")
AssertArrayEq(ReversedArray(Array()), Array())
AssertArrayEq(ReversedArray(Array(4, 5, 6)), Array(6, 5, 4))
AssertArrayEq(ReversedArray(Array(3, 4, 5, 6)), Array(6, 5, 4, 3))
' Sorted
AssertArrayEq(SortedArray(Array(5, 7, 9, 5, 4, 2, 1)), Array(1, 2, 4, 5, 5, 7, 9))
AssertArrayEq(SortedArray(Array(5, 7, 9, 5, 4, 2, 1, 10, 18, 16)), Array(1, 2, 4, 5, 5, 7, 9, 10, 16, 18))
AssertArrayEq(SortedArray(Array(80, 16, 9, 14, 68, 0, 46, 98, 74, 37, 18, 58, 69, 28, 62, 53, 76, 2, 57, 20, 11, 72, 84, 86, 50, 78, 39, 40, 27, 94, 81, 67, 61, 26, 12, 96, 19, 71, 92, 47, 75, 6, 42, 55, 54, 17, 21, 66, 8, 59, 63, 45, 88, 44, 49, 41, 4, 83, 22, 31, 82, 99, 5, 48, 79, 1, 73, 77, 65, 38, 90, 30, 91, 32, 43, 25, 33, 35, 85, 60, 87, 51, 36, 70, 7, 29, 56, 93, 24, 15, 89, 52, 13, 95, 10, 34, 64, 3, 23, 97)),_
Array(0, 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))
AssertArrayEq(SortedArray(Array("80", "16", "9", "14", "68", "0", "46", "98", "74", "37", "18", "58", "69", "28", "62", "53", "76", "2", "57", "20", "11", "72", "84", "86", "50", "78", "39", "40", "27", "94", "81", "67", "61", "26", "12", "96", "19", "71", "92", "47", "75", "6", "42", "55", "54", "17", "21", "66", "8", "59", "63", "45", "88", "44", "49", "41", "4", "83", "22", "31", "82", "99", "5", "48", "79", "1", "73", "77", "65", "38", "90", "30", "91", "32", "43", "25", "33", "35", "85", "60", "87", "51", "36", "70", "7", "29", "56", "93", "24", "15", "89", "52", "13", "95", "10", "34", "64", "3", "23", "97")),_
Array("0", "1", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "2", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "3", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "4", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "5", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "6", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "7", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "8", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "9", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99"))
' SortInPlace
Dim arr As Variant
arr = Array(5, 7, 9, 5, 4, 2, 1)
SortArrayInPlace(arr)
AssertArrayEq(arr, Array(1, 2, 4, 5, 5, 7, 9))
arr = Array(5, 7, 9, 5, 4, 2, 1, 10, 18, 16)
SortArrayInPlace(arr)
AssertArrayEq(arr, Array(1, 2, 4, 5, 5, 7, 9, 10, 16, 18))
arr = Array(80, 16, 9, 14, 68, 0, 46, 98, 74, 37, 18, 58, 69, 28, 62, 53, 76, 2, 57, 20, 11, 72, 84, 86, 50, 78, 39, 40, 27, 94, 81, 67, 61, 26, 12, 96, 19, 71, 92, 47, 75, 6, 42, 55, 54, 17, 21, 66, 8, 59, 63, 45, 88, 44, 49, 41, 4, 83, 22, 31, 82, 99, 5, 48, 79, 1, 73, 77, 65, 38, 90, 30, 91, 32, 43, 25, 33, 35, 85, 60, 87, 51, 36, 70, 7, 29, 56, 93, 24, 15, 89, 52, 13, 95, 10, 34, 64, 3, 23, 97)
SortArrayInPlace(arr)
AssertArrayEq(arr,_
Array(0, 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))
arr = Array("80", "16", "9", "14", "68", "0", "46", "98", "74", "37", "18", "58", "69", "28", "62", "53", "76", "2", "57", "20", "11", "72", "84", "86", "50", "78", "39", "40", "27", "94", "81", "67", "61", "26", "12", "96", "19", "71", "92", "47", "75", "6", "42", "55", "54", "17", "21", "66", "8", "59", "63", "45", "88", "44", "49", "41", "4", "83", "22", "31", "82", "99", "5", "48", "79", "1", "73", "77", "65", "38", "90", "30", "91", "32", "43", "25", "33", "35", "85", "60", "87", "51", "36", "70", "7", "29", "56", "93", "24", "15", "89", "52", "13", "95", "10", "34", "64", "3", "23", "97")
SortArrayInPlace(arr)
AssertArrayEq(arr,_
Array("0", "1", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "2", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "3", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "4", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "5", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "6", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "7", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "8", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "9", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99"))
' Create N arrays
Dim arrs(1) As Variant
Dim arr2 As Variant
Dim i, j, size As Long
For i=LBound(arrs) To UBound(arrs)
size = Int(Rnd() * 50000) + 50000
Redim arr(size-1)
For j=LBound(arr) To UBound(arr)
arr(j) = Int(Rnd() * 10000) - 5000
Next j
arrs(i) = arr
Next i
Dim t0, t1 As Double
t0 = Now()
For Each arr In arrs
arr2 = SortedArray(arr)
For j=LBound(arr) To UBound(arr)-1
AssertEq(arr2(j) <= arr2(j+1), True)
Next j
Next arr
t1 = Now()
MsgBox(t1 - t0)
t0 = Now()
For Each arr In arrs
SortArrayInPlace(arr)
For j=LBound(arr) To UBound(arr)-1
AssertEq(arr(j) <= arr(j+1), True)
Next j
Next arr
t1 = Now()
MsgBox(t1 - t0)
MsgBox "Shuffle :" & ArrayToString(ShuffledArray(SortedArray(Array(5, 7, 9, 5, 4, 2, 1, 10, 18, 16))))
End Sub
REM
REM Lists
REM
''
'' The ArrayList Type
'' The type of elements may be mixed.
''
Type ArrayList
arr() As Variant
size As Long
End Type
''
'' Create a new ArrayList, given an initial capacity or array of elements.
''
Function NewList(Optional initialCapacityOrArr As Variant) As ArrayList
If IsMissing(initialCapacityOrArr) Then
NewList = NewListWithCapacity(8)
ElseIf IsArray(initialCapacityOrArr) Then
NewList = NewListFromArray(initialCapacityOrArr)
Else
NewList = NewListWithCapacity(initialCapacityOrArr)
End If
End Function
''
'' Create a new ArrayList, given an initial capacity.
''
Function NewListWithCapacity(capacity As Long) As ArrayList
Dim list As ArrayList
Dim arr(capacity - 1) As Variant
list.arr = arr
list.size = 0
NewListWithCapacity = list
End Function
''
'' Create a new ArrayList, given an initial array of elements
''
Function NewListFromArray(arr As Variant) As ArrayList
If LBound(arr) <> 0 Then arr(0) ' trigger an error
Dim list as ArrayList
Dim newArr() As Variant
Dim capacity As Long
If UBound(arr) < 7 Then
capacity = 8
Else
capacity = Round(UBound(arr) * 1,5)
End If
newArr = arr
ReDim Preserve newArr(capacity - 1) As Variant
list.arr = newArr
list.size = UBound(arr) + 1
NewListFromArray = list
End Function
''
'' Update the list capacity
''
Sub SetListCapacity(list As ArrayList, newCapacity As Long)
Dim arr As Variant
If newCapacity < list.size Then Exit Sub
arr = list.arr
Redim Preserve arr(newCapacity) As Variant
list.arr = arr
End Sub
''
'' Append an element to a list
''
Sub AppendListElement(list As ArrayList, element As Variant)
Dim arr() As Variant
_EnsureListCapacity(list, list.size + 1)
list.arr(list.size) = element
list.size = list.size + 1
End Sub
''
'' Ensure list capacity
''
Sub _EnsureListCapacity(list As ArrayList, capacity As Long)
Dim arr As Variant
If capacity <= UBound(list.arr) + 1 Then Exit Sub
arr = list.arr
Redim Preserve arr(capacity * 1.2) As Variant
list.arr = arr
End Sub
''
'' Append an array of elements to a list
''
Sub AppendListElements(list As ArrayList, elements() As Variant)
Dim i, newCapacity, elementsSize As Long
Dim arr() As Variant
If LBound(elements) <> 0 Then elements(0) ' trigger an error
elementsSize = UBound(elements) + 1
_EnsureListCapacity(list, list.size + elementsSize)
For i=0 To elementsSize - 1
list.arr(list.size) = elements(i)
list.size = list.size + 1
Next i
End Sub
''
'' Pop an element from a list
''
Function PopListElement(list As ArrayList) As Variant
PopListElement = list.arr(list.size - 1)
list.size = list.size - 1
End Function
''
'' Get the element of a list at a given index.
''
Function GetListElement(list As ArrayList, index As Long) As Variant
If index >= list.size Then list.arr(-1)
GetListElement = list.arr(index)
End Function
''
'' Set the element of a list at a given index to a value
''
Sub SetListElement(list As ArrayList, index As Long, element As Variant)
If index >= list.size Then list.arr(-1)
list.arr(index) = element
End Sub
''
'' Insert the element at a given index
''
Sub InsertListElement(list As ArrayList, index As Long, element As Variant)
Dim arr() As Variant
Dim i As Long
_EnsureListCapacity(list, list.size + 1)
For i = list.size To index + 1 Step -1
list.arr(i) = list.arr(i - 1)
Next i
list.arr(index) = element
list.size = list.size + 1
End Sub
''
'' Remove the element at a given index
''
Sub RemoveListElement(list As ArrayList, index As Long)
Dim arr() As Variant
Dim i As Long
For i = index To list.size - 2
list.arr(i) = list.arr(i + 1)
Next i
list.size = list.size - 1
End Sub
''
'' Reverse a List
''
Sub ReverseList(list As ArrayList)
Dim arr() As Variant
arr = list.arr
arr = ReversedArray(arr)
list.arr = arr
End Sub
''
'' Sort a List
''
Sub SortList(list As ArrayList)
Dim arr() As Variant
arr = list.arr
arr = SortedArray(arr)
list.arr = arr
End Sub
''
'' Shuffle a List
''
Sub ShuffleList(list As ArrayList)
Dim arr() As Variant
arr = list.arr
arr = ShuffledArray(arr)
list.arr = arr
End Sub
''
'' Copy the list into an array
''
Function ListToArray(list As ArrayList) As Variant
If list.size = 0 Then
ListToArray = Array()
Else
Dim arr() As Variant
arr = list.arr
Redim Preserve arr(list.size - 1)
ListToArray = arr
End If
End Function
''
'' Return the size of a list
''
Function GetListSize(list As ArrayList) As Long
GetListSize = list.size
End Function
''
'' Return True if the list is empty
''
Function ListIsEmpty(list As ArrayList) As Boolean
ListIsEmpty = (list.size = 0)
End Function
''
'' Return the index of element in the list, or -1 if element is not in the list
''
Function ListIndexOf(list As ArrayList, element As Variant) As Long
Dim i As Long
For i=0 To list.size - 1
If list.arr(i) = element Then
ListIndexOf = i
Exit Function
End If
Next i
ListIndexOf = -1
End Function
Function ListLastIndexOf(list As ArrayList, element As Variant) As Long
Dim i As Long
For i=list.size-1 To 0 Step -1
If list.arr(i) = element Then
ListLastIndexOf = i
Exit Function
End If
Next i
ListLastIndexOf = -1
End Function
Function ListToString(list As ArrayList) As String
Dim i As Long
Dim newArr(0 To list.size - 1) As String
For i=0 To list.size - 1
newArr(i) = UnoValueToString(list.arr(i))
Next i
ListToString = "[" & Join(newArr, ", ") & "]"
End Function
Sub ListTests
Dim list As ArrayList
list = NewList(Array(4, 5, 6))
AppendListElement(list, "a")
AppendListElement(list, "b")
AppendListElement(list, "c")
AssertEq(GetListSize(list), 6)
AssertEq(ListIsEmpty(list), False)
AssertEq(ListIndexOf(list, "b"), 4)
AssertEq(ListLastIndexOf(list, "b"), 4)
AssertEq(ListIndexOf(list, "d"), -1)
AppendListElement(list, "d")
AppendListElement(list, 2)
AppendListElement(list, "f")
AppendListElement(list, "g")
AppendListElement(list, "h")
SetListElement(list, 9, "z")
AppendListElements(list, Array("Z", "W", "T"))
InsertListElement(list, 5, "XYZ")
RemoveListElement(list, 10)
AssertArrayEq(ListToArray(list), Array(4, 5, 6, "a", "b", "XYZ", "c", "d", 2, "f", "h", "Z", "W", "T"))
AssertEq(ListToString(list), "[4, 5, 6, ""a"", ""b"", ""XYZ"", ""c"", ""d"", 2, ""f"", ""h"", ""Z"", ""W"", ""T""]")
End Sub
REM
REM Sets
REM
''
'' The HashSet type
''
Type HashSet
typeName As String
map As com.sun.star.container.EnumerableMap
End Type
''
'' Create a new Set of type typeName
''
Function NewSet(typeName As String, Optional arr As Variant) As HashSet
If IsMissing(arr) Then
NewSet = NewEmptySet(typeName)
Else
NewSet = NewSetFromArray(typeName, arr)
End If
End Function
''
'' Create a new empty Set of type typeName
''
Function NewEmptySet(typeName As String) As HashSet
Dim s As HashSet
s.typeName = typeName
s.map = com.sun.star.container.EnumerableMap.create(typeName, "byte")
NewEmptySet = s
End Function
''
'' Create a new Set of type typeName having the elements arr
''
Function NewSetFromArray(typeName As String, arr() As Variant) As HashSet
Dim s As HashSet
s = NewEmptySet(typeName)
AddSetElements(s, arr)
NewSetFromArray = s
End Function
''
'' Add an element to a Set
''
Function AddSetElement(s As HashSet, element As Variant)
s.map.put(CreateUnoValue(s.typeName, element), 1)
End Function
''
'' Add some elements to a Set
''
Sub AddSetElements(s As HashSet, arr() As Variant)
Dim element As Variant
For Each element In arr
AddSetElement(s, element)
Next element
End Sub
''
'' Remove an element from a Set
''
Function RemoveSetElement(s As HashSet, element As Variant)
s.map.remove(CreateUnoValue(s.typeName, element))
End Function
''
'' Return True if the Set contains this element
''
Function SetContains(s As HashSet, element As Variant) As Boolean
Contains = s.map.containsKey(element)
End Function
''
'' Remove a random element from the Set and return it
''
Function TakeSetElement(s As HashSet) As Variant
Dim e As Object
Dim element As Variant
e = s.map.createKeyEnumeration(True)
If e.hasMoreElements() Then
element = e.nextElement()
s.map.remove(element)
TakeSetElement = element
Else
TakeSetElement = Empty
End If
End Function
''
'' Copy the elements of the Set to an Array
''
Function SetToArray(s As HashSet) As Variant
Dim e As Object
e = s.map.createKeyEnumeration(True)
SetToArray = EnumToArray(e)
End Function
''
'' Return the Set size
''
Function GetSetSize(s As HashSet) As Variant
Dim e As Object
e = s.map.createKeyEnumeration(True)
GetSetSize = GetEnumSize(e)
End Function
''
'' Return True if the Set is empty
''
Function SetIsEmpty(s As HashSet) As Variant
Dim e As Object
e = s.map.createKeyEnumeration(True)
SetIsEmpty = Not e.hasMoreElements()
End Function
Function SetToString(s As HashSet) As String
SetToString = "{" & ArrayToString(SetToArray(s)) & "}"
End Function
Sub SetTests
Dim s As HashSet
Dim e As Variant
s = NewEmptySet("string")
AssertEq(SetIsEmpty(s), True)
s = NewSetFromArray("long", Array(1, 3, 5))
AddSetElement(s, 15)
AddSetElement(s, 8)
AddSetElement(s, 3)
AssertArrayEq(SetToArray(s), Array(1, 3, 5, 8, 15))
AssertEq(SetToString(s), "{1, 3, 5, 8, 15}")
AssertEq(GetSetSize(s), 5)
Do While Not SetIsEmpty(s)
e = TakeSetElement(s)
AssertEq(IsEmpty(e), False)
Loop
AssertEq(SetIsEmpty(s), True)
AssertArrayEq(SetToArray(s), Array())
e = TakeSetElement(s)
AssertEq(IsEmpty(e), True)
End Sub
REM
REM Maps
REM
''
'' The HashMap type
''
Type HashMap
keyTypeName As String
valueTypeName As String
map As com.sun.star.container.EnumerableMap
End Type
''
'' Create a new Map.
''
Function NewEmptyMap(keyTypeName As String, valueTypeName As String) As HashSet
Dim m As HashMap
m.keyTypeName = keyTypeName
m.valueTypeName = valueTypeName
m.map = com.sun.star.container.EnumerableMap.create(keyTypeName, valueTypeName)
NewEmptyMap = m
End Function
''
'' Remove a key-value pair in the Map
''
Function PutMapElement(m As HashMap, key As Variant, value As Variant)
m.map.put(CreateUnoValue(m.keyTypeName, key), CreateUnoValue(m.valueTypeName, value))
End Function
''
'' Remove a Map element by key
''
Function RemoveMapElement(m As HashMap, key As Variant) As Variant
RemoveMapElement = m.map.remove(CreateUnoValue(m.keyTypeName, key))
End Function
''
'' Return True if the Map contains this Key
''
Function MapContains(m As HashMap, key As Variant) As Boolean
MapContains = m.map.containsKey(CreateUnoValue(m.keyTypeName, key))
End Function
''
'' Return the value mapped to this key, or raise an exception
''
Function GetMapElement(m As HashMap, key As Variant) As Variant
GetMapElement = m.map.get(CreateUnoValue(m.keyTypeName, key))
End Function
''
'' Return the value mapped to this key, or a default value
''
Function GetMapElementOrDefault(m As HashMap, key As Variant, default As Variant) As Variant
If m.map.containsKey(CreateUnoValue(m.keyTypeName, key)) Then
GetMapElementOrDefault = m.map.get(CreateUnoValue(m.keyTypeName, key))
Else
GetMapElementOrDefault = default
End If
End Function
''
'' Return an Array of the keys.
''
Function MapKeysToArray(m As HashMap) As Variant
Dim e As Object
e = m.map.createKeyEnumeration(True)
MapKeysToArray = EnumToArray(e)
End Function
''
'' Return an Array of the values.
''
Function MapValuesToArray(m As HashMap) As Variant
Dim e As Object
e = m.map.createValueEnumeration(True)
MapValuesToArray = EnumToArray(e)
End Function
''
'' Return an Set of the keys.
''
Function MapKeysToSet(m As HashMap) As Variant
Dim s As HashSet
s = NewEmptySet(m.keyTypeName)
e = m.map.createKeyEnumeration(True)
Do While e.hasNext()
AddSetElement(e.nextElement())
Loop
MapKeysToSet = s
End Function
''
'' Return the Map size
''
Function GetMapSize(m As HashMap) As Variant
Dim e As Object
e = m.map.createKeyEnumeration(True)
GetMapSize = GetEnumSize(e)
End Function
''
'' Return True if the Map is empty
''
Function MapIsEmpty(m As HashMap) As Variant
Dim e As Object
e = m.map.createKeyEnumeration(True)
MapIsEmpty = Not e.hasMoreElements()
End Function
''
'' Return a copy of the map
''
Function CopyMap(m As HashMap) As HashMap
Dim newM As HashMap
Dim e, p As Variant
newM = NewEmptyMap(m.keyTypeName, m.valueTypeName)
e = m.map.createElementEnumeration(True)
Do While e.hasMoreElements()
p = e.nextElement()
PutMapElement(newM, p.First, p.Second)
Loop
CopyMap = newM
End Function
''
'' Return a merged map
''
Function MergeMaps(m1 As HashMap, m2 As HashMap) As HashMap
Dim newM As HashMap
Dim e, p As Variant
newM = NewEmptyMap(m1.keyTypeName, m1.valueTypeName)
e = m1.map.createElementEnumeration(True)
Do While e.hasMoreElements()
p = e.nextElement()
PutMapElement(newM, p.First, p.Second)
Loop
e = m2.map.createElementEnumeration(True)
Do While e.hasMoreElements()
p = e.nextElement()
PutMapElement(newM, p.First, p.Second)
Loop
MergeMaps = newM
End Function
Function MapToString(m As HashMap) As String
Dim i As Long
Dim e, p, arr As Variant
e = m.map.createElementEnumeration(True)
arr = EnumToArray(e)
Dim newArr(LBound(arr) To UBound(arr)) As String
For i=LBound(arr) To UBound(arr)
p = arr(i)
newArr(i) = UnoValueToString(p.First) & ": " & UnoValueToString(p.Second)
Next i
MapToString = "{" & Join(newArr, ", ") & "}"
End Function
Sub MapTests
Dim m As HashMap
m = NewEmptyMap("string", "long")
AssertEq(MapIsEmpty(m), True)
PutMapElement(m, "a", 1)
AssertEq(MapIsEmpty(m), False)
AssertEq(GetMapSize(m), 1)
PutMapElement(m, "b", 2)
PutMapElement(m, "c", 3)
AssertArrayEq(MapKeysToArray(m), SortedArray(Array("a", "b", "c")))
AssertArrayEq(MapValuesToArray(m), SortedArray(Array(1, 2, 3)))
AssertEq(GetMapSize(m), 3)
PutMapElement(m, "d", 4)
AssertEq(GetMapElementOrDefault(m, "e", 20), 20)
AssertEq(MapContains(m, "b"), True)
AssertEq(GetMapSize(m), 4)
AssertEq(MapToString(m), "{""a"": 1, ""b"": 2, ""c"": 3, ""d"": 4}")
AssertEq(GetMapElement(m, "b"), 2)
AssertEq(RemoveMapElement(m, "b"), 2)
AssertEq(MapContains(m, "b"), False)
AssertEq(GetMapSize(m), 3)
AssertRaises("GetMapElement", Array(m, "b"))
Dim m2 As HashMap
m2 = NewEmptyMap("string", "long")
PutMapElement(m2, "foo", 100)
m = MergeMaps(m, m2)
AssertEq(MapToString(m), "{""a"": 1, ""c"": 3, ""d"": 4, ""foo"": 100}")
End Sub
Sub AllTests()
AssertTests()
ArrayTests()
ListTests()
SetTests()
MapTests()
End Sub
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment