Code archives/Miscellaneous/String banks/data buffers
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This code requires MikhailV's free FastPointer DLL. This tiny library lets you treat strings exactly as you would a Blitz bank: peek and poke bytes, shorts, ints and floats. Strings make a great way to store binary data: they're basically the same as banks, a flat data buffer, but you don't need to worry about freeing them! Unfortunately, they have a couple of major drawbacks: it's really slow to extract data as characters using the Mid command, and it's even more annoying to set data by building up a whole new string - it's even slower, and you have to return it, pass it back to wherever the old string was, etc. No longer! This library provides the eight Peek and Poke functions familiar from banks, but for use with strings. The Peek functions are nothing that can't be done in pure Blitz code using Mid, but are implemented (hopefully) faster here thanks to dark pointer magic. This makes it more convenient to store data in strings to access later, because accessing the data becomes a little bit easier. The Poke functions, on the other hand... provide something new: the ability to modify strings in-place, exactly as you would poke to a bank! Normally, Blitz strings are immutable, and when you want to change a value in your highly-complex string data type, you need to recreate and return a whole new string with the new data. But these new Poke functions mean that the string you pass into the function will be modified by it, exactly as a bank would be! This means it's now possible to set the character data within existing strings, without the massive overhead of building new strings! This is really great for speeding up code that relies on modifying very large string structures, which would take a lot of time and memory to recreate. Tiny example: Include "StringBanks.bb" Print Hex(StrPeekShort("abcde", 1)) : Print "" Local s$ = String("-", 8) ;Simplest way to pre-create a string of given length StrPokeFloat s, 0, 42.6 StrPokeFloat s, 4, 87.19 Print s Print StrPeekFloat(s, 0) Print StrPeekFloat(s, 4) WaitKey : End As you can see, s$ changed, even though it was never set. While this violates the Blitz Basic notion that strings should be "value types" like hardware numbers, it's really, really useful. You can effectively use strings as garbage-collected banks with this code. The other bank functions - CreateBank, CopyBank etc. are not provided because they're kinda trivial. (To create a new string of a dynamic length for poking values into, i.e. to CreateBank, use the 'String' function.) | |||||
; Fast string data access (Blitz3D/+) ;===================================== ; Requires FastPointer DLL (free): http://www.fastlibs.com/index.php ; Offsets of char data, data length, and buffer size within a Blitz string Const FSTRING_CHAR_OFFSET = 4, FSTRING_LEN_OFFSET = 8, FSTRING_MAX_OFFSET = 12 Type FSTRING_Wrapper_ ;Singleton wrapper type, used to get pointer only Field s$ End Type Global FSTRING_private_WSlot_.FSTRING_Wrapper_, FSTRING_private_SPtr_ ;Singleton instance ; Retrieve the byte at the given offset from a string buffer Function StrPeekByte(s$, offset) Return Asc(Mid(s, offset + 1, 1)) ;Trivial, but here for completeness End Function ; Retrieve the short int at the given offset from a string buffer Function StrPeekShort(s$, offset) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 2) RuntimeError "StrPeekShort: offset out of range" EndIf Return MemoryFastPeekShort(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset) End Function ; Retrieve the integer at the given offset from a string buffer Function StrPeekInt(s$, offset) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 4) RuntimeError "StrPeekInt: offset out of range" EndIf Return MemoryFastPeekInt(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset) End Function ; Retrieve the float at the given offset from a string buffer Function StrPeekFloat#(s$, offset) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 4) RuntimeError "StrPeekFloat: offset out of range" EndIf Return MemoryFastPeekFloat(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset) End Function ; Destructively set the byte at the given offset within a string buffer Function StrPokeByte(s$, offset, val) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 1) RuntimeError "StrPokeByte: offset out of range" EndIf Return MemoryFastPokeByte(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset, val) End Function ; Destructively set the short int at the given offset within a string buffer Function StrPokeShort(s$, offset, val) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 2) RuntimeError "StrPokeShort: offset out of range" EndIf Return MemoryFastPokeShort(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset, val) End Function ; Destructively set the integer at the given offset within a string buffer Function StrPokeInt(s$, offset, val) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 4) RuntimeError "StrPokeInt: offset out of range" EndIf Return MemoryFastPokeInt(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset, val) End Function ; Destructively set the float at the given offset within a string buffer Function StrPokeFloat(s$, offset, val#) If FSTRING_private_WSlot_ = Null FSTRING_private_WSlot_ = New FSTRING_Wrapper_ FSTRING_private_SPtr_ = TypePointer(FSTRING_private_WSlot_) EndIf FSTRING_private_WSlot_\s = s Local strPtr = MemoryFastPeekInt(FSTRING_private_SPtr_) If offset < 0 Or offset > (MemoryFastPeekInt(strPtr + FSTRING_LEN_OFFSET) - 4) RuntimeError "StrPokeFloat: offset out of range" EndIf Return MemoryFastPokeFloat(MemoryFastPeekInt(strPtr + FSTRING_CHAR_OFFSET) + offset, val) End Function ;~IDEal Editor Parameters: ;~F#17#1F#24#32#40#4E#5C#6A#78 ;~C#Blitz3D |
Comments
| ||
This is an excellent idea of yours of altering strings with pointers and stuff [FastPointer DLL...] { I previously downloaded the FastPointer, and purchased the FastText option. } There are so many valuable things that can be stored in strings, such as pictures (BMP,PNG,etc), other programs, UTF8 strings, unicode strings, .... If you'd like to read about UTF8, see this link: http://en.wikipedia.org/wiki/UTF-8 The FastText Extension allows the use of UTF8, and therefore it allows a way to represent all unicodes. http://fastlibs.com/ You can store an entire program (or DLL) in a string and then it can be 'extracted' back to a file. In the case where unusual numbers must be stored in a string (such as control characters), then first use a form like s$ = String("-", 800), and then I guess come back after the program is made, and use a hex editor to force the real data in. Have you ever noticed that if you use too many "Data ..." statements in your program, that it crashes? Well I found out the hard way that it does; Using strings to store data instead shows great promise. By the way, using s$=chr$(7)+chr$(8)+chr$(9)+...+chr$(that) is the really clumsy way to store data in a string, (therefore, use hex-editor). And what if the string has a chr$(34)= (") in it? Imagine the chaos that would cause, consider the scenario: S$ = " a very very long string with something "fishy" in it". NOW WHAT? ------------------------------------- Some nice things about strings though: (a) They are compact, and store data one byte at a time. (b) You can use the INSTR(s,sub,n) function with strings. I definitely plan to use the 'Yasha' code. |
| ||
And what if the string has a chr$(34)= (") in it? There's no problem with a string containing Chr(34) - the double quote is just syntax for the B3D compiler and has no bearing on how strings work at runtime. Or do you mean for generating Data statements automatically, so that everything also has to be valid B3D source? The other unprintable characters (or newline) will also cause problems - you could get around this by storing the data in the Data blocks in base-80 or something like that. Just add a conversion step before they're actually used. |
| ||
That's clever, you said "base-80". Now you've stirred up a whole hornet's nest of stuff. Someone will have to dedicate an entire topic to that. ;) Binary to Text Encoding http://en.wikipedia.org/wiki/Binary-to-text_encoding Ascii85: http://en.wikipedia.org/wiki/Ascii85 Base 64: http://stackoverflow.com/questions/201479/what-is-the-use-of-base-64-encoding Base 96: http://gendev.spritesmind.net/forum/viewtopic.php?p=17643 Base 80: ??? http://z13.invisionfree.com/DozensOnline/index.php?showtopic=757 |
| ||
...I was thinking of Ascii85, yes. Whoops. |
Code Archives Forum