Code archives/Miscellaneous/String banks/data buffers

This code has been declared by its author to be Public Domain code.

Download source code

String banks/data buffers by Yasha2013
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

virtlands2013
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.


Yasha2013
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.


virtlands2013
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


Yasha2013
...I was thinking of Ascii85, yes. Whoops.


Code Archives Forum