Hey!
I'm quite new to QB64, although I dabbled with some QuickBasic a few decades ago.
It seems that QB64 has no "list" data type, but only arrays. Since I have an irrational fear of arrays, I am experimenting with creating a "StringList" container instead, which behind the scenes is based on arrays, but will keep me away from most of the work related to dealing with array sizes etc. and provides a few nifty functions for handling the list. Specifically, the code adds a type, "StringList", which relies on a 2d array with a defined max size. It might not be the most memory efficient solution, since each array is max'ed at the size of the largest StringList used, but at least in some basic testing it seems to work decently.
Current functions are (not tested extensively, so some of them might be buggy):
Before I spend too much time on this, I'd be curious to hear from someone with more QB64 experience, whether this concept is solid and whether something better already exists? I can't imagine that I am the first to try something like this, and maybe there is some big disadvantage, that I haven't yet discovered?
What do you think?
Here's the code as it looks right now:
And here's a quick, messy example of some the functions:
I'm quite new to QB64, although I dabbled with some QuickBasic a few decades ago.
It seems that QB64 has no "list" data type, but only arrays. Since I have an irrational fear of arrays, I am experimenting with creating a "StringList" container instead, which behind the scenes is based on arrays, but will keep me away from most of the work related to dealing with array sizes etc. and provides a few nifty functions for handling the list. Specifically, the code adds a type, "StringList", which relies on a 2d array with a defined max size. It might not be the most memory efficient solution, since each array is max'ed at the size of the largest StringList used, but at least in some basic testing it seems to work decently.
Current functions are (not tested extensively, so some of them might be buggy):
- StringList_Init (ListName) - Initialize the stringlist after DIM'ing it
- StringList_AddItem (ListName, String) - Add a new string as the last item
- StringList_InsertItem (ListName, String, Pos) - Insert a new string at a specified index/position
- StringList_RemoveItem (ListName, ItemNo/Index) - Remove the specified item no.
- StringList_SetItem (ListName, ItemNo, String) - Set/replace a specific list item
- StringList_Clear (ListName) - Clear the entire string list
- StringList_GetItem$ (ListName, index) - Get the text at item no./index
- StringList_ItemCount& (sl As StringList) - Return the number of items in the list
- StringList_Text$ (sl As StringList) - Return the entire contents of the stringlist in one string
- StringList_Swap (ListName, indexA, indexB) - Swap two items in the list
- StringList_SaveToFile%% (ListName, filename) - Save the string list to the specified plain text file
- StringList_LoadFromFile%% (ListName, filename) - Load list from the specified plain text file
Before I spend too much time on this, I'd be curious to hear from someone with more QB64 experience, whether this concept is solid and whether something better already exists? I can't imagine that I am the first to try something like this, and maybe there is some big disadvantage, that I haven't yet discovered?
What do you think?
Here's the code as it looks right now:
Code: (Select All)
Type StringList
id As Long
End Type
'==========================================================================
' Subs and Functions
'--------------------------------------------------------------------------
'__________________________________________________________________________
' To limit potential memory issues, do not set too high!
Const SL_MAX_LISTS = 10 ' Maximum number of lists
Const SL_MAX_ITEMS = 1000000 ' Maximum items per list
' Shared storage
Dim Shared SL_Data(1 To SL_MAX_LISTS, 1 To SL_MAX_ITEMS) As String
Dim Shared SL_Count(1 To SL_MAX_LISTS) As Long
Dim Shared SL_Used(1 To SL_MAX_LISTS) As _Byte
'__________________________________________________________________________
' Initialize a StringList
Sub StringList_Init (sl_id As StringList)
Dim i As Long
For i = 1 To SL_MAX_LISTS
If SL_Used(i) = 0 Then
SL_Used(i) = -1
SL_Count(i) = 0
sl_id.id = i
Exit Sub
End If
Next
Print "No free StringList slots!"
End Sub
'__________________________________________________________________________
' Add item to end
Sub StringList_AddItem (sl_id As StringList, txt_str As String)
If SL_Count(sl_id.id) >= SL_MAX_ITEMS Then
Print "Error: List exceeded maximum items."
Exit Sub
End If
SL_Count(sl_id.id) = SL_Count(sl_id.id) + 1
SL_Data(sl_id.id, SL_Count(sl_id.id)) = txt_str
End Sub
'__________________________________________________________________________
' Insert item at position
Sub StringList_InsertItem (sl_id As StringList, txt_str As String, insertAt As Long)
Dim i As Long
If insertAt < 1 Or insertAt > SL_Count(sl_id.id) + 1 Then
Print "Error: Invalid insert sl_index."
Exit Sub
End If
If SL_Count(sl_id.id) >= SL_MAX_ITEMS Then
Print "Error: List exceeded maximum items."
Exit Sub
End If
For i = SL_Count(sl_id.id) To insertAt Step -1
SL_Data(sl_id.id, i + 1) = SL_Data(sl_id.id, i)
Next
SL_Data(sl_id.id, insertAt) = txt_str
SL_Count(sl_id.id) = SL_Count(sl_id.id) + 1
End Sub
'__________________________________________________________________________
' Remove item at sl_index
Sub StringList_RemoveItem (sl_id As StringList, sl_index As Long)
Dim i As Long
If sl_index < 1 Or sl_index > SL_Count(sl_id.id) Then
Print "Error: Invalid remove sl_index."
Exit Sub
End If
For i = sl_index To SL_Count(sl_id.id) - 1
SL_Data(sl_id.id, i) = SL_Data(sl_id.id, i + 1)
Next
SL_Data(sl_id.id, SL_Count(sl_id.id)) = ""
SL_Count(sl_id.id) = SL_Count(sl_id.id) - 1
End Sub
'__________________________________________________________________________
' Replace item at sl_index
Sub StringList_SetItem (sl_id As StringList, sl_index As Long, txt_str As String)
If sl_index < 1 Or sl_index > SL_Count(sl_id.id) Then
Print "Error: Invalid sl_index in SetItem."
Exit Sub
End If
SL_Data(sl_id.id, sl_index) = txt_str
End Sub
'__________________________________________________________________________
' Clear entire list
Sub StringList_Clear (sl_id As StringList)
Dim i As Long
For i = 1 To SL_Count(sl_id.id)
SL_Data(sl_id.id, i) = ""
Next
SL_Count(sl_id.id) = 0
End Sub
'__________________________________________________________________________
' Get item at sl_index
Function StringList_GetItem$ (sl_id As StringList, sl_index As Long)
If sl_index < 1 Or sl_index > SL_Count(sl_id.id) Then Exit Function
StringList_GetItem = SL_Data(sl_id.id, sl_index)
End Function
'__________________________________________________________________________
' Item count
Function StringList_ItemCount& (sl_id As StringList)
StringList_ItemCount = SL_Count(sl_id.id)
End Function
'__________________________________________________________________________
' Full text (all items)
Function StringList_Text$ (sl_id As StringList)
Dim i As Long
Dim result As String
For i = 1 To SL_Count(sl_id.id)
result = result + SL_Data(sl_id.id, i)
If i < SL_Count(sl_id.id) Then result = result + Chr$(10)
Next
StringList_Text = result
End Function
'__________________________________________________________________________
' Swap two items
Sub StringList_Swap (sl_id As StringList, sl_indexA As Long, sl_indexB As Long)
Dim tmp As String
If sl_indexA < 1 Or sl_indexA > SL_Count(sl_id.id) Then Exit Sub
If sl_indexB < 1 Or sl_indexB > SL_Count(sl_id.id) Then Exit Sub
If sl_indexA = sl_indexB Then Exit Sub
tmp = SL_Data(sl_id.id, sl_indexA)
SL_Data(sl_id.id, sl_indexA) = SL_Data(sl_id.id, sl_indexB)
SL_Data(sl_id.id, sl_indexB) = tmp
End Sub
'__________________________________________________________________________
' Save StringList to file
Function StringList_SaveToFile%% (sl_id As StringList, sl_filename As String)
Dim i As Long
Dim ff As Integer
' Reject empty sl_filename
If Len(sl_filename) = 0 Then
StringList_SaveToFile = _FALSE
Exit Function
End If
' Get a free file handle
ff = FreeFile
' Try opening file
Open sl_filename For Output As #ff
' If OPEN failed, QB64 sets ERR
If Err <> 0 Then
StringList_SaveToFile = _FALSE
Exit Function
End If
' Write items
For i = 1 To SL_Count(sl_id.id)
Print #ff, SL_Data(sl_id.id, i)
Next
Close #ff
StringList_SaveToFile = _TRUE
End Function
'__________________________________________________________________________
' Load StringList from file
Function StringList_LoadFromFile%% (sl_id As StringList, sl_filename As String)
Dim ff As Integer
Dim lineIn As String
' Validate sl_filename
If Len(sl_filename) = 0 Then
StringList_LoadFromFile = _FALSE
Exit Function
End If
' File must exist
If _FileExists(sl_filename) = 0 Then
StringList_LoadFromFile = _FALSE
Exit Function
End If
' Clear current contents
StringList_Clear sl_id
' Open file safely
ff = FreeFile
Open sl_filename For Input As #ff
' Check for open failure
If Err <> 0 Then
StringList_LoadFromFile = _FALSE
Exit Function
End If
' Read file
Do Until EOF(ff)
If SL_Count(sl_id.id) >= SL_MAX_ITEMS Then Exit Do
Line Input #ff, lineIn
SL_Count(sl_id.id) = SL_Count(sl_id.id) + 1
SL_Data(sl_id.id, SL_Count(sl_id.id)) = lineIn
Loop
Close #ff
StringList_LoadFromFile = _TRUE
End Function
And here's a quick, messy example of some the functions:
Code: (Select All)
' First DIM the lists
Dim L As StringList
Dim N As StringList
' Remember to initialize the lists
StringList_Init L
StringList_Init N
' Add some test items to the stringlist:
StringList_AddItem L, "One"
StringList_AddItem L, "Two"
StringList_AddItem L, "Three"
' Add items to numeric list
'For i = 1 To 10
'StringList_AddItem N, Str$(i)
'Next
StringList_AddItem N, "1"
StringList_AddItem N, "2"
StringList_AddItem N, "3"
StringList_AddItem N, "4"
StringList_AddItem N, "5"
StringList_AddItem N, "6"
StringList_AddItem N, "7"
StringList_AddItem N, "8"
StringList_AddItem N, "9"
StringList_AddItem N, "10"
' Manipulate text list
StringList_InsertItem L, "Inserted", 2
StringList_SetItem L, 3, "Replaced"
StringList_RemoveItem L, 1
StringList_AddItem N, "11"
StringList_AddItem N, "12"
StringList_AddItem N, "13"
Print "Text List:"
Print StringList_Text(L)
Print , "Count is: " + Str$(StringList_ItemCount(L))
Print
Print "Numeric List:"
Print StringList_Text(N)
Print , "Count is: " + Str$(StringList_ItemCount(N))
If StringList_SaveToFile(N, "myexport-tempdelete.txt") = _TRUE Then
Print "All saved!"
Else
Print "Not saved!"
End If

