pharoah | Dynamic list implementation
Well, here's my first module. Hope it's useful to everyone. The idea is to provide you with the ability to create dynamic data structures in Qbasic (e.g. lists that can be resized). Since strings are the only dynamic Qbasic datatype, I'm using them to store a list of elements, which you can add to, remove from, or retrieve by index. Having a dynamic list type makes writing certain kinds of code much easier, as I'm sure you'll see.
Strlists don't have to only store strings. You can use them to store integer values in a compact way using the MKI$ and CVI functions, and similar functions for other data types as well.
The code is well commented, but please post any questions or bugs you may have. Most of the comments begin with a double apostrophe, because they are meant to be read by a documentation generator for Qbasic which I haven't finished yet. Nonetheless, I hope they're helpful.
''Package: strlist (String List)
''Version: 1.0
''By: Pharoah
''Overview:
'' This package provides a way to create and manipulate dynamic
'' lists of variable length strings. First, create an empty strlist
'' using the strlist$() function, and assign it to a string. Then,
'' keep passing the same list into the various other list methods to
'' manipulate it.
''Limitations:
'' Strlist items can be a maximum of 32 767 bytes in length, and there
'' can only be 32 767 elements in a list. The total size of the list
'' itself is limited by the implementation of BASIC.
''Explanation:
'' Strlists are essentially linked lists built into Qbasic strings.
'' At the beginning of each strlist, there is a 2 byte integer
'' specifying its number of elements. Following that are the actual data
'' elements, which consist of 2 byte lengths followed by data.
DECLARE FUNCTION strlist$ ()
DECLARE FUNCTION strlist.count% (list$)
DECLARE SUB strlist.add (list$, index%, value$)
DECLARE FUNCTION strlist.remove$ (list$, index%)
DECLARE SUB strlist.set (list$, index%, value$)
DECLARE FUNCTION strlist.get$ (list$, index%)
DECLARE SUB strlist.push (list$, value$)
DECLARE FUNCTION strlist.pop$ (list$)
FUNCTION strlist$
strlist$ = MKI$(0)
END FUNCTION
SUB strlist.add (list$, index%, value$)
''Adds an item to the list after the specified index.
''If index = 0, prepends a value to the list.
c% = strlist.count%(list$)
''Throws: an illegal function call on invalid index
IF index% < 0 OR index% > c% THEN ERROR 5
p% = 3
FOR i% = 1 TO index%
l% = CVI(MID$(list$, p%, 2))
p% = p% + 2 + l%
NEXT i%
list$ = MKI$(c% + 1) + MID$(list$, 3, p% - 3) + MKI$(LEN(value$)) + value$ + MID$(list$, p%)
END SUB
FUNCTION strlist.count% (list$)
''Returns the number of elements in a strlist
strlist.count% = CVI(LEFT$(list$, 2))
END FUNCTION
FUNCTION strlist.get$ (list$, index%)
''Gets an element from the given list using the one based index
c% = strlist.count%(list$)
''Throws: an illegal function call on invalid index
IF index% < 1 OR index% > c% THEN ERROR 5
p% = 3
FOR i% = 1 TO index% - 1
l% = CVI(MID$(list$, p%, 2))
p% = p% + 2 + l%
NEXT i%
l% = CVI(MID$(list$, p%, 2))
strlist.get$ = MID$(list$, p% + 2, l%)
END FUNCTION
FUNCTION strlist.pop$ (list$)
''Removes an element from the end of a strlist
c% = CVI(LEFT$(list$, 4)) ' Get a count
''Throws: an illegal function call on stack underflow
IF c% = 0 THEN ERROR 5
' Find the last node
p% = 3
FOR i% = 1 TO c% - 1
l% = CVI(MID$(list$, p%, 2))
p% = p% + 2 + l%
NEXT i%
strlist.pop$ = MID$(list$, p% + 2)
list$ = MKI$(c% - 1) + MID$(list$, 3, p% - 3) ' Rebuild list
END FUNCTION
SUB strlist.push (list$, value$)
''Adds an element to the end of a strlist
list$ = MKI$(CVI(LEFT$(list$, 2)) + 1) + MID$(list$, 3) + MKI$(LEN(value$)) + value$
END SUB
FUNCTION strlist.remove$ (list$, index%)
''Removes a value from the strlist at the given one based index
c% = strlist.count%(list$)
''Throws: an illegal function call on invalid index
IF index% < 1 OR index% > c% THEN ERROR 5
p% = 3
FOR i% = 1 TO index% - 1
l% = CVI(MID$(list$, p%, 2))
p% = p% + 2 + l%
NEXT i%
l% = CVI(MID$(list$, p%, 2))
strlist.remove$ = MID$(list$, p% + 2, l%)
list$ = MKI$(c% - 1) + MID$(list$, 3, p% - 3) + MID$(list$, p% + 2 + l%)
END FUNCTION
SUB strlist.set (list$, index%, value$)
''Sets an element in the given list using the one based index
c% = strlist.count%(list$)
''Throws: an illegal function call on invalid index
IF index% < 1 OR index% > c% THEN ERROR 5
p% = 3
FOR i% = 1 TO index% - 1
l% = CVI(MID$(list$, p%, 2))
p% = p% + 2 + l%
NEXT i%
l% = CVI(MID$(list$, p%, 2))
list$ = LEFT$(list$, p% - 1) + MKI$(LEN(value$)) + value$ + MID$(list$, p% + 2 + l%)
END SUB
| 2011-04-13 | 12:57 AM |