Home | Reviews | GUIpedia | Forum | Fun500


pharoahDynamic 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-1312:57 AM

HorvatMRe:Dynamic list implementation
This is great! I've been thinking about doing such a thing myself, but you've just made my job way easier :)
2011-04-1311:12 AM

ToddRe:Dynamic list implementation
That's clever! I was going to do a linked-list but this works just as well.
2011-04-132:18 PM

pharoahRe:Dynamic list implementation
In Freebasic I'd imagine it's better to do a linked list, because strings are allocated continuously, so reallocating the entire list each time will be slower. Unfortunately, there's no convenient way to work with pointers and allocate chunks of memory in good ol' Qbasic (that I know of, at least).
2011-04-133:27 PM

HorvatMRe:Dynamic list implementation
Here's a function that might be useful: FUNCTION strlist.find% (list$, value$) 'Searches list$ for value$ and returns its index if found or 0 otherwise. FOR i% = 1 TO strlist.count(list$) IF strlist.get$(list$, i%) = value$ THEN strlist.find% = i% EXIT FUNCTION END IF NEXT i% END FUNCTION
2011-06-258:46 AM

Code


2021 Brandon Cornell