Code archives/Algorithms/Single Byte Arrays
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
All numerical values stored in Blitz variables are stored as signed, long Integers. This means, each uses 4 bytes of memory even if the value of the variable never requires more than a single byte. Also, typically, Blitz Arrays are compiled first and memory reserved even if they are never fully used. The code here can be used instead of the Dim() function or even Global BlitzArray[] function to create single or two dimensional arrays where the array elements each use up only a single byte. Applications may be for example, A* pathfinding cell data or character ability stats etc. | |||||
;Single-Byte Array functions by PJ 2015 ;Example: a=DefineArray(16777215) Print "Please check memory" WaitKey() FreeArray a Dim b(16777215) Print "Please check memory again" WaitKey() End ;Declarations Type Array Field ArrayBankHandle Field ArrayX Field ArrayY End Type ;Functions Function DefineArray(x=1,y=1) y=Abs(y) x=Abs(x) If (Not (x Or y)) RuntimeError "Array must have dimensions" End If Local NewArray.Array=New Array NewArray\ArrayX=x NewArray\ArrayY=y NewArray\ArrayBankHandle=CreateBank(x*y) Return Handle(NewArray) End Function Function SetArrayElement(Array, Value, x=1, y=1) Local Instance.Array=Object.Array(Array) Local Reference=ArrayReference(x,y,Instance\ArrayX) PokeByte Instance\ArrayBankHandle,Reference,Value End Function Function GetArrayElement(Array,x=1,y=1) Local Instance.Array=Object.Array(Array) Local Reference=ArrayReference(x,y,Instance\ArrayX) Local Element=PeekByte(Instance\ArrayBankHandle,Reference) Return Element End Function Function ResizeArray(Array,x,y=1) Local Instance.Array=Object.Array(Array) Local OldSize=BankSize(Instance\ArrayBankHandle) Local NewSize=(x*y) If (NewSize=OldSize) Return End If If (NewSize<OldSize) Local Byte For Byte=NewSize To OldSize-1 PokeByte Instance\ArrayBankHandle,Byte,0 Next OldSize=NewSize End If Local NewBank=CreateBank(NewSize) CopyBank Instance\ArrayBankHandle,0,NewBank,0,OldSize-1 FreeBank Instance\ArrayBankHandle Instance\ArrayBankHandle=NewBank Instance\ArrayX=x Instance\ArrayY=y End Function Function FreeArray(Array) Local Instance.Array=Object.Array(Array) FreeBank Instance\ArrayBankHandle Instance\ArrayX=0 Instance\ArrayY=0 Delete Instance End Function Function ArrayReference(x,y,xmax) Local Ref=y-1 Ref=Ref*xmax Ref=Ref+x Ref=Ref-1 Return Ref End Function |
Comments
| ||
A more complete version, allowing for short (2-byte) arrays as well as resizeable integer arrays.;Single, Double Byte Arrays ;PJ 2015 Type Array Field Bank Field Width Field X Field Y End Type Function DefineArray(Width=1,x=1,y=1) y=Abs(y) x=Abs(x) If (Not (x Or y)) RuntimeError "Array must have dimensions" End If Local NewArray.Array=New Array NewArray\Width=Width NewArray\X=x NewArray\Y=y NewArray\Bank=CreateBank(x*y*Width) Return Handle(NewArray) End Function Function SetArrayElement(Array, Value, x=1, y=1) Local Instance.Array=Object.Array(Array) Local Offset=(((y-1) * (Instance\X*Instance\Width))+(x*Instance\Width))-1 Select (Instance\Width) Case 1: PokeByte Instance\Bank,Offset,Value And 255 Case 2: PokeShort Instance\Bank,Offset,Value And 65535 ; Case 3: ; PokeByte Instance\Bank,Offset,(Value Shr 24) And 255 ; PokeShort Instance\Bank,Offset+1,Value And 65535 Case 4: PokeInt Instance\Bank,Offset,Value Default: ;Invalid Width End Select End Function Function GetArrayElement(Array,x=1,y=1) Local Instance.Array=Object.Array(Array) Local Offset=(((y-1) * (Instance\X*Instance\Width))+(x*Instance\Width))-1 Local Element Select (Instance\Width) Case 1: Element=PeekByte(Instance\Bank,Offset) And 255 Case 2: Element=PeekShort(Instance\Bank,Offset) And 65535 ; Case 3: ; Element=PeekByte(Instance\Bank,Offset) Shl 24 ; Element=Element+(PeekShort(Instance\Bank,Offset+1) And 65535) Case 4: Element=PeekInt(Instance\Bank,Offset) Default: ;Invalid Width End Select Return Element End Function Function ResizeArray(Array,x,y=1) Local Instance.Array=Object.Array(Array) Local OldSize=BankSize(Instance\Bank) Local NewSize=(x*y*Instance\Width) If (NewSize=OldSize) Return End If If (NewSize<OldSize) Local Byte For Byte=NewSize To OldSize-1 PokeByte Instance\Bank,Byte,0 Next OldSize=NewSize End If Local NewBank=CreateBank(NewSize) CopyBank Instance\Bank,0,NewBank,0,OldSize-1 FreeBank Instance\Bank Instance\Bank=NewBank Instance\X=x Instance\Y=y End Function Function FreeArray(Array) Local Instance.Array=Object.Array(Array) FreeBank Instance\Bank Instance\X=0 Instance\Y=0 Instance\Width=0 Delete Instance End Function |
| ||
This is fascinating... I added a 3rd case, where one assumes to read + write the byte values directly from an INT array, C(..), in byte fashion. Here are memory usage statistics from your program, ( as studied from Task Manager, or otherwise... ). 1st case, using a=DefineArray(16777215), :: memory usage = ~ 1 byte required to store 1 byte 2nd case, using Dim b(16777215), :: memory usage = ~ 4 bytes required to store 1 byte 3rd case, using Dim c(4194304), :: memory usage = ~ 1 byte required to store 1 byte ----> Dim C(4194304) is sufficient for storing 16777216 BYTES. ;;; -_- There is some compact math here; Took me about 2 hours to get it working... I'm still shocked this works... : ;; Coded by VirtLands, { Jan 06, 2015 } Graphics 500,640,32,2 Print Print Global ByteMask[4] ByteMask[0] = $FFFFFF00 ByteMask[1] = $FFFF00FF ByteMask[2] = $FF00FFFF ByteMask[3] = $00FFFFFF ;; Use an INT array, and access it at BYTE offsets ... ( As if we were accessing a BYTE array ) Dim C(4194304) ;; Create an array with enough room for 16777216 bytes. ;;____ ( 4194304 * 4 = 16777216 ) ;;____ Do some testing to prove that the functions work. For z = 0 To 20 StoreByte_at_index( z*2, z ) ;; Take the first 21 numbers and multiply x 2. Next For z = 0 To 20 Print " z = "+z+" : "+ GetByte_at_index( z ) ;;; .. Read back the results .. Next Print For z = 0 To 20 StoreByte_at_index( z+100, z ) ;; Take the first 21 numbers and add +100. Next For z = 0 To 20 Print " z = "+z+" : "+ GetByte_at_index( z ) ;;; .. Read back the results .. Next WaitKey():End ;; ... Stores a byte value at a byte index, ( starting at offset zero, and using Little-Endian storage methods ) Function StoreByte_at_index( byte, index ) div = index Shr 2 ;; divide it by 4 rem = index Mod 4 ;; find the remainder v = C(div) ;; read the current INT C(..) value v = v And ByteMask[rem] ;; Clear the target byte to zero. v = v Or byte Shl (rem Shl 3) ;; Update that byte to a new value. C(div) = v ;; upate that INT memory. End Function ;; ... Retrieves a byte value, using a byte offset index, (starting at offset zero). Function GetByte_at_index%( index ) div = index Shr 2 rem = index Mod 4 v = C(div) v = (v Shr (rem Shl 3)) And $FF ;; .... 0_0 Return v End Function |
| ||
Interesting - the reason I didn't bother making a facility for 4xByte integers was because of Blitz always using 32-bit signed int's for its integers therebye using all 4bytes anyway. There might be a danger with trying to vary sizes of overwriting another value if you exceed the 8th bit of the high byte... |
Code Archives Forum