PDA

View Full Version : is Union a step to dynamic UDT-arrays?



ReneMiner
14-05-2013, 16:17
Not a feature request but some idea that spooks in my head for a few days already...

Might it be possible to use UNION as a way to dynamic UDT-subsets?

I know, Union does not support dynamic strings but UDTs "support" them...

UNION t_Union

st As ASCIIZ * 12
b(12) As Byte ' at VarPtr(.st)

End UNION


would be the current supported syntax, but :whacky34:

UNION t_DynamicByteArray

st As String
b() As Byte ' at StrPtr(.st)

End UNION
is currently not possible...:locomotive:

Maybe someone can think the idea to an end?

Petr Schreiber
14-05-2013, 16:45
If creating wrappers is OK for you, it can be done this way:


' -- Types
Type tVertex
x As Single
y As Single
z As Single
End Type

Type tPolygon
sVertexBuffer As String ' -- Dynamic string to serve as buffer for our array
End Type

' -- Creating polygon
Dim p As tPolygon

' -- Dimensioning the array
tPolygon_RedimArray(p, 3) ' -- 3 elements

' -- Assigning array
tPolygon_Set(p, 1,
1, 2, 3)

tPolygon_Set(p, 2,
4, 5, 6)

tPolygon_Set(p, 3,
7, 8, 9)

Dim v As tVertex
Dim i As Long

' -- Reading array
For i = 1 To 3
v = tPolygon_Get(p, i)
MsgBox 0, UDT_ElementsData_Join(v, ", ")
Next

' -- Wrapper routines to manage the array
Function tPolygon_UBound(var As tPolygon)
Return Len(var.sVertexBuffer)/SizeOf(tVertex)
End Function

Function tPolygon_RedimArray( var As tPolygon, newUBound As Long, Optional preserveFlag As Long = FALSE )

Long oldUBound = tPolygon_UBound(var)

If newUbound = oldUbound Then Exit Function

If preserveFlag Then

If newUbound > oldUbound Then
var.sVertexBuffer+= String$(SizeOf(tVertex) * (newUBound-oldUbound), 0)
Else
var.sVertexBuffer = LEFT$(var.sVertexBuffer, SizeOf(tVertex) * newUbound)
End If

Else

var.sVertexBuffer = String$(SizeOf(tVertex) * newUBound, 0)

End If

End Function

Function tPolygon_Get( var As tPolygon, index As Long ) As String

Long curUBound = tPolygon_UBound(var)
If Outside(index, 1, curUBound) Then
MsgBox 0, "Invalid index"
Exit Function
End If

Dim sArray(curUBound) As tVertex At StrPtr(var.sVertexBuffer)

Return sArray(index)

End Function

Function tPolygon_Set( var As tPolygon, index As Long, x As Single, y As Single, z As Single )

Long curUBound = tPolygon_UBound(var)
If Outside(index, 1, curUBound) Then
MsgBox 0, "Invalid index"
Exit Function
End If

Local v As tVertex
v.x = x
v.y = y
v.z = z

Dim sArray(curUBound) As String * SizeOf(tVertex) At StrPtr(var.sVertexBuffer)

sArray(index) = Peek$(VarPtr(v), SizeOf(tVertex))

End Function


Petr

ReneMiner
14-05-2013, 18:31
Currently I just use Strings as "dynamic subsets" and like this



Alias String As DynamicColorPalette

Dim foo As DynamicColorPalette

' add colors as
foo += MKBYT$(Red) + MKBYT$(Green) + MKBYT$(Blue)


If StrPtrLen(StrPtr(foo)) > 0 Then

Local lFoo( StrPtrLen(StrPtr(foo))/ SizeOf(TBGL_TRGB) ) As TBGL_TRGB At StrPtr(foo)

' now would have lFoo(1).R, lFoo(1).G and lFoo(1).B - that's ok

' but I always repeatedly
' have to put a virtual array over the same thing before...

' or like this to get just one desired value - fine too

Local lFoo1 as TBGL_TRGB
Memory_Copy(StrPtr(foo) + SizeOf(TBGL_TRGB) * (DesiredIndex -1), VarPtr(lFoo1), SizeOf(TBGL_TRGB))

' now have lFoo1.R, lFoo1.G and lFoo1.B, surely can peek just one byte out there too...
Endif

So maybe call it


Alias String As DynamicColorPalette In Union With TBGL_TRGB

ReneMiner
18-05-2013, 11:37
I have also another solution to emulate dynamic udt-subsets which does not use strings but heap to store, check this example:



Uses "Console"

Alias DWord As DynamicVariable

Type t_Test
bBytes As DynamicVariable
lLongs As DynamicVariable
sStrings As DynamicVariable
End Type

Dim DynamicReserve As String ' use this in all subs + functions - so no local declaration-time needed

Dim foo As t_Test
Dim i As Long


' "SetBytes(foo.bBytes, 1, 2, 4, 8)" :

foo.bBytes = HEAP_AllocByStr(MKBYT$(1) + MKBYT$(2) + MKBYT$(4) + MKBYT$(8))

If foo.bBytes Then
PrintL "UBound foo.bBytes =" + Str$(HEAP_Size(foo.bBytes))
PrintL "------------------------------"
For i = 1 To HEAP_Size(foo.bBytes)' / SizeOf(Byte)
PrintL "foo.bBytes(" + TStr$(i) + ") = " + Str$(Peek(Byte, foo.bBytes + i-1))
Next
EndIf

foo.lLongs = HEAP_AllocByStr(MKL$(&H10000000) + MKL$(&H20000000) + MKL$(&H30000000) + MKL$(&H40000000))

If foo.lLongs Then
PrintL "UBound foo.lLongs =" + Str$(HEAP_Size(foo.lLongs)/SizeOf(Long))
PrintL "------------------------------"

For i = 1 To HEAP_Size(foo.lLongs) / SizeOf(Long)
PrintL "foo.lLongs(" + TStr$(i) + ") = " + Str$(Peek(Long, foo.lLongs + (i-1) * SizeOf(Long) ))
Next
EndIf

PrintL "------------------------------"

PrintL "append 1 byte value 32 to foo.bBytes..."

foo.bBytes = AddByte(foo.bBytes, 32)

PrintL "oops, forgot 16, so insert at position 5"
PrintL

foo.bBytes = InsertByte(foo.bBytes, 5, 16)

PrintL "now foo.bBytes has" + Str$(HEAP_Size(foo.bBytes)) + " elements"
PrintL "------------------------------"



If foo.bBytes Then
For i = 1 To HEAP_Size(foo.bBytes)' / SizeOf(Byte)
PrintL "foo.bBytes(" + TStr$(i) + ") = " + Str$(Peek(Byte, foo.bBytes + i-1))
Next
EndIf

PrintL "------------------------------"

foo.sStrings = AddString(foo.sStrings, "World")
foo.sStrings = AddString(foo.sStrings, "Hello")

PrintL GetString(foo.sStrings, 2)
PrintL GetString(foo.sStrings, 1)


WaitKey
' ------------------------------------------
Function AddByte(ByVal pBytes As DynamicVariable, Optional bVal As Byte) As DynamicVariable

If HEAP_Size(pBytes) Then
DynamicReserve = Peek$(pBytes, HEAP_Size(pBytes)) + MKBYT$(bVal)
HEAP_Free(pBytes)
pBytes = HEAP_AllocByStr(DynamicReserve)
Else
pBytes = HEAP_AllocByStr(MKBYT$(bVal))
EndIf

Function = pBytes

End Function
' ------------------------------
Function InsertByte(ByVal pBytes As DynamicVariable, ByVal Position As Long, Optional bVal As Byte) As DynamicVariable

If HEAP_Size(pBytes) Then
If Position <= 1 Then
DynamicReserve = MKBYT$(bVal) + Peek$(pBytes, HEAP_Size(pBytes))
ElseIf Position > HEAP_Size(pBytes) Then
DynamicReserve = Peek$(pBytes, HEAP_Size(pBytes)) + MKBYT$(bVal)
Else
DynamicReserve = Peek$(pBytes, Position - 1) + MKBYT$(bVal) + Peek$(pBytes + Position - 1, HEAP_Size(pBytes) + 1 - Position )
EndIf

HEAP_Free(pBytes)

pBytes = HEAP_AllocByStr(DynamicReserve)
Else
pBytes = HEAP_AllocByStr(MKBYT$(bVal))
EndIf
Function = pBytes

End Function
' ---------------------------------
Function AddString(ByVal pStrings As DynamicVariable, Optional sString As String) As DynamicVariable

If HEAP_Size(pStrings) Then
If sString = "" Then
DynamicReserve = Peek$(pStrings, HEAP_Size(pStrings)) + MKDWD$(0)
Else
DynamicReserve = Peek$(pStrings, HEAP_Size(pStrings)) + MKDWD$(HEAP_AllocByStr(sString))
EndIf
HEAP_Free(pStrings)

pStrings = HEAP_AllocByStr(DynamicReserve)

Else
If sString = "" Then
pStrings = HEAP_AllocByStr(MKDWD$(0))
Else
pStrings = HEAP_AllocByStr(MKDWD$(HEAP_AllocByStr(sString)) )
EndIf
EndIf

Function = pStrings

End Function
' --------------------
Function GetString( ByVal pStrings As DynamicVariable, ByVal Position As Long) As String

If Not Between(Position, 1, HEAP_Size(pStrings)/SizeOf(DynamicVariable)) Then Return ""

If Peek(DynamicVariable, pStrings + (Position-1) * SizeOf(DynamicVariable)) = 0 Then Return ""

Function = Peek$(Peek(DynamicVariable, pStrings + (Position-1) * SizeOf(DynamicVariable)), HEAP_Size(Peek(DynamicVariable, pStrings + (Position-1) * SizeOf(DynamicVariable) )) )


End Function


AddByte is not really needed as a seperate function, but to clear the example...Of course it would need Insert-Functions for all used types and also some special treatment when replacing Strings...
In any case you can Dim a virtual array over this - like


local myBytes(Heap_Size(foo.bBytes)) as Byte at foo.bBytes

for strings you put a Dword-Array over to read out the "String-Pointers"

ErosOlmi
18-05-2013, 14:52
Do you know you can have arrays of dynamic strings inside UDT?

Maybe this can help:


Uses "Console"


Type MyType
aaa As String '---Single dynamic string inside UDT
bbb(100000) As String '---Array of dynamic string inside UDT
ccc As Long
ddd(10) As Long
end type


dim x1 as mytype
dim count as long


'---Allocate some big data
x1.aaa = String$( 10, "X") '--- 10 bytes
x1.bbb(1) = String$( 1000000, "Y") '--- 1 MBytes
x1.bbb(2) = String$( 10000000, "Z") '--- 10 MBytes
x1.bbb(3) = String$(100000000, "W") '---100 MBytes




'---Show some big data
PrintL "x1.aaa ", x1.aaa
PrintL "x1.bbb(1)", LEFT$(x1.bbb(1), 50), "Size:", Len(x1.bbb(1))
PrintL "x1.bbb(2)", LEFT$(x1.bbb(2), 50), "Size:", Len(x1.bbb(2))
PrintL "x1.bbb(3)", LEFT$(x1.bbb(3), 50), "Size:", Len(x1.bbb(3))


'---Clean big data
x1.aaa = ""
x1.bbb(1) = ""
x1.bbb(2) = ""
x1.bbb(3) = ""


PrintL "---Press a key to continue---"
WaitKey


I know I have to implement it a bit. I should add some important features like:

REDIM [PRESERVE] dynamic string arrays inside UDT (actually they must be defined during UDT declaration
UBOUND/LBOUND work with dynamic string arrays inside UDT
VARPTR/STRPTR work with dynamic string arrays inside UDT
...

ReneMiner
18-05-2013, 15:15
Yes I know I can have arrays inside udt... but not variable amount...yet - which I need to bind variable names as pointers (see here (http://www.thinbasic.com/community/showthread.php?t=12052&page=2&p=88793#post88793)) for flexible purpose as binding some arbitrary udt to some listview-control... next step is a treeview :scare: