My current project requires me to QUICKLY insert and delete strings in a one dimensional array. The array can be many thousands of elements and the strings can be from zero length to a several hundred bytes.
Moving most of the strings in an array can take time.
To speed things up when inserting and deleting elements I decided to adjust the string pointer table, the base of which is returned by @Array$() and has an array of N+1 long pointers if the string array has been dimensioned with ‘N’ elements.
Having made this work in a specific application I wanted to make the solution more general and wrote the two procedures here; which do what I want.
Code: Select all
; WARNING: Experimental code; untidy, untested and possibly unsafe
; ================================================================
; Declare Procedures
Declare.l InsertS(*BaseAddress,Offset.l)
Declare.l DeleteS(*BaseAddress,Offset.l)
Declare.l ShowData()
; Create string array with some data
Global Elements ; Needed gor testing
Elements.l = 11
Dim a$(Elements) ; Produces a$(0) to a$(11)
; Some test data
a$(0)="Start"
a$(1)="Tom"
a$(3)="Harry"
a$(6)="Six"
a$(Elements)="End"
*t = @a$() ; LEGAL : Base address of array of pointers to strings
Debug "Dim ?? "+Str(PeekL(*t-8)) ; SUSPECT :For a one dimesioned array this contains the array size
Debug ""
ShowData()
Debug DeleteS(@a$(),3) ; Delete element number
ShowData()
z = 1
Debug InsertS(@a$(),z) ; Insert element number
a$(z)="New item"
ShowData()
End
Procedure InsertS(*BaseAddress,Offset.l)
; Starting at the specified element move
; all the string pointers up by one
Protected *a, *b, Elements.l, x.l, t.l, Result
Result = 1 ; Default to OK
Elements = PeekL(*BaseAddress-8) ; Find # of elements ****
If (Offset>0) And (Offset<=Elements) ; Check the Offset is in range
*a = Elements ; Build pointer to last table entry
*a * 4
*a + *BaseAddress
*b = *a - 4
Offset + 1 ; Move pointers UP...
For x = Elements To Offset Step-1
t = PeekL(*b)
PokeL(*a,t)
*a - 4
*b - 4
Next
PokeL(*a,0) ; NULL pointer = no string asigned at insert point
Else
Result=0
EndIf
ProcedureReturn Result
EndProcedure
Procedure DeleteS(*BaseAddress,Offset.l)
Protected *a, *b, Elements.l, x.l, t.l, Result
Result=1
Elements = PeekL(*BaseAddress-8) ; ****
If (Offset>=0) And (Offset<Elements)
*a = Offset
*a * 4
*a + *BaseAddress
*b = *a + 4
Elements - 1
For x = Offset To Elements
t = PeekL(*b)
PokeL(*a,t)
*a + 4
*b + 4
Next
PokeL(*a,0)
Else
Result=0
EndIf
ProcedureReturn Result
EndProcedure
Procedure ShowData()
; Show the pointer values for the array and the string where they point
*t = @a$() ; Base address of pointers
For n = 0 To Elements ;
*a = PeekL(*t+(n*4)) ; Get the pointer value
d$=Str(n)+" "+Hex(*a) ; Start result string
If *a ; If valid pointer...
d$+" >"+PeekS(*a) ; add the string
EndIf
Debug d$ ; Show result
Next
Debug "============================"
EndProcedure
Both procedures require the size of the array which I could pass as a variable, but it would be neater if they could find it themselves. See the lines marked ‘*****” in the listings.
Three questions:
1. Is the structure of PB stable enough for me to find the size of the array in this way?
2. Are there any published notes regarding the way single and multi-dimensioned arrays are stored in memory?
3. The InsertS(…) procedure will orphan the last string in the array. Will this present a problem when / if PB tidies up its string space? (I well remember the complex Garbage Collect functions in the early Commodore Basics
