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: