PDA

View Full Version : Release the beast: Get$/Set$/GetPtr



ReneMiner
22-07-2013, 10:02
the most dirty approach ever- but surprisingly it works. :)

Three functions that work on variables and one-dimensional arrays of strings and fixed size udts:

Edit:

This was the beginning, one page further (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89391#post89391) and somewhere at the recents posts you'll find LazyFun.tBasicU - so this example just demonstrates what's possible.
In the meantime there's much more - there are a lot of functions to pointers, heap and even storing multidynamic data -find an overview here (http://www.thinbasic.com/community/showthread.php?t=12174&page=6&p=89504#post89504)


Dword myPtr = GetPtr(ByVal sVariableName as String, Optional Index as Long, lSize as Long)

pass any variables name to receive a pointer,
give an index if you want a pointer to a certain element of one-dimensional arrays
pass for example a SizeOf() to lSize if you want a pointer to an non-string-array-element


String sContent = Get$(Byval sVariableName as String, Optional Index as Long, lSize as Long)

pass any variables name to receive its content in form of a string
give an index if you want the content of a certain element of one-dimensional arrays
pass for example a SizeOf() to lSize if you want the content of a non-string-array-element
pass lSize to receive just "Left$(lSize)" of a string-array-element


Dword myNewPtr = Set$(Byval sVariableName as String, byval sData as String, Optional Index as Long)

pass any variables name to change its content to sData
give an index if you want to change a certain element of one-dimensional arrays
receive the variables (new) pointer or 0 if fails



#MinVersion 1.9.7.0

Uses "console"

Declare Function VarInfo Lib "thinCore.DLL" _
Alias "thinBasic_VariableGetInfoEX" _
( _
ByVal SearchKey As String , _
ByRef MainType As Long , _ '---ATTENTION: parameter passed BYREF will return info
ByRef SubType As Long , _ '---ATTENTION: parameter passed BYREF will return info
ByRef IsArray As Long , _ '---ATTENTION: parameter passed BYREF will return info
ByRef DataPtr As Long , _ '---ATTENTION: parameter passed BYREF will return info
ByRef nElements As Long , _ '---ATTENTION: parameter passed BYREF will return info
Optional _
ByVal WhichLevel As Long _
) As Long

%Is_String = 30

' ---------------------------------------------------------------------------
Function GetPtr(ByVal sName As String, Optional Index As Long, lSize As Long) As DWord

' returns pointer to any variable passed by name

If Not VARIABLE_Exists(sName) Then Return 0

Local lMainType, lSubType, lIsArray, lDataPtr, lnElements As DWord
VarInfo(sName, lMainType, lSubType, lIsArray, lDataPtr, lnElements)

If Between(Index, 1, lnElements) Then
If lMainType = %Is_String Then
Return Peek(DWord, lDataPtr + (Index - 1) * SizeOf(DWord))
Else
Return lDataPtr + (Index-1) * lSize
EndIf
Else
If lMainType = %Is_String Then
Return Peek(DWord, lDataPtr)
Else
Return lDataPtr
EndIf
EndIf

End Function

' ------------------------------------------------------------------------------
Function Get$(ByVal sName As String, Optional Index As Long, lSize As Long) As String

' returns content of variable passed by name
If Not VARIABLE_Exists(sName) Then Return ""

Local lMainType, lSubType, lIsArray, lDataPtr, lnElements As DWord
Local realPtr, realSize As DWord

VarInfo(sName, lMainType, lSubType, lIsArray, lDataPtr, lnElements)

If All( _
lIsArray <> 0, _
Between(Index, 1, lnElements) _
) Then
If lMainType = %Is_String Then
realPtr = Peek(DWord, lDataPtr + (Index - 1) * SizeOf(DWord))
realSize = Peek(DWord, realPtr - SizeOf(DWord))
If realSize = 0 Then Return ""
If Between(lSize, 1, realSize) Then
Function = Memory_Get(realPtr, lSize)
Else
Function = Memory_Get(realPtr, realSize)
EndIf
ElseIf lSize > 0 Then
Function = Memory_Get(lDataPtr + (Index - 1) * lSize, lSize)
EndIf
Else
If lMainType = %Is_String Then
realPtr = Peek(DWord, lDataPtr)
realSize = Peek(DWord, realPtr - SizeOf(DWord))
If realSize = 0 Then Return ""
If Between(lSize, 1, realSize) Then
Function = Memory_Get(realPtr, lSize)
Else
Function = Memory_Get(realPtr, realSize)
EndIf
ElseIf lSize > 0 Then
Function = Memory_Get(lDataPtr, lSize)
EndIf

EndIf

End Function
' ------------------------------------------------------------------------------
Function Set$(ByVal sName As String, ByVal sData As String, Optional Index As Long) As DWord

' change value of any variable passed by name
' returns pointer to (new) variables location

If Not VARIABLE_Exists(sName) Then Return 0

Local lMainType, lSubType, lIsArray, lDataPtr, lnElements As DWord
Local lDummyPtr As DWord

VarInfo(sName, lMainType, lSubType, lIsArray, lDataPtr, lnElements)

If All( _
lIsArray <> 0, _
Between(Index, 1, lnElements) _
) Then

If lMainType = %Is_String Then
VarInfo("sData", lMainType, lSubType, lIsArray, lDummyPtr, lnElements)
' -- this does the trick:
Memory_Swap(lDataPtr + (Index - 1) * SizeOf(DWord), lDummyPtr, SizeOf(DWord))
Function = Peek(DWord, lDataPtr + (Index - 1) * SizeOf(DWord))
ElseIf sData <> "" Then
Memory_Set(lDataPtr + (Index - 1) * Peek(DWord, StrPtr(sData) - 4), sData)
Function = lDataPtr + (Index - 1) * Peek(DWord, StrPtr(sData) - 4)
EndIf

Else

If lMainType = %Is_String Then
VarInfo("sData", lMainType, lSubType, lIsArray, lDummyPtr, lnElements)
' -- dirty- ain't it?
Memory_Swap(lDataPtr, lDummyPtr, SizeOf(DWord))
Function = Peek(DWord, lDataPtr)
ElseIf sData <> "" Then
Memory_Set(lDataPtr, sData)
Function = lDataPtr
EndIf

EndIf

End Function

' ------------------------------------------------------------------------------
' all from here is just some testing:

Dim foo As String = "abc"
Dim dog As Ext = 1.2345678
Dim oops(3) As String

Type t_udt
a As Byte
b As Long
c As Double
End Type

Dim udt(5) As t_udt
Dim dummy As t_udt

Dim i As Long

Do

PrintL $CRLF + "First test: simple string-variable" + $CRLF
PrintL "assign 'abc' to 'foo' now"
foo = "abc"
PrintL "foo-ptr :" + Str$(GetPtr("foo"))
PrintL "foo-content: " + foo
PrintL "Get$('foo'): " + Get$("foo")
PrintL $CRLF
PrintL "Set$('foo','hello world!') now"
PrintL "foo-ptr :" + Str$(Set$("foo", "hello world!"))
PrintL "foo-content: " + foo
PrintL "Get$('foo'): " + Get$("foo")

PrintL $CRLF + "any key to continue" + $CRLF
WaitKey

PrintL $CRLF + "Second test: string-array" + $CRLF
For i = 1 To 3
PrintL "Set$('oops','I am oops(" + i + ")', " + i + ") now"
Set$("oops","I am oops("+ i +")", i)
Next
For i = 1 To 3
PrintL "oops("+i+") contains: " + oops(i)
PrintL "Get$('oops',"+i+") : " + Get$("oops", i)
Next
PrintL $CRLF + "any key to continue" + $CRLF
WaitKey

PrintL $CRLF + "Third test: simple numeric variable" + $CRLF
PrintL "dog current :" + Str$(dog)
PrintL "dog-pointer :" + Str$(GetPtr("dog"))
PrintL $CRLF
PrintL "double content now"
Set$("dog", MKE$( CVE(Get$("dog",, SizeOf(Ext))) * 2))
PrintL "Get$('dog',,SizeOf(Ext)): " + CVE(Get$("dog",, SizeOf(Ext)))
PrintL "re-check dog :" + Str$(dog)
PrintL $CRLF + "any key to continue" + $CRLF
WaitKey

PrintL $CRLF + "Fourth test: fixed size udt-array variable" + $CRLF
dummy.a += 1
dummy.b += 2
dummy.c += 3.45

Set$("udt", Memory_Get(VarPtr(dummy), SizeOf(t_udt)), 3)
PrintL "udt(3).a:" + Str$(udt(3).a)
PrintL "udt(3).b:" + Str$(udt(3).b)
PrintL "udt(3).c:" + Str$(udt(3).c)

PrintL "------------------------------------------------"
PrintL $CRLF + "ESC to end, any other key to re-run" + $CRLF

Loop While WaitKey <> "[ESC]"


Not possible:
any actions on multidimensional arrays, there's only possible to receive pointer to very first element
Set$/Get$ on udt-substrings directly

ReneMiner
22-07-2013, 10:39
ok, on 2-dimensional arrays it would simple work by some multiplication + addition - but the user has to pass the correct calculated index. On moredimensional arrays one would need to know in which order they are stored. I don't...

For udt-array-substrings user needs to swap the sub-pointers himself after retrieving them using Get$.
Edit: now there's SetUdtStr to do that

Petr Schreiber
22-07-2013, 11:29
Hi Rene,

I can't get it to work, do you use some special thinCore by any chance? Can you run this script:


Uses "Console", "File", "Crypto"

$DLL_CORE = APP_Path+"thinCore.dll"
$BIN_CORE = FILE_Load($DLL_CORE)

DWord cSize = FILE_Size($DLL_CORE)
DWord cSig1 = HASH(1, $BIN_CORE)
DWord cSig2 = iCrypto_MD5($BIN_CORE)

String sOutput = "CoreTest v1.0" + $CRLF +
"Core size = " + Format$(cSize, "0,") + "b" + $CRLF +
"Core signature 1 = " + Hex$(cSig1) + $CRLF +
"Core signature 2 = " + Hex$(cSig2)

PrintL sOutput
ClipBoard_SetText(sOutput)

PrintL
PrintL "(Info above placed to clipboard now, press any key to quit)"

WaitKey

On my PC I get:


CoreTest v1.0
Core size = 172,032b
Core signature 1 = CC97657E
Core signature 2 = A9A329C9



Petr

ReneMiner
22-07-2013, 11:32
this is what I got:



CoreTest v1.0
Core size = 172,032b
Core signature 1 = 3E7670E0
Core signature 2 = 1DCD6500

Petr Schreiber
22-07-2013, 11:37
Thanks,

looking at the signatures - it means you have different core than me, that is the reason why it works for you and not for me. I am on PC with clean 1.9.7.0 installation, I think, I didn't add any beta cores later.


Petr

ReneMiner
22-07-2013, 11:42
probably you're right. I think I have it from somewhere of this thread (http://www.thinbasic.com/community/showthread.php?t=12138), page 2 at bottom - but I'm not sure about it (date) - can very well be it was posted inside this attachement.
(http://www.thinbasic.com/community/showthread.php?t=12145&p=89086#post89086)
Anyway- there's a new version of Oxygen (http://www.thinbasic.com/community/showthread.php?t=12175&p=89376) which uses in Examples\General\VarArrayPointers.tBasic the same thinCore-function - would you mind trying it?

+ + +

One more script to test the attached unit-file - the functions from above are included and a 'few' more - so those functions still work as described above.
I called it LazyFun(ctions) and it's filled with functions that I'd like to see as native tB-functions.
A few more are on my list as to receive the size of a variable passed "byName" since it could improve a few of the already existing functions when user does not need to pass them as parameters nor my - for example listview - would need to have storage-varaiables to what amount one element is sized.

So this is a script for test-run, should be saved next to the attachement.


Uses "Console"
#INCLUDE "lazyFun.tBasicU"

' ----------------
'[] Heap
' ----------------
DWord foo
String sX = "123456789|"

Heap_SetAt(VarPtr(foo), "I am an important thing to memorize")

PrintL $CRLF + Heap_Get$(foo) + $CRLF
PrintL $CRLF + "test instr-position: 'important' (9 chars)"
PrintL "found here : '" + Memory_Get(foo + Heap_Instr(foo, "important") - 1, 9) +"'"

Print $CRLF + "test Heap_Left$/Heap_Mid$:"
PrintL Heap_Left$(foo, 7) + "other " + Heap_Mid$(foo, 19, 5)

PrintL $CRLF + "test Heap_Right$ with fill-option:"
PrintL sX + sX + sX+ sX + sX +"<< 50"
PrintL Heap_Right$(foo, 50, Asc("."))
PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey


PrintL $CRLF + "this is a copy of foo:"
DWord dog = Heap_Copy(foo)
PrintL $CRLF + Heap_Get$(dog)
PrintL "append something now"
Heap_AppendAt(VarPtr(dog), " too!")
PrintL $CRLF + Heap_Get$(dog)
PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL $CRLF + "now resize to 50 bytes and fill with sX: '" + sX +"'"
PrintL " 5 times, StrLen(sX): " + StrLen(sX)
Heap_ResizeAt(VarPtr(dog), 5 * StrLen(sX))
Heap_Fill(dog, sX)
PrintL $CRLF + Heap_Get$(dog)
PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey


PrintL "dog-length = " + HEAP_Size(dog)
PrintL "fill with 'hello world !'"
Heap_Fill(dog, "hello world !")
PrintL $CRLF + Heap_Get$(dog)

PrintL $CRLF + "now resizing using %auto-switch"
' usually one would use SizeOf(some type) instead of Len here
Heap_ResizeAt(VarPtr(dog), Len("hello world !"), %auto)

PrintL $CRLF + Heap_Get$(dog)
PrintL "-----------------------------------------"

PrintL $CRLF + "key to continue" + $CRLF

WaitKey
HEAP_Free(foo)
HEAP_Free(dog)

' ----------------
'[] SetUDTStr/GetDataPtr
' ----------------


PrintL $CRLF + "test to alter string inside udt"
Type t_test
A As Byte
B As Long
C As String
End Type

Dim test(12) As t_test

SetUDTStr("test",7, UDT_ElementOffset(test(1).c), SizeOf(t_test), "I'm supposed to become no.7")

foo = GetDataPtr("test",7, UDT_ElementOffset(test(1).c), SizeOf(t_Test))
' in case Stringpointer peek StrPtr+StrPtrLen -
PrintL Memory_Get(Peek(DWord, foo), Peek(DWord, Peek(DWord, foo) - SizeOf(DWord)))
' but we have a function for this also:
PrintL StrAtPtr$ foo
PrintL test(7).c

PrintL $CRLF + "test variable in UDT:"

foo = GetDataPtr("test",6, UDT_ElementOffset(test(1).b), SizeOf(t_Test))
PrintL "requested adress" + Str$(foo)
PrintL "put 123 there" : Poke(Long, foo, 123)
PrintL "check content" + Str$(test(6).b)

'PrintL $CRLF + "key to continue" + $CRLF
'WaitKey


PrintL $CRLF + "key to end" + $CRLF
WaitKey


Edit:attachement removed. Some functions have been changed. find LazyFun.tBasicU here (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89391#post89391)

ReneMiner
23-07-2013, 07:42
I'm still nosy- I rewrote part of it using oxygen based on the mentioned example and it would be of interest to me if it works then:


Uses "Console", "Oxygen"

' shared points:
Dim As Long pGetAnyPtr
Dim As Long pFinish

' setup O2-code:
O2_Basic RawText
'From ThinCore header
! thinBasic_VariableGetInfoEX Lib "thinCore.dll" (String SearchKey, sys *pMainType,*pSubType,*pIsArray,*pDataPtr,*pnElements,WhichLevel) As sys

'---Equates for variable Main Type
%MainType_IsNumber = 20&
%MainType_String = 30&
%MainType_IsString = %MainType_String
%MainType_Variant = 50&
%MainType_IsVariant = %MainType_Variant
%MainType_UDT = 60&
%MainType_IsUDT = %MainType_UDT
'---Equates for variable Sub Type
%SubType_Byte = 1&
%SubType_Integer = 2&
%SubType_Word = 3&
%SubType_DWord = 4&
%SubType_Long = 5&
%SubType_Quad = 6&
%SubType_Single = 7&
%SubType_Double = 8&
%SubType_Currency = 9&
%SubType_Ext = 10&
%SubType_AsciiZ = 25&


Function GetAnyPtr(bstring varname, Optional sys n, Optional Long lSize, Optional Long lOffset ) As sys, link #pGetAnyPtr
============================================================================
'
sys MainType, SubType, IsArray, DataPtr, nElements, WhichLevel
thinBasic_VariableGetInfoEX Varname, MainType, SubType, IsArray, DataPtr, nElements, WhichLevel

If MainType = %MainType_IsString Then
If n <= nElements Then
bstring Array At (DataPtr) 'thinBasic uses bstrings
Return StrPtr Array[n]
Else
Return *DataPtr
EndIf
Else
If n <= nElements And lSize > 0 Then DataPtr = DataPtr + (n-1) * lSize
DataPtr = DataPtr + lOffset
Return DataPtr
End If

End Function


Sub finish() link #pFinish
==========================
terminate
End Sub

End RawText


If O2_Error <> "" Then
PrintL "Can not run - Error within o2-script:" + $CRLF
PrintL O2_Error
WaitKey
Stop
Else
' can run
O2_Exec
End If
' -----------------------------------------------------
' tB-section

Declare Function GetAnyPtr(ByVal String, _
Optional ByVal DWord, _
Optional ByVal Long, _
Optional ByVal Long _
) As DWord At pGetAnyPtr

Declare Sub Finish() At pFinish


' tests :
' string-array
String a(3)
a(1)="Apples"
a(2)="Bananas"
a(3)="Corn"
DWord p=GetAnyPtr("a",2) 'pointer to Bananas


If p Then PrintL Memory_Get(p, Peek(DWord, p - SizeOf(DWord)))

' simple string
String b = "I am here"
p = GetAnyPtr("b")
If p Then PrintL Memory_Get(p, Peek(DWord, p - SizeOf(DWord)))
PrintL $CRLF

' simple numeral
DWord q = GetAnyPtr("p")
If q Then
PrintL "p located at:" + Str$(q)
PrintL "p contains :" + Str$(Peek(DWord,q))
EndIf
PrintL $CRLF

' udt-array
Type t_Test
X As Byte
Y As String
Z As Double
End Type
Dim test(12) As t_Test

' udt-numeral
Test(7).Z = 12.34567890

PrintL $CRLF + "ask for pointer to test(7).Z:"
p = GetAnyPtr("test", 7, SizeOf(t_Test), UDT_ElementOffset(Test(1).Z))
If p Then PrintL "found double at p: " + Peek(Double, p)
PrintL $CRLF

' udt-string
Test(8).Y = "I am test(8).Y"

PrintL $CRLF + "ask for pointer to test(8).Y:"
q = GetAnyPtr("test", 8, SizeOf(t_Test), UDT_ElementOffset(Test(1).Y))
If q Then PrintL "found string at q: " + Memory_Get(Peek(DWord, q), Peek(DWord, Peek(DWord, q) - SizeOf(DWord)))


PrintL $CRLF + "any key to end"
WaitKey
Finish()

Petr Schreiber
23-07-2013, 08:51
Works okay for me!


Petr

ReneMiner
23-07-2013, 09:03
Works okay for me!


Petr
Assume you mean the last posted test-script using oxygen and not the stuff above it - or did you get some other thinCore.dll in the meantime? - that tells me
old thinCore had no optional WhichLevel ??? - or:
it works through oxygen but not in plain thinBasic. so there must be something through using those "safe sys-pointer-variables".
There's nothing equal to these in tB...yet...

There seems to be an advantage using oxygen on thincore+pointer-stuff through using these sys-variables.
Currently I'm trying some function to find out the size of an element, probably have to use Function thinBasic_ArrayGetInfo() for this but using it always crashes even if I request another Pointer using thinBasic_ArrayGetPtr().

Petr Schreiber
23-07-2013, 12:32
Hi Rene,

I got the core from the other thread you linked, so the examples started working for me.


Petr

ReneMiner
23-07-2013, 13:29
I see.

I had to remove the older version since I discovered that ByRef passed UDT-subsets seem not to work, so there are some new functions and also some new syntax to some existing functions. Now these functions await an address where to find/store the pointer - these functions names end with "At" now.
StrLen-Function still inside - attention that works only on String/String-Array but not on strings which are subsets of an UDT.

Also Set$ I changed to SetStr since it does not return a string. Same applies to SetUdtStr. Mainly the functions work still the same way as described above, a few have been exchanged:

Some demonstration code that shows usage of heap as dynamic UDT-subsets
Heap_SetAt
Heap_AppendAt


Uses "Console"
#INCLUDE "lazyFun.tBasicU"

Type t_type
S1 As DWord
S2 As DWord
End Type

Type t_Subtype
A As Long
B As Byte
C As Double
End Type

Dim foo(3) As t_type
Dim dummy As t_Subtype
Dim i As Long

For i = 1 To 3
' now tell foo(2).S1 to hold something:

dummy.A += 12
dummy.B += 3
dummy.C += 4.5
Heap_AppendAt(VarPtr(foo(2).S1), Memory_Get(VarPtr(dummy), SizeOf(t_Subtype)) )

Next i
' retrieve data:
Dim dArray(HEAP_Size(foo(2).S1)\SizeOf(t_SubType)) As t_SubType At foo(2).S1

For i = 1 To UBound(dArray)
' PrintL "element" + Str$(i)
PrintL "A:" + dArray(i).A
PrintL "B:" + dArray(i).B
PrintL "C:" + dArray(i).C
PrintL
Next

PrintL $CRLF + "key to continue" + $CRLF
WaitKey

dummy.A = 77
dummy.B = 77
dummy.C = 77

PrintL $CRLF + "now insert new element 2"

Heap_ElementInsertAt(VarPtr(foo(2).S1), 2, Memory_Get(VarPtr(dummy), SizeOf(t_Subtype)) )

ReDim dArray(HEAP_Size(foo(2).S1)\SizeOf(t_SubType)) As t_SubType At foo(2).S1

For i = 1 To UBound(dArray)
' PrintL "element" + Str$(i)
PrintL "A:" + dArray(i).A
PrintL "B:" + dArray(i).B
PrintL "C:" + dArray(i).C
PrintL
Next

PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL "new use of Heap_SetAt"

Heap_SetAt VarPtr(foo(3).S2), "this is important"
PrintL Heap_Get$(foo(3).S2)
' - - - - - -
String fish
PrintL $CRLF + "new : SetStr (replaces Set$ since does not return string)"
SetStr "fish", "apple juice"
PrintL Get$("fish")
PrintL
Dword myPtr = GetPtr "fish"
PrintL StrAtPtr$ myPtr
PrintL
PrintL fish

PrintL $CRLF + "key to end" + $CRLF
WaitKey

EDIT:
Functions-Overview version 0.42 (http://www.thinbasic.com/community/showthread.php?t=12174&page=6&p=89504#post89504)- find a link to the latest version there

This attachements is an older version to run the posted examples before 12-08-2013.
MinVersion 1.9.7.0
Functions-Overview version 0.35
(http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400)FileVersion 0.35, 07-08-2013

Charles Pegge
23-07-2013, 15:19
sys and long are the same in a 32 bit system. Using sys for most integer variables is a safe bet.

ReneMiner
23-07-2013, 15:23
I have 64Bit...but anyhow I try- I don't get Function thinBasic_ArrayGetPtr nor thinBasic_ArrayGetInfo to deliver results without crashing. Would be nice if one would not need to pass an elements size and the GetAnyPtr function (http://www.thinbasic.com/community/showthread.php?t=12174&p=89385#post89385) would find out.

Charles Pegge
23-07-2013, 16:00
To clarify: I should have said 32 bit process The width of sys is determined by the compilation mode: 32 or 64 bit.

ReneMiner
23-07-2013, 20:36
One more example how to use and organize Heap for storing dynamic arbitrary amounts of "sub-heap" and once more some "ByName"-example.



Uses "Console"
#INCLUDE "lazyFun.tBasicU"

DWord foo ' might be any subset of udt...
Long i

' storing dynamic multiple subsets, let's say 7 Sub-Heaps to foo
' so make space for 7 pointers and save their positions to heap at foo

foo = HEAP_Alloc( 7* SizeOf(DWord) )

For i = 1 To 7
PrintL "fill in data: 'I am Number"+Str$(i)+"'"
' pass the position where to find/store the pointer:
Heap_SetAt(foo + (i-1) * SizeOf(DWord), "I am number" + Str$(i) )
Next


PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey
' all noded to one Dword, however:

For i = 1 To HEAP_Size(foo)\SizeOf(DWord)
PrintL Heap_Get$(Peek( DWord, foo + (i-1) * SizeOf(DWord)))
Next
PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

' exchange number 3, access the single subitem only, pass the position(!) of the pointer:
Heap_SetAt(foo + (3 - 1)* SizeOf(DWord), "hey - I am new number 3 here")

' or append one - have to refer to the parent here
' doing a few things in one step : create some new heap and append its pointer to heap at foo
Heap_AppendAt VarPtr(foo), MKDWD$(HEAP_AllocByStr("so I should be the last"))

' squeeze new one at position 8 in:

Heap_ElementInsertAt VarPtr(foo), 8, MKDWD$(HEAP_AllocByStr("I sneak in here now"))
' also here: the result of Heap_AllocByStr gets inserted to the data found at the position
' stored at varptr foo, new resulting heap gets created and replaces the "old" one. Finally
' the new heaps address gets stored at varptr foo

For i = 1 To HEAP_Size(foo)\SizeOf(DWord)
PrintL Heap_Get$(Peek( DWord, foo + (i-1) * SizeOf(DWord)))

' can release heap using for example Heap_ResizeAt with a size of 0
HEAP_ResizeAt( foo + (i-1) * SizeOf(DWord), 0 )
' also valid - does basically the same:
' HEAP_SetAt( foo + (i-1) * SizeOf(DWord), "" )

Next

' remember:
HEAP_ResizeAt(VarPtr(foo), 0)
' equals
' Free_Heap(foo) : foo = 0

' every of these subheaps could hold an array of any fixed size Type as "huge" as in the post above
' you can "node" heaps to any of these - as many as your memory allows

PrintL "-----------------------------------------" + $CRLF
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

' just because it's so cool:
String fishsoup
' changing string by passing its name:
SetStr "fishsoup", "lemon juice"
' retrieve Ptr by passing name
foo = GetPtr "fishsoup"
' retrieve string by passing its pointer
PrintL StrAtPtr$ foo
' or just as
PrintL Get$ "fishsoup"
' returns same as
PrintL "lemon juice"
' or
PrintL fishsoup

PrintL "-----------------------------------------" + $CRLF
'PrintL $CRLF + "key to continue" + $CRLF
'WaitKey

PrintL $CRLF + "key to end" + $CRLF
WaitKey

you'll need the attachement "LazyFun.tBasicU" above or below saved next to this:)

kryton9
24-07-2013, 06:23
Rene, I just wanted to say that while I have not posted anything for some time. I have been reading the forums on and off again and have enjoyed seeing an enthusiastic and prolific programmer contributing to this fine forum and language.

ReneMiner
24-07-2013, 09:51
thanks guys. your words make me feel good - and I would not play around with this stuff if I wouldn't have some fun doing it. Once again I exchanged the attachement.
I mostly went over it and filled it with a few more comments and a little explanation. A "little change" to Heap_Mid$-Function, see below on this post

A small overview about the included functions:


"Lazy Functions" - old version: find the new list here (http://www.thinbasic.com/community/showthread.php?t=12174&page=6&p=89504#post89504)

contains:

--------------------------------------------------------------------------------
functions to manipulate variables
passed "byName" in a string - find an example covering these in code below
i think these functions names will be prefixed Variable_ in near future...

Get$ Get String-data from any variable passed "byName"
GetDataPtr Get Pointer to Data of a certain element of any variable
GetPtr Get Pointer to any variable
SetStr Set String-data to any variable
SetUdtStr Set String-data to dynamic-string in udts
VarInfo - Alias thinBasic_VariableGetInfoEx, Lib "thinCore.dll"

restrictions to these:
for multidimensional arrays just the first elements pointer can be returned
for multidimensional arrays only first or all elements capture is possible
--------------------------------------------------------------------------------
functions to manage Heap-memory

>> common:
Heap_AppendAt append some data to heap and get/store pointer at specified position
Heap_Copy create copy of existing heap and return new pointer
Heap_Fill fills/overwrites heap with some string-data
Heap_Get$ get entire heap as string
Heap_InsertAt insert new data at absolute position within heap
Heap_Instr find the position of next occurence of string to find
Heap_Left$ get left part/get string of desired length with heap content left
Heap_Mid$ get mid part/get string of desired length and heap within
Heap_ResizeAt resizes heap, preserving data, resize to 0 will just free the heap
Heap_Right$ get right part/string of desired lenght with heap-content right
Heap_SetAt set new data to heap and get/store pointer at the specified position

>> elements stored in "1-dimensional, fixed size heap-array":
Heap_ElementFreePtrAt removes a pointer-element and free sub-heap
Heap_ElementGet$ returns data of one single element
Heap_ElementGetPtr returns pointer to single element
Heap_ElementIDAt returns index of data, creates it if not exists
HEAP_ElementPeekPtr peek pointer that's stored as element - NOT INCLUDED YET because of bigger news to await about Heap_Nodes
Heap_ElementInsertAt insert data as new element
Heap_ElementRemoveAt will remove one element
Heap_ElementSet set data to an existing element

>> organized in multidimensional storage:
Heap_OrganizeAddress will return an address where to find/store data
Heap_OrganizeAt will create organized heap with at least 2 dimensions
Heap_OrganizerFreeAt will free heap + organized sub-heap
Heap_OrganizerGetDim$ returns information about organized heap dimensions

remarks:
all Heap-functions ending ...At await a position where to store or find a pointer so all these create some new heap and/or take care of releasing the old data and update the passed position with the new pointer or 0 if released.

--------------------------------------------------------------------------------
functions to dynamic strings

Dictionary_Len returns size of dictionary-buckets
StrAtPtr$ returns string found at passed position
StrLen - limited usage since not works on udt-substrings, shortens StrPtrLen(StrPtr())

--------------------------------------------------------------------------------
pointer functions

PeekPtrAt safe way to peek pointers without risk to Peek at 0



all functions ending with $ return string-data- however
#MINVERSION 1.9.7.0


find the attachement above or at the recent posts in this thread

Here also once more an example-script about the in the title of this thread mentioned -and their related- functions as they work now:



Uses "Console"
#INCLUDE "lazyFun.tBasicU"

Type t_type
A As Long
B As Byte
C As String
End Type
Dim hut(3) As t_type

String foo
DWord myPtr, test
Long i

PrintL "change a simple variables content using SetStr" + $CRLF
SetStr "foo", "I am new content of foo now"
PrintL foo

PrintL Get$("foo")
' retrieve a pointer:
myPtr = GetPtr("foo")
' in case String use StrAtPtr$
PrintL StrAtPtr$(myPtr)
PrintL

' numeral:
SetStr "test", MKDWD$(12345)
PrintL "Value at test:" + Str$(test)

myPtr = GetPtr("test")
PrintL Peek(DWord, myPtr)

PrintL CVDWD(Get$("test",,SizeOf(DWord)))


PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL "fill in some data to udt-array:" + $CRLF

For i = 1 To UBound(hut)
hut(i).A = 42 * i
PrintL "hut("+i+").A:" + Str$(hut(i).A)

hut(i).B = i
PrintL "hut("+i+").B:" + Str$(hut(i).B)
hut(i).C = "I am hut("+i+").C"
PrintL "hut("+i+").C: " + hut(i).C
PrintL
Next

PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL "retrieve data of one complete array-element: hut(2)"+ $CRLF
PrintL "using Get$"
foo = Get$("hut", 2, SizeOf(t_Type))

PrintL "A: " + Peek(Long, StrPtr(foo))
PrintL "B: " + Peek(Byte, StrPtr(foo) + SizeOf(Long))

' StrAtPtr$ will return the string stored at passed Pointer
PrintL "C: " + StrAtPtr$(PeekPtrAt StrPtr(foo) + UDT_ElementOffset(hut(1).C))

PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL "retrieve data of dynamic udt sub-string hut(3).C" + $CRLF
PrintL "using GetDataPtr"

myPtr = GetDataPtr("hut", 3, UDT_ElementOffset(hut(1).C), SizeOf(t_Type) )

Print "hut(3).C: " ' in case udt-substring have to peek the pointer at myPtr:
PrintL StrAtPtr$(PeekPtrAt myPtr)

' in other cases peek the value directly at myPtr
myPtr = GetDataPtr("hut", 3, UDT_ElementOffset(hut(1).A), SizeOf(t_Type) )
PrintL "hut(3).A:" + Str$(Peek(Long, myPtr))

PrintL $CRLF + "change data of dynamic udt sub-string:" + $CRLF
PrintL "using SetUdtStr"
SetUdtStr "hut", 3, UDT_ElementOffset(hut(1).C), SizeOf(t_Type), "Now I have been changed"

PrintL $CRLF + "re-check: " + hut(3).C
' make sure it's correct here too:
myPtr = GetDataPtr("hut", 3, UDT_ElementOffset(hut(1).C), SizeOf(t_Type) )
PrintL StrAtPtr$(PeekPtrAt myPtr)

PrintL "-----------------------------------------"
PrintL $CRLF + "key to end" + $CRLF
WaitKey

So there's just to say, GetPtr-Function will return immediately the correct pointer - either VarPtr or StrPtr while GetDataPtr always returns pointer to the data, which is in case string... a stringpointer

Small change to Heap_Mid$-Function to match the functionalities of Heap_Left$/Heap_Right$ so this takes now an optional Byte-parameter to fill missing bytes with its value
Also accepts negative start-value now to append bytes in front, if passed Len exceeds Heap in any way the rest will be filled with the passed bFill-byte or 0 by default

usage example:



Uses "console"
#INCLUDE "LazyFun.tBasicU"


DWord foo = HEAP_AllocByStr(Repeat$(4,"123456789|"))

' test get entire heap
PrintL Heap_Mid$(foo, 1, HEAP_Size(foo))

' get 40 bytes, thus append left 10 spaces and use 30 from heap
PrintL Heap_Mid$(foo, -10, 40, Asc(" "))

' get 40 bytes, start at byte 11, use heap till end and fill desired len
PrintL Heap_Mid$(foo, 11, 40, Asc("."))

' get 50 bytes, even if Heap is smaller, start to fill 5 bytes in front
PrintL Heap_Mid$(foo, -5, 50, Asc("+"))

Heap_SetAt VarPtr foo, "" ' free the Heap and update the pointer stored in foo

PrintL "----+----|----+----|----+----|----+----|----+----|"
PrintL $CRLF + "any key to end" + $CRLF

WaitKey

ReneMiner
24-07-2013, 21:12
An additional example - use the attachement above :

new function

Heap_ElementRemoveAt
which allows to remove an element inside a row of even sized elements stored to heap-memory. As the name tells it awaits a position where to find/save the pointer.


Uses "Console"
#INCLUDE "lazyFun.tBasicU"

Type t_type
S1 As DWord
S2 As DWord
End Type

Type t_Subtype
A As Long
B As Byte
C As Double
End Type

Dim foo(3) As t_type
Dim dummy As t_Subtype
Dim i As Long

For i = 1 To 3
' now tell foo(2).S1 to hold something:

dummy.A += 12
dummy.B += 3
dummy.C += 4.5
Heap_AppendAt(VarPtr(foo(2).S1), Memory_Get(VarPtr(dummy), SizeOf(t_Subtype)) )

Next i
' retrieve data:
Dim dArray(HEAP_Size(foo(2).S1)\SizeOf(t_SubType)) As t_SubType At foo(2).S1

For i = 1 To UBound(dArray)
' PrintL "element" + Str$(i)
PrintL "A:" + dArray(i).A
PrintL "B:" + dArray(i).B
PrintL "C:" + dArray(i).C
PrintL
Next

PrintL $CRLF + "key to continue" + $CRLF
WaitKey

' create a copy at foo(3).S1
foo(3).S1 = Heap_Copy(foo(2).S1)
dummy.A = 77
dummy.B = 77
dummy.C = 77

PrintL $CRLF + "now insert new element 2"

Heap_ElementInsertAt(VarPtr(foo(3).S1), 2, Memory_Get(VarPtr(dummy), SizeOf(t_Subtype)) )

ReDim dArray(HEAP_Size(foo(3).S1)\SizeOf(t_SubType)) At foo(3).S1

For i = 1 To UBound(dArray)
' PrintL "element" + Str$(i)
PrintL "A:" + dArray(i).A
PrintL "B:" + dArray(i).B
PrintL "C:" + dArray(i).C
PrintL
Next

PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL $CRLF + "now remove element 2"
Heap_ElementRemoveAt VarPtr(foo(3).S1), 2, SizeOf(t_Subtype)

ReDim dArray(HEAP_Size(foo(3).S1)\SizeOf(t_SubType)) At foo(3).S1

For i = 1 To UBound(dArray)
' PrintL "element" + Str$(i)
PrintL "A:" + dArray(i).A
PrintL "B:" + dArray(i).B
PrintL "C:" + dArray(i).C
PrintL
Next

PrintL $CRLF + "key to end" + $CRLF
WaitKey

ReneMiner
25-07-2013, 14:41
Store data at heap in up to 8 dimensions now - accessible through one single pointer
I think theres no problem to raise that to 31 dimensions... :dance1:but I think 8 dimensions should serve the most usual needs. If it happens to you that you are in need of 42 dimensions then the call has to be changed slightly to pass all these parameters.

Now there are additional:

Heap_OrganizeAt
Heap_OrganizeAddress
Heap_OrganizerFreeAt
Heap_OrganizerGetDim$

One script-example to this:


Uses "Console"
#INCLUDE "lazyFun.tBasicU"

Type t_Type
A As Long
B As Byte
C As DWord
End Type

DWord foo ' here we node heap
DWord myPtr
Dim dummy As t_Type At 0 ' virtual "peekhole"

' setup the dimensions in following way:
' fixed-size way:
' somewhat like "Dim Heap foo(5,4,3,5) as t_Type"
' currently maximum of 8 dimensions possible
If Heap_OrganizeAt( VarPtr(foo), MKDWD$(5, 4, 3, 5), SizeOf(t_Type) ) Then
' this call will setup TWO heaps now:
' one as the organizer which holds pointer to data-heap and
' information about dimensions - this one is quite small, depending
' on count of dimensions 4 Byte per dimension + a pointer + size,
' ( in this example here 24 Byte )
' and an additional heap wich will store the actual data. It depends
' on dimensions and usage, can become quite large...
' the first dword at position of "organizer"-heap(foo) will hold the pointer to the
' data-heap then, the second dword is the size of one element if fixed - or 0 if not
' the following dwords hold the dimensions in the passed order

' this call requests the pointer of element 1,1,1,1 in organized heap foo
myPtr = Heap_OrganizeAddress( foo, 1, 1, 1, 1 )

If myPtr Then
SetAt(dummy, myPtr) ' put the dummy-pattern onto this position
dummy.A = 11 ' and put some values there
dummy.B = 11
dummy.C = 11
Else
PrintL "no pointer?"
EndIf

SetAt(dummy, Heap_OrganizeAddress( foo, 5, 4, 3, 5 ))
dummy.A = 22
dummy.B = 22
dummy.C = 22

SetAt(dummy, Heap_OrganizeAddress( foo, 3, 3, 3, 3 ))
dummy.A = 33
dummy.B = 33
dummy.C = 33

PrintL "Get back for 1,1,1,1"
SetAt(dummy, Heap_OrganizeAddress( foo, 1, 1, 1, 1 ))
PrintL dummy.A
PrintL dummy.B
PrintL dummy.C
PrintL

PrintL "Get back for 5,4,3,5"
SetAt(dummy, Heap_OrganizeAddress( foo, 5, 4, 3, 5 ))
PrintL dummy.A
PrintL dummy.B
PrintL dummy.C
PrintL

PrintL "Get back for 3,3,3,3"
SetAt(dummy, Heap_OrganizeAddress( foo, 3, 3, 3, 3 ))

PrintL dummy.A
PrintL dummy.B
PrintL dummy.C
PrintL $CRLF + "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

' remove the virtual "Peekhole" before killing memory:
SetAt(dummy, 0)

Heap_OrganizerFreeAt VarPtr foo

' variable foo holds the position of where heap(foo) can be found
' which is the "organizer"

' at that position inside the organizer stored is the pointer
' to organized "data-heap" which has been released now too


EndIf

' unfixed-size way:
' more "complicated" but dynamic in elements-size
' setup some new dimensions

' the element size in the organizer becomes SizeOf(Dword) automatic - do not pass a size here to stay unfixed!
' omit size or pass 0 to organize pointers where you can organize heap of different sizes in each element.
' so on "cleanup" using Heap_OrganizerFreeAt the function "knows" that there are probably pointers to
' allocated heap which has to be deleted too

If Heap_OrganizeAt( VarPtr(foo), MKDWD$(3,4,5) ) Then
' creates two heaps: one to store information and one
' supposed to store just pointers where your data can be found

myPtr = Heap_OrganizeAddress(foo, 1, 2, 3)
' here this call requests the address where the pointer shall be stored
' since we want to store a pointer to some heap here

' now put there some data to store:

Heap_SetAt myPtr, "this is data 1 2 3"
'which creates heap "this is data 1 2 3" and stores the pointer at myPtr
PrintL Heap_Get$(PeekPtrAt myPtr)
' request pointer: - in case use it more than once it's better to save the
' result local instead of calculating the position again
myPtr = Heap_OrganizeAddress(foo, 3, 4, 5)
Heap_SetAt myPtr, "and this is data 3 4 5" ' size does not matter...
PrintL Heap_Get$(PeekPtrAt myPtr)
' re-check:
PrintL Heap_Get$( PeekPtrAt Heap_OrganizeAddress(foo, 1, 2, 3) )
' free resources:
Heap_OrganizerFreeAt(VarPtr(foo))
' the organizer will not delete any noded sub-organizers !
' but it will delete all heap wich was organized through
' foo here so the data is gone now!
' Either free noded sub-organizers in advance - or they are lost

PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

EndIf
' next test, 2 dimensions, fixed size

If Heap_OrganizeAt( VarPtr(foo), MKDWD$(77, 99), SizeOf(Double) ) Then
' fill in some data
myPtr = Heap_OrganizeAddress(foo, 1,1 )
If myPtr Then
Poke(Double, myPtr, 1.1)
Else
PrintL "no pointer?"
EndIf

Poke(Double, Heap_OrganizeAddress(foo, 2,2 ), 2.2)
Poke(Double, Heap_OrganizeAddress(foo, 66,66 ), 66.66)
Poke(Double, Heap_OrganizeAddress(foo, 77,77 ), 77.77)

myPtr = Heap_OrganizeAddress(foo, 1,1 )
If myPtr Then PrintL "re-check: 1,1: " + Peek(Double, myPtr)

PrintL "re-check: 2,2: " + Peek(Double, Heap_OrganizeAddress(foo, 2,2 ))
PrintL "re-check: 66,66: " + Peek(Double, Heap_OrganizeAddress(foo, 66,66 ))
PrintL "re-check: 77,77: " + Peek(Double, Heap_OrganizeAddress(foo, 77,77 ))

PrintL $CRLF + "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

Heap_OrganizerFreeAt VarPtr foo

EndIf

' now it gets crazy: 5 Dimensions where elements can vary in size
'============================================
' DON'T RUN THIS ON A WEAK SYSTEM !
'============================================

If Heap_OrganizeAt( VarPtr(foo), MKDWD$(12, 23, 34, 45, 56) ) Then
'= 23647680 addresses...= 94 590 720 Bytes to store just the pointers...
myPtr = Heap_OrganizeAddress(foo, 6,11,17,22,28)
If myPtr Then
Heap_SetAt myPtr, "this is data 6, 11, 17, 22, 28"
PrintL Heap_Get$(PeekPtrAt myPtr)
Else
PrintL "no pointer?"
EndIf

myPtr = Heap_OrganizeAddress(foo, 7,7,7,7,7)
Heap_SetAt myPtr, "this is data 7,7,7,7,7"
PrintL Heap_Get$(PeekPtrAt myPtr)

PrintL "Re-check: " + Heap_Get$( PeekPtrAt Heap_OrganizeAddress(foo, 6,11,17,22,28) )
PrintL "Re-check: " + Heap_Get$( PeekPtrAt Heap_OrganizeAddress(foo, 7,7,7,7,7) )

' next commented on purpose:
' Heap_OrganizerFreeAt VarPtr foo - needs very long- we're finished anyway
EndIf
PrintL $CRLF + "-----------------------------------------"
PrintL $CRLF + "key to end" + $CRLF
WaitKey


Don't forget- you can "append" such a thing to anything that has 4 Bytes


another small - hopefully now very easy to understand one that shows how to use heap to store "multidimensional array of pointers"


Uses "Console"
#INCLUDE "lazyFun.tBasicU"

' very simple example 3-dimensions, arbitrary size of each sub-element

DWord foo
DWord myPtr
Long i, j ,k

' setup the dimensions:

If HEAP_OrganizeAt( VarPtr(foo), MKDWD$(2,3,4) ) Then
For i = 1 To 2
For j = 1 To 3
For k = 1 To 4
myPtr = Heap_OrganizeAddress( foo, i, j, k )
If myPtr Then
Heap_SetAt myPtr, "i="+i+" j="+j+" k="+k
PrintL "got there: " + Heap_Get$(PeekPtrAt myPtr)
EndIf
Next
Next
Next

PrintL
PrintL "now get back the stuff:"
For i = 1 To 2
For j = 1 To 3
For k = 1 To 4
PrintL "Re-check: " + Heap_Get$( PeekPtrAt Heap_OrganizeAddress( foo, i, j, k ) )
Next
Next
Next

Heap_OrganizerFreeAt VarPtr foo ' no real need here since script ends now...

EndIf
PrintL "-----------------------------------------"
PrintL $CRLF + "key to end" + $CRLF
WaitKey



no protest? Is it really that easy?

Billbo
26-07-2013, 00:35
Rene,

Could you please number your programs when you update them?

Bill

ReneMiner
26-07-2013, 10:47
Updated again - I have made some minor change to syntax of Heap_InsertAt which is named now Heap_ElementInsertAt. The function Heap_InsertAt will insert data now at an absolute position.

There are about 27 functions inside the attachement - that's why its version 0.27 :wink: >> Functions-Overview (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400) <<

Also new Heap_ElementGet$ which returns data of the certain element - all that "Element"-functions assume to work with some "array" their elements all have same size.



Uses "Console"
#INCLUDE "lazyFun.tBasicU"


DWord foo
' Heap_ElementInsertAt will treat the data to insert if it was an
' element in an array

Heap_SetAt VarPtr foo, "+11++22++33++55+"
PrintL Heap_Get$ foo
PrintL
PrintL "Insert 'x44x' to be element #4"
Heap_ElementInsertAt VarPtr foo, 4, "x44x"

PrintL Heap_Get$ foo
PrintL
' now remove element 3 with a size of 4 bytes
PrintL "Remove element #3 with a size of 4 bytes:"
Heap_ElementRemoveAt VarPtr foo, 3, 4
PrintL Heap_Get$ foo
PrintL
' insert data at absolute position of heap foo:
PrintL "Insert data '*33*' at absolute position 9:"
Heap_InsertAt VarPtr foo, 9, "*33*"
PrintL Heap_Get$ foo
PrintL

PrintL "retrieve element #3 with a size of 4 bytes"
PrintL Heap_ElementGet$( foo, 3, 4 )
PrintL
PrintL "-----------------------------------------"
PrintL $CRLF + "key to end" + $CRLF
WaitKey


Functions are documented within code. I also updated all code-examples and docs within this thread - so these are also still valid.

ReneMiner
27-07-2013, 11:00
"ReDim" multidimensional heap is possible with already available methods quite easy, so there's no need for an update here, nor a need for special functions to do this.

The example shows how to "redim" multidimensional heap in the same amount of dimensions. In fact, it creates a new organized heap and just transferes the data from old to new heap.



Uses "Console"
#INCLUDE "lazyFun.tBasicU"

' "redim" organized heap - example
' same amount of dimensions but different dimension-sizes then

DWord foo, fresh
DWord myPtr
Long i, j ,k

' setup the dimensions for foo:

If Heap_OrganizeAt( VarPtr(foo), MKDWD$(2,3,4) ) Then

For i = 1 To 2
For j = 1 To 3
For k = 1 To 4
myPtr = Heap_OrganizeAddress( foo, i, j, k )
If myPtr Then
Heap_SetAt myPtr, "i= "+i+" j= "+j+" k= "+k
PrintL "got there: " + Heap_Get$(PeekPtrAt myPtr)
EndIf
Next
Next
Next

PrintL
PrintL "recheck:"
For i = 1 To 2
For j = 1 To 3
For k = 1 To 4
PrintL Heap_Get$( PeekPtrAt Heap_OrganizeAddress( foo, i, j, k ) )
Next
Next
Next

PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

' now create organized heap 'fresh' in some bigger dimensions:
' the new heaps "fixed-size or not"-switch has to match the old heap settings
' you can not transfer data from fixed-size to unfixed-size "organized heap".

If Heap_OrganizeAt( VarPtr(fresh), MKDWD$(3,4,5) ) Then
PrintL "new heap 'fresh' has been organized now"
' now transfer the data to new organized heap "fresh" from "foo" :
For i = 1 To 2
For j = 1 To 3
For k = 1 To 4
' now swap the pointers -SizeOf(Dword)- from old & new heap
' inside the shared dimension-sizes of "foo" and "fresh" only of course

Memory_Swap( Heap_OrganizeAddress( foo, i, j, k ), Heap_OrganizeAddress( fresh, i, j, k), SizeOf(DWord))

' in a fixed size organized heap you would just pass the sizeOf(some type)
' if transferring fixed-size of different element-size- be sure to just
' transfer the size of the smaller elements.
Next
Next
Next
PrintL "done swapping"
PrintL

' just quick show how to retrieve the dimensions
String sDims = Heap_OrganizerGetDim$(fresh) ' ask for information
' length of returned string/Sizeof(Dword) = number of dimensions

' every Dword holds the count of elements in this dimension
For i = 1 To StrLen(sDims)/SizeOf(DWord)

Print "Dimension" + Str$(i) + " of 'fresh' has"
PrintL Str$( Peek(DWord, StrPtr(sDims) + (i-1) * SizeOf(DWord))) + " elements"
Next
PrintL

' free the old organizer...
Heap_OrganizerFreeAt VarPtr foo

' be sure to have used Memory_Swap - especially in UNFIXED organized heap,
' else Heap_OrganizerFreeAt would have deleted all you data now since it
' would have found valid heap-pointers to delete still organized in foo...

PrintL "-----------------------------------------"
PrintL $CRLF + "key to continue" + $CRLF
WaitKey

PrintL "now get back the stuff:"
PrintL " i j k"
For i = 1 To 3
For j = 1 To 4
For k = 1 To 5
PrintL Str$(i)+Str$(j)+Str$(k) +" : " + Heap_Get$(PeekPtrAt Heap_OrganizeAddress( fresh, i, j, k ) )
Next
Next
Next
EndIf
EndIf
PrintL "-----------------------------------------"
PrintL $CRLF + "key to end" + $CRLF
WaitKey


If you want to raise the amount of dimensions , maybe fresh(3,4,5,6) you would request for all elements the new address alike this


Memory_Swap( Heap_OrganizeAddress( foo, i, j, k ), Heap_OrganizeAddress( fresh, i, j, k, 1), SizeOf(DWord))

and order the "old" elements just to the first index(1) of the new dimension.
Lowering the amount of dimensions is probably a thing that's never needed, but then it were vice versa, you could only transfer one element-index of the dimension to delete.

Of course variable 'fresh' here might be just some local, so after


Heap_FreeOrganizerAt VarPtr foo

assign simply


foo = fresh : fresh = 0
'or
Memory_Swap( VarPtr(foo), VarPtr(fresh), SizeOf(Dword) )

to have the new dimensioned heap organized at old "foo" while "fresh" is free again.

ReneMiner
27-07-2013, 14:27
Another function to make life easier :)

Heap_ElementGetPtr



Uses "Console"
#INCLUDE "lazyFun.tBasicU"

' example Function Heap_ElementGetPtr
' on dynamic sub-arrays of pointers to dynamic "sub-heap"

%PointerSize = SizeOf(DWord) ' = better readable

DWord foo
DWord myPtr

Long i

' setup 10 dynamic sub-elements to foo, so
' make space for 10 pointers...

foo = HEAP_Alloc(10 * %PointerSize)

If foo Then
' foo we interpret now as "heaped array" that has same-sized elements -
' in this case 10 pointers - but that could change. What not changes is
' %Pointersize which is SizeOf(one element) of the "heaped array" -
' so the Element-stuff always assumes elements of same size - have to pass
' the size always -except when passing an element- thats length will inform
' the function of the element-size in this "heaped array"

For i = 1 To 10
'retrieve a pointer to element foo(i)

myPtr = Heap_ElementGetPtr(foo, i, %PointerSize)

Heap_SetAt myPtr, "I am heap foo(" + i + ").Data"
' this creates some new heap with the passed string and stores its address to
' the in myPtr specified position - wherever that is - can be a variables position or within other heap


Next
' now just for fun go backward and pick only every second
For i = 10 To 1 Step - 2
myPtr = Heap_ElementGetPtr(foo, i, %PointerSize)

' peek out the pointer to data at the returned address

If myPtr Then PrintL Heap_Get$( PeekPtrAt myPtr )

Next

PrintL "'Ubound' foo = " + Str$( HEAP_Size(foo)/%PointerSize )

PrintL $CRLF + "-----------------------------------------"
PrintL $CRLF + " key to continue" + $CRLF
WaitKey
' exchange data of "foo(7).Data":
Heap_SetAt Heap_ElementGetPtr(foo, 7, %PointerSize), "now I'm changed - i am number 7"
' will create new heap with the passed content
' release heap found at the pointer of old number 7 also
' and store the new pointer at the specified position

' retrieve data as string:
PrintL Heap_Get$( PeekPtrAt Heap_ElementGetPtr(foo, 7, %PointerSize) )

PrintL $CRLF + "now insert one:" + $CRLF

Heap_ElementInsertAt VarPtr(foo), 7, MKDWD$(HEAP_AllocByStr( "let me be #7!" ))
' which will insert the pointer received by Heap_AllocByStr as new element 7 to heap at foo
' once again : all Heap_...At-functions await a position where to find or store the pointer

PrintL "'Ubound' foo = " + Str$( HEAP_Size(foo)/%PointerSize )

' you can append new elements to foo also just using
' Heap_AppendAt VarPtr(foo), MKDWD$(Heap_AllocByStr("NewData"))
' which just "appends" the result of HeapAllocByStr to memory found in heap at foo and saves
' data to new heap, then releases the old memory (if some) and updates the passed position with the new pointer
' therefore it does not need any special Heap_ElementAppendAt-function, so use the "ordinary" one

' now foo has 11 sub-elements...
For i = 1 To HEAP_Size(foo)/%Pointersize
myPtr = Heap_ElementGetPtr(foo, i, %PointerSize)

PrintL Heap_Get$( PeekPtrAt myPtr )
' in case of removing elements you should free the noded sub-heap before
Heap_SetAt myPtr, "" '- will free the heap that's address is stored in myPtr

' therafter you could call Heap_ElementRemoveAt VarPtr foo, Index, %Pointersize
' to eliminate the pointer-space also- don't do this now within this loop
'[] Edit: in the meantime there's Heap_ElementFreePtrAt which will do both in one call

' you could use Heap_SetAt( myPtr, "") to release heap and update pointers also

Next
Heap_SetAt VarPtr foo, ""
' also valid: Heap_ResizeAt( VarPtr(foo), 0 ) to free heap and update the pointer
EndIf

PrintL $CRLF + "-----------------------------------------"
PrintL $CRLF + " key to end" + $CRLF
WaitKey



I think there's no need to explain that function on elements of other size than pointers
- there you would not peek the pointer and pass %PointerSize but instantly the data in your desired element-size, probably using Heap_ElementGet$

Do not mess up elements-functions (one-dimensional) with organizer functions (multi-dimensional) !

Functions-Overview (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400)

If you wish any functions of this to be implemented or to become a module please press the "Like-Button" below :comp1:

ReneMiner
28-07-2013, 11:04
However- I often ran into the problem that there might be no pointer at a certain address returned by some function - or the function returned 0 - so I had to make sure not to Peek at 0 and either store the result somewhere or call the function twice. So I added very small function PeekPtrAt which just peeks Dwords there if it's a valid Address, else returns 0 of course.

PeekPtrAt

usage example:


#MINVERSION 1.9.7.0

Uses "console"
#INCLUDE "LazyFun.tBasicU"

' PeekPtrAt - safe peeking pointers-example
' at return-value of Heap_GetElementPtr
' of course also usable together with Heap_OrganzieAddress
' and any other functions that return pointers or 0.

%PointerSize = SizeOf(DWord) ' reads better

DWord myHeap
Long i

' just create some sub-array and fill it
For i = 1 To 5
Heap_AppendAt VarPtr(myHeap), MKDWD$(HEAP_AllocByStr("i am number" + Str$(i)))
Next

' now read back - on purpose more than we have...Heap_ElementGetPtr would return 0
' Heap_Get$ will return empty string then

For i = -1 To 6
PrintL Heap_Get$( PeekPtrAt Heap_ElementGetPtr(myHeap, i, %Pointersize) )
Next

PrintL $CRLF + Repeat$(5, "----------") + $CRLF
PrintL "any key to end"

WaitKey

Edit: All examples in this thread have been updated and lots of them are making use of this function now too
:excited:

ReneMiner
28-07-2013, 20:19
At least the code is posted here- full of possible solutions for problems that none will ever have ? :roll:

This is an "ideas forum" - and this is just my idea - make tB easier, comfortable, understandable. So here I post what I think which methods or functions can be of use - and all the functions already exist now - at least prototyped in thinBasic, maybe some professional programmer could have a look over these and optimize them - but I'm just a hobbyist - I can't do any better and I do it just for fun. This is just to tell in what kind of direction I would like thinBasic to evolute.

I could very well imagine that oxygen could do all those calculations - a lot faster, or if these functions were compiled in some other way could also raise the performance - but until I get this kind 'a stuff in oxygen together - that might be 2017 or later because I think it would be better to use oxygen-assembler than oxygen-basic...

Petr Schreiber
29-07-2013, 08:41
Please continue Rene :) I think this is the best way to "soft forge" functionalities, which could be later moved to Core, if proven to be useful (which they seem to me).

Petr

ReneMiner
29-07-2013, 12:09
The LazyFun.tBasicU includes in the meantime more of heap than the in the title of the thread mentioned stuff about variables-"byName". Maybe these are two different things- but both make use of some other lazy functions that are also included. Altogether it's a collection of pointer+heap-functions (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400).

the "byName"-functions provide great flexibility in multiple usable functions that make use of user-data. Imagine your code provides a Listview/Grid of whatever kind to display user-data. The user can assign the names of the variables at which your Listview-code can find the data to display or to set the changed data. Even after the user redimmed or whatever - no problem if the pointer has changed- variables name is still the same.
But for the "full-power-functionality" I see the need of a function to retrieve the PatternOf(<a type>), maybe as String (like "BLLLL$$$$" means Byte, L-Long(4 bytes) ,$-dynamic string, 4 bytes signalize stringpointer, nested subtypes could be inserted in brackets- but that would result in a different length of the pattern- so maybe just one L for a long...) - I dont know - maybe can be a pointer to the real structure... This would allow to dynamical create virtual overlays to variables of unknown type. Would probably need an additional function to specify this as type. Example how I imagine that:



Type t_Type
A as ...
B as ...
PhoneNum as String
End Type
Dim foo(123) as t_Type

Control Add Listview hDlg, myLV ...
Lisview SetDataArray hDlg, myLV, "foo", PatternOf(t_Type)

' %Type_IsString = 30 ' ;) - I imagine some built-in equates here too
' ...ListView SetColumnData hDlg, myLV, colNum, "Phone Number", %Type_IsString, Udt_ElementOffset(foo(1).PhoneNum)
' ...

Function whateverListview()
'sPattern be the assigned value through PatternOf() above
'sName contains the assigned value through "foo" above

Local x as UDT_Signature(sPattern) At GetPtr sName

End Function

So the "byName"-stuff is not really done in my eyes - there are more possibilities raising at the horizon, I did hide a few ideas in the script above and on many places else in this whole thread...

Heap offers great freedom in storing stuff of all kinds. But whenever one uses it - one has to create own functions to organize the data somehow and everyone has to create more or less functions that work like these. Whenever before I start to code a project i have to think about organizing my data. How to store and how to retrieve it, how to change it. Often it's the case not all elements of data do have the same sub-elements or they have to be dynamic. Before I had no idea how to manage this and not loosing overview here. I think now I have written the functionalities and the idea that you have more time left to code your programs instead of thinking about how to manage and organize the data your programs are supposed to work with as flexible as you need it.

The advantage of heap compared to usual variables is the freedom to expand in any dimensions and to append dynamically as much as needed and wanted. A disadvantage is of course the data is not all in one row as in a variable- so one can not peek all the "sub-heaps" at once - while that also keeps dimensioning times small since never the whole variable space has to be (re-)allocated but just the space for current to changed items [+subitems] data.

Before making this a module or adding it to core - we could discuss about it here - maybe something can done better, easier, faster, safer - perhaps something more is needed?

ReneMiner
29-07-2013, 20:41
What does DLLC mean? Google says Departement of Languages, Literature and Culture or Departement of Liquor Licenses and Control. - I guess some DLL-compiling-stuff? So please don't let me die as stupid as I feel now :D

Charles Pegge
29-07-2013, 21:35
It's a generic module for interfacing ScriptBasic to DLLs without using extension modules. Department of Liquor Licenses and Control: I'll go for that :D

ReneMiner
30-07-2013, 17:08
One addition to the Heap_Instr-function. I think it'll be better if it returns the pointer to the position instead of the position - but I did not change it yet- since Heap_Instr was one of the first functions in that unit - and honestly I did not need it yet. It was just made because it's possible ;)

Edit: squeeze simple example in here. It shows how to use heap to store dynamic one-lined text-items all in one heap using the powers of Parse-function.


Uses "console"
#INCLUDE "lazyFun.tBasicU"

' - example storing one-lined "text-items"
' of different length simply by using some $CRLF as delimiter


' any 4 bytes to store a pointer
DWord foo = HEAP_AllocByStr( "I am one !" + $CRLF _
+ "I am two !!" + $CRLF _
+ "I am three !!!" + $CRLF _
+ "I am four !!!!" + $CRLF )

PrintL Heap_Get$(foo)
PrintL $CRLF + "now append five"

Heap_AppendAt VarPtr foo, "I am five !!!!!" + $CRLF

PrintL $CRLF + "key to continue"
PrintL $CRLF + Repeat$(50,"-") + $CRLF
WaitKey

Dim sData() As String

Long i = Parse( Heap_Get$ foo, sData, $CRLF )
' a $crlf at the end of data will parse into one item more than there are
' ubound(sData) is 6 here now!

' this does the trick then:
If Heap_Right$(foo, 2) = $CRLF Then i -= 1

' on the other side:
' a higher ubound instantly offers space for a new element here
' without the need to redim...

While i > 0
PrintL "item" + Str$(i)+": " + sData(i)
i -= 1
Wend

PrintL $CRLF + Repeat$(50, "-") + $CRLF
PrintL "key to end" + $CRLF
WaitKey

ReneMiner
31-07-2013, 11:04
Edit

these functions:

Heap_ElementScanPtr
Heap_ElementScanIndex

have been removed again

ReneMiner
31-07-2013, 12:55
function to manage palette-like series of unique entries like colors, vertices etc.

Heap_ElementIDAt

which will tell the index of an element in "heaped array" matching the data to search for. If an element with matching data does not exist it will be created (and also return the index of the new element then)

tiny example:


Uses "console"
#INCLUDE "lazyFun.tBasicU"

' - example
' Heap_ElementIDAt

' assumed example-type
' (must not contain dynamic strings!)
Type t_Type
R As Byte
G As Byte
B As Byte
End Type

DWord foo ' any address to store 4 bytes will serve...

' the function will check for this elements index
' and create the element if not exists
PrintL Heap_ElementIDAt VarPtr foo, MKBYT$(255,0,0)
PrintL Heap_ElementIDAt VarPtr foo, MKBYT$(0,255,0)
PrintL Heap_ElementIDAt VarPtr foo, MKBYT$(0,0,255)

' returns just element-index if element already exists
PrintL "check index:" + Heap_ElementIDAt VarPtr foo, MKBYT$(0,255,0)

PrintL "'ubound':" + Str$( HEAP_Size(foo)/SizeOf(t_Type) )

PrintL $CRLF + Repeat$(5, "----------") + $CRLF
PrintL "key to end" + $CRLF
WaitKey


Functions-Overview (http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400)

ReneMiner
31-07-2013, 19:37
Another one

Heap_ElementSet
set data of existing element to new content



Uses "console"
#INCLUDE "lazyFun.tBasicU"

' - example
' Heap_ElementSet

' example-type
' (must not contain dynamic strings!)
Type t_Type
A As Long
B As Byte
C As Double
End Type
Long i

Dim dummy As t_Type At 0
' Heap_ElementSet will only work on existing elements

' any 4 bytes to store 5 elements of t_Type
DWord foo = HEAP_Alloc(5 * SizeOf(t_Type) )

DWord myPtr = Heap_ElementSet foo, 1, MKL$(11)+ MKBYT$(1)+ MKD$(1.11)

PrintL "check the result:"
SetAt(dummy, myPtr)
PrintL dummy.a
PrintL dummy.b
PrintL dummy.c
PrintL

For i = 2 To 5
Heap_ElementSet foo, i, MKL$(11*i)+ MKBYT$(i)+ MKD$(1.11*i)
Next
PrintL "filled in 5 elements"

Heap_AppendAt VarPtr foo, MKL$(66) + MKBYT$(66) + MKD$(6.66)
PrintL "and appended one..."

PrintL
PrintL $CRLF + "key to continue"
PrintL $CRLF + Repeat$(5,"----------") + $CRLF
WaitKey

For i = 1 To HEAP_Size(foo)/SizeOf(t_Type)
PrintL "element"+ Str$(i)
SetAt(dummy, Heap_ElementGetPtr foo, i, SizeOf(t_Type) )
PrintL dummy.a
PrintL dummy.b
PrintL dummy.c
PrintL
Next

PrintL $CRLF + Repeat$(5, "----------") + $CRLF
PrintL "key to end" + $CRLF
WaitKey

ReneMiner
01-08-2013, 09:13
Not a new version nor function this time, but some illustration to differ items in a row of elements in a "heaped array" from items in "organized heap" and how they work.
The red dot in the top left corner is actually the pointer to heap.

Elements - whatever they are: pointers or data - are just ordinary row of bytes in repeated order stored directly to the heap. Just like 1-dimensional arrays.

Organizer - is a heap that just holds 3 things: pointer to organized heap, if fixed then size else 0, 1 number per dimension tells ubound. The pointer to the organized heap is the first dword found at position of the organizer. So organizer requires 2 heaps that will be created by Heap_OrganizeAt. It requires at least 2 dimensions and can manage currently up to 8 dimensions with at least 2 items per dimension.

Elements and Organizer work with same sized items that must not contain dynamic strings *. These items - (enumerated 1 to 9) can be either the items data or pointers to the items data. In organized heap the organizer-functions take care of this as much as possible so one passes a SizeOf(one item) to make the grid hold the items data - or omit a size so the grid is supposed to hold pointers to the items data. If using elements, one has to care himself and setup the size of one element either to size of item or size of pointer.

Storing pointers allows the subitems to have different sizes while storing the items data directly as elements or in organized heap only works with same-sized items. The advantage of storing pointers is, that sub-items can be totally different types - even lists of more pointers. It allows even different items to "share" the same subitem. When doing so, my advice: don't attach the pointer to the subitem directly to these items - but store a position where to find a pointer - so if the shared data changes and might get a new address it just has to be stored there and all items sharing this data are up-to-date since they "know" where to find the correct pointer.
Also if storing pointers the heap containing the pointers is small in size - especially when adding/removing elements the size of memory to be re-allocated is 4 bytes per pointer - so this won't surely need as long as all at once. Changing any subitem then will only affect the memory-size of the subitem while the already existing pointer-space just changes its value.

On the other hand - storing the items data directly allows to retrieve all data at once and does not make it necessary to peek all data together from different places when it comes to save the data. Especially elements allow easy virtual overlay on data-items.

A list of elements can be changed in size anytime with not much effort, there are a few functions to this. Elements are very dynamic though. But to resize organized heap in it's dimensions there's currently no other way than creating a new organizer and transfering the data within the shared bounds of old and new organizer. See previous page of this thread for an example (http://www.thinbasic.com/community/showthread.php?t=12174&page=3&p=89418#post89418) to this.

*) if you know what you are doing you might include dynamic strings - but it's not easy to keep overview...

ReneMiner
01-08-2013, 20:43
The goal is just to have functions that do repeatedly used sequences of calls in an understandable and easy way because it's much faster to write, read and remember a function name than typing each time some mindcranking 3-line formula, always check if valid etc... as the name says - lazy. My standard here is to have some extreme dynamic memory-management which variables and udts - as they are - can not fulfill to my satisfaction.
Oh what english - i'll surely get some creativity-diploma in literature for that -but wait- there's more of my fortune-cookie-wisdom:

The point is, to store dynamic data it needs extendable types with flexible dimensions and unlimited ability to extend or expand. Because the core has to work in a secure and safe way it does not allow experiments here and needs fixed structures anyway.

But- we have an interpreter and it's our beer how we interpret the data. Heap gives great freedom because it encapsulates the data in some clearly arranged frame like a sandbox and one knows what one is dealing with. It could close the gap because allows in a comfortable way to manage dynamic data in udts. It's not a replacement nor workaround but some fully functional way of it's own that will allow the user to handle dynamic data in a fast and understandable way. Heap can extend udts and also contain udts - so it's not an attempt to "play with structures under the covers" but an attempt to "uncover the structures" :)

This is just the base. Others having understood don't need to create all this stuff themselves- it'll need a few hours - no, they can instantly start from this point.
Of course I'd like to see most of these functions implemented since I have the idea they would work even faster if they are compiled - and not "just" interpreted during run.
I hope, that one or another tB-user - maybe the unknown one that always downloads my uploads a few seconds after i posted them - can see the point.

Memory-management can be easy without variables, just needs a few little functions that make the pie tasty.
If nobody jumps into the lake - nobody can tell if the water is too cold :D

ReneMiner
01-08-2013, 22:35
Then Eros will for sure have them implemented in any case before I get them in O2 together. Of course - never anyone learned a language in a few weeks. As I wrote- I'm just coding for fun: if no fun? I not do...

to keep this serious- I added another function:

Heap_ElementFreePtrAt

It's especially to work with elements that are pointers to some sub-heap. It will remove the specified element (pointer) and also free the heap where that element pointed to. It's like a combination of Heap_FreeAt and Heap_ElementRemoveAt but needs less parameters to pass since pointer-sizes are fix and less calls anyway.
Example


Uses "console"
#INCLUDE "lazyFun.tBasicU"

' - example Heap_ElementFreePtrAt

' 4 bytes to store a pointer...
DWord foo = HEAP_AllocByStr( MKDWD$(HEAP_AllocByStr( "I am one !" )) _
+ MKDWD$(HEAP_AllocByStr( "I am two !!" )) _
+ MKDWD$(HEAP_AllocByStr( "I am three !!!" )) _
+ MKDWD$(HEAP_AllocByStr( "I am four !!!!" )) _
+ MKDWD$(HEAP_AllocByStr( "I am five !!!!!" )) )

' filled in 5 pointers now and created altogether 6 heaps!

PrintL "'Ubound foo':" + Str$( HEAP_Size(foo)/SizeOf(DWord) )+ $CRLF

Long i

For i = 1 To HEAP_Size(foo)/SizeOf(DWord)
PrintL Heap_Get$( PeekPtrAt Heap_ElementGetPtr foo, i, SizeOf(DWord) )
Next
PrintL $CRLF + Repeat$(50, "-") + $CRLF
PrintL "key to continue" + $CRLF
WaitKey

PrintL "now lets kill three:" + $CRLF

Heap_ElementFreePtrAt VarPtr foo, 3
' this will delete the heap that's pointer is stored as element 3 in heap foo
' additional it will also delete the pointer-space, foo now has one element less

PrintL "'Ubound foo':" + Str$( HEAP_Size(foo)/SizeOf(DWord) )+ $CRLF

For i = 1 To HEAP_Size(foo)/SizeOf(DWord)
PrintL Heap_Get$( PeekPtrAt Heap_ElementGetPtr foo,i, SizeOf(DWord) )
Next

PrintL $CRLF + Repeat$(50, "-") + $CRLF
PrintL "key to end" + $CRLF
WaitKey

ReneMiner
02-08-2013, 10:52
Setup dynamic 2-dimensional heap using elements:

It's possible to "redim" any dimension this way. But it's not even sized into all dimensions- the first dimension holds pointers to the second dimension...the last "dimension" will hold the data.

No additional functions needed to this.

Example:


Uses "console"
#INCLUDE "lazyFun.tBasicU"

' - example 2 flexible Dimensions, fixed-size-type elements -

Type t_type
A As Long
B As Byte
C As Double
End Type


Long i, j
Dim dummy As t_Type
DWord myPtr

Randomize ' very flexible...

Long Dimension1 = Rnd(2,4)
Long Dimension2

' any 4 bytes
DWord foo = HEAP_Alloc(Dimension1 * SizeOf(DWord))

For i = 1 To Dimension1
' go through first dimension
PrintL "dimension 1:" + Str$(i)

' ask for the position where to find/store pointer foo(i,..)
myPtr = Heap_ElementGetPtr( foo, i, SizeOf(DWord) )
Dimension2 = Rnd(1,4)

For j = 1 To Dimension2
PrintL "...element" + Str$(j)
' fill in data at second dimension
dummy.A = i * 100000 + j * 100
dummy.B = i * 10 + j
dummy.C = i * 11 + j * 0.11
' append the data to heap that's pointer is stored in position myPtr
Heap_AppendAt myPtr, Memory_Get(VarPtr(dummy), SizeOf(t_Type))
Next
PrintL
Next

PrintL $CRLF + Repeat$(50, "-") + $CRLF
PrintL "key to continue" + $CRLF
WaitKey

Dim vDummy As t_Type At 0 ' prepare some "virtual peekhole"

For i = 1 To HEAP_Size(foo)/SizeOf(DWord)
' go through first dimension
PrintL "first dimension, element " + Str$(i)

' now don't need to pass the position where to find the pointer
' just need the actual pointer to the heap containing the elements of this dimension
myPtr = PeekPtrAt Heap_ElementGetPtr( foo, i, SizeOf(DWord) )
' at this position you could just use a virtual array as t_Type at myPtr

' but show how to get the single elements here:

For j = 1 To HEAP_Size(myPtr)/SizeOf(t_Type)
PrintL "second dimension, element" + Str$(j)
' get element-data in second "dimension"
SetAt(vDummy, Heap_ElementGetPtr myPtr, j, SizeOf(t_Type) )
PrintL vDummy.A
PrintL vDummy.B
PrintL vDummy.C
Next
PrintL
Next

' you can insert, remove or append new elements in both dimensions!
' it's even possible to have dimensions with no elements...

PrintL $CRLF + Repeat$(50, "-") + $CRLF
PrintL "key to end" + $CRLF
WaitKey

ReneMiner
05-08-2013, 09:48
few little changes - but nothing in syntax nor additional functions.

mainly added/fixed comments, also re-checked existing functions to return expected and useable results
minor changes to a few functions, for example Heap_ResizeAt accepts a size of 0 now - which does the same as Heap_FreeAt() or Heap_SetAt passing empty string as data then - which makes Heap_FreeAt probably obsolete.

Great would be now some method as mentioned in another thread (http://www.thinbasic.com/community/showthread.php?t=12037&page=4&p=89228&viewfull=1#post89228) that would do a virtual overlay onto heap in one step alike


Dim vArray(Heap_Size(myHeap)\SizeOf(myType)) As myType At myHeap
'shortened to
Dim vArray(Fill) As myType At Heap(myHeap)

but I already suggested this (http://www.thinbasic.com/community/project.php?issueid=413) some time ago...

ReneMiner
06-08-2013, 17:53
Small change to Heap_Instr. The function accepts now some optional start-parameter so it can be called repeatedly. Still no real use for this :D
But already an example:


Uses "console"
#INCLUDE "lazyFun.tBasicU"

DWord foo = HEAP_AllocByStr("is it? This is a test ! it is")
Long lPos

PrintL Heap_Get$ foo
PrintL "123456789|123456789|123456789" + $CRLF

PrintL "search for 'is'" + $CRLF

Repeat
lPos = Heap_Instr(foo, "is", lPos + 1)
If lPos Then PrintL "found at " + lPos
Until lPos = 0

PrintL $CRLF + "key to end" + $CRLF
WaitKey

Petr Schreiber
07-08-2013, 07:08
Thanks Rene,

very nice fine tuning :)


Petr

ReneMiner
07-08-2013, 09:53
Still on it :)

This time there are no additional functions but the opposite case: I threw a few out since they were not really needed.

There's no more

Heap_FreeAt:
the same can be achieved a few different ways already
Heap_SetAt position_of_myPtr, ""
Heap_ResizeAt position_of_myPtr, 0
Heap_ElementRemoveAt position_of_myPtr, 1, Heap_Size(value_of_myPtr) ' not made for that purpose, but does it too


Heap_ElementScanIndex/Heap_ElementScanPtr:
both are a little too "special" and I created them before Heap_ElementIDAt - which serves when it comes to indexing unique values as vertices, colors etc.



Functions-Overview
(http://www.thinbasic.com/community/showthread.php?t=12174&page=2&p=89400#post89400)
MinVersion 1.9.7.0 - get it here (http://www.thinbasic.com/community/showthread.php?t=12141)
FileVersion 0.35, 07.08.2013

ReneMiner
09-08-2013, 08:25
Does anyone know where Heap_Size is stored?

And - probably some changes to await, I guess the variables-"byName" functions could all get prefixed Variable_ - thinking - I'm just not in the mood to update all examples today. See my last blog.

ReneMiner
10-08-2013, 12:35
Today I got some bigger example. It contains 3 simple functions to manage HEAP-Nodes and allows to build tree-alike structures. It's just a test, means these functions are not part of LazyFun.tBasicU yet but they show what probably to await in near future. MinVersion 1.9.7.0, use attachement 2 posts above.


Uses "console"
#INCLUDE "lazyFun.tBasicU"

'------------------------------------
' "root" (1 heap)
' Dword node(...) - contains node-Ptrs in element-order 1,2,3...
' ordinary ptr-array = use Heap_Element...-functionality on it
'------------------------------------
' "node" (2 heaps)
' Dword DataPtr - ptr to second heap containing data
' Dword Flags
%Flag_Expanded = &H00000001 As DWord
%Flag_Hidden = &H00000002 As DWord
'Flags could be some more f.e. %Flag_Disabled etc.

' Dword Parent - contains element-index
'[ Dword Child(...) ] - appended element-indexes if some
'------------------------------------

DWord myTree ' holds pointer to root-heap

DWord myComputer, myCDrive ' hold index of nodes


' create a few nodes
' pass position where to store/find pointer, data, parent(if one) and flags if desired
' and retrieve the Index of this node
myComputer = Heap_NodeAppendAt VarPtr myTree, "my computer",,%Flag_Expanded
' myComputer now holds the Element-Index where the pointer to this node can be stored/found in Heap(myTree)
' since it was the very first node it becomes the top-level-parent of all that's noded to myTree later
' the first node always gets Index 1, so never needed to store this - except to make this example readable

myCDrive = Heap_NodeAppendAt VarPtr myTree, "c:", myComputer

Heap_NodeAppendAt VarPtr myTree, "d:", myComputer

Heap_NodeAppendAt VarPtr myTree, "program files", myCDrive
Heap_NodeAppendAt VarPtr myTree, "thinBasic" , myCDrive
Heap_NodeAppendAt VarPtr myTree, "hidden folder", myCDrive, %Flag_Hidden
Heap_NodeAppendAt VarPtr myTree, "windows xp" , myCDrive

' now retrieve a string of the indexes of all visible
' nodes below myComputer(including) in order
String sIndexes = Heap_NodeList$(myTree, myComputer)
Long i

' virtual overlay of Dwords there:
Dim dIndex(StrLen(sIndexes)/4) As DWord At StrPtr(sIndexes)

DWord ppNode, pNode, pData

' now print all:
For i = 1 To UBound(dIndex)
' small steps:
ppNode = HEAP_ElementGetPtr myTree, dIndex(i), 4 ' ask for the place of pointer-storage-position
' for "node(dIndex(i)) in tree 'myTree'"
' 4 means SizeOf(Dword) = the size of one element/ a pointer in myTree

pNode = PeekPtrAt ppNode ' get the actual pointer at this "pointer-storage-position"

pData = PeekPtrAt pNode ' get the pointer to data-heap at first position of the "node-heap"

' inset according to depth of the node
PrintL Repeat$(Heap_NodeGetDepth(myTree, dIndex(i)), " ") + HEAP_Get$(pData)

Next

PrintL $CRLF + Repeat$(50,"-") + $CRLF
PrintL "key to continue" + $CRLF
WaitKey

PrintL "now expand 'my c-drive'" + $CRLF
' get the pointer to the noded heap:
pNode = PeekPtrAt HEAP_ElementGetPtr myTree, myCDrive, 4
' the second dword is Flags there:
Poke(DWord, pNode + 4, %Flag_Expanded)

' retrieve string of visible indexes in order
sIndexes = Heap_NodeList$(myTree, myComputer)

' virtual overlay of Dwords there:
ReDim dIndex(StrLen(sIndexes)/4) At StrPtr(sIndexes)

' now print all:
For i = 1 To UBound(dIndex)
Print Repeat$(Heap_NodeGetDepth(myTree, dIndex(i)), " ")
PrintL HEAP_Get$ PeekPtrAt PeekPtrAt HEAP_ElementGetPtr myTree, dIndex(i), 4

Next

PrintL $CRLF + Repeat$(50,"-") + $CRLF
PrintL "key to continue" + $CRLF
WaitKey

PrintL "now change data at some node in line 5 displayed"

pNode = PeekPtrAt HEAP_ElementGetPtr myTree, dIndex(5), 4
HEAP_SetAt pNode, "windows 8"

PrintL "or at some Index we know:"
pNode = PeekPtrAt HEAP_ElementGetPtr myTree, myCDrive, 4
HEAP_SetAt pNode, "volume C"

' now print again - order has not changed:
For i = 1 To UBound(dIndex)
Print i + Repeat$(Heap_NodeGetDepth(myTree, dIndex(i)), " ")
PrintL HEAP_Get$ PeekPtrAt PeekPtrAt HEAP_ElementGetPtr myTree, dIndex(i), 4

Next


PrintL $CRLF + Repeat$(50,"-") + $CRLF
PrintL "key to end" + $CRLF

WaitKey

' -----------------------------------------------------------------
Function HEAP_NodeAppendAt( ByVal rootPos As DWord, _
ByVal sData As String, _
Optional Parent As DWord, _
Flags As DWord _
) As DWord
' rootPos awaits a position where the pointer to the root to be found/stored
' sData the data to set at this node
' only the first node of a tree can be without parent
' use flags as %Flag_Expanded, %Flag_Hidden or create own, additional flags

If rootPos < 1 Then Return 0 ' invalid pointer-position

Local pData, pNode, ppParent, Index As DWord

If StrLen(sData) Then

pData = HEAP_AllocByStr(sData)

If pData = 0 Then Return 0
' probably out of memory...
EndIf

' new nodes Index would be:
Index = HEAP_Size(PeekPtrAt rootpos)/4 + 1

' the node consists of DataPtr + Flags + ParentIndex [ + ChildIndex(...) ]

If Index = 1 Then
' this is the first node then
HEAP_SetAt rootpos, MKDWD$( HEAP_AllocByStr( MKDWD$(pData, Flags, 0) ) )
Return 1
EndIf

If Parent < 1 Or Parent >= Index Then
' impossible- that index does not exist
If HEAP_Size(pData) Then HEAP_Free(pData)
Return 0
EndIf

' find out pointer-position of the parent that's Index we have here
ppParent = HEAP_ElementGetPtr( PeekPtrAt rootpos, Parent, 4 )

' append the new childs Index at the parent
If Not HEAP_AppendAt ppParent, MKDWD$(Index) Then
' something went wrong - release garbage:
If HEAP_Size(pData) Then HEAP_Free(pData)
Return 0
EndIf

' create the new node since we got all needed data now
pNode = HEAP_AllocByStr( MKDWD$(pData, Flags, Parent) )

If HEAP_Size(pNode) < 12 Then
' something went wrong - release garbage:
If HEAP_Size(pData) Then HEAP_Free(pData)
If HEAP_Size(pNode) Then HEAP_Free(pNode)
Return 0
EndIf

' append the new nodes pointer as new index-element finally
If Not HEAP_AppendAt rootPos, MKDWD$(pNode) Then
' probably out of memory or amount of nodes*4 exceeds max heap-size...
If HEAP_Size(pData) Then HEAP_Free(pData)
If HEAP_Size(pNode) Then HEAP_Free(pNode)
Return 0
EndIf

Function = Index

End Function
' -----------------------------------------------------------------
Function HEAP_NodeGetDepth(ByVal pRoot As DWord, _
ByVal Index As DWord _
) As DWord

' retrieve depth of a node passing it's root-pointer and index
' will return 1 for the first -(top-level-parent)- node, 2 for a child of first, 3 for grandchild etc.

If Index > HEAP_Size(pRoot)/4 Then Return 0

Local dResult, pNode As DWord

While Index > 0
dResult += 1
pNode = PeekPtrAt HEAP_ElementGetPtr( pRoot, Index, 4 )
If HEAP_Size(pNode) < 12 Then Exit While
Index = Peek(DWord, pNode + 8)
Wend

Function = dResult

End Function

' -----------------------------------------------------------------

Function HEAP_NodeList$(ByVal pRoot As DWord, _
ByVal Index As DWord _
) As String

Local i As Long
Local pNode As DWord
Local sResult As String


' recursive build a string together

' so this will build a list of indexes of visible/expanded nodes
' and return them in a string finally

' pRoot awaits the pointer to root-heap
' as Index pass the Index of the node to start with


pNode = PeekPtrAt HEAP_ElementGetPtr( pRoot, Index, 4 )

If Peek(DWord, pNode + 4) And %Flag_Hidden Then Return ""

sResult = MKDWD$(Index)

If HEAP_Size(pNode) > 12 Then
' this one has children
If Peek(DWord, pNode + 4) And %Flag_Expanded Then
For i = 3 To HEAP_Size(pNode)/4 - 1
sResult += HEAP_NodeList$(pRoot, Peek(DWord, pNode + i * 4 ))
Next
EndIf

EndIf

Function = sResult
' on exit this returns a string with all visible below Index (incl.Index!)

End Function


And once again the question that busies me: at which position can I find Heap_Size?

ReneMiner
10-08-2013, 19:20
for a string you find strings length just 4 bytes in front of the string. sadly not at heap...but maybe somewhere else or just in another format (ascii?)
and b.t.w. you told me in the oxygen-thread that heap would not be exclusively belong to tB - now what shall I believe?

Petr Schreiber
10-08-2013, 20:51
Hi Rene,

Heap in ThinBASIC is not implemented via PB commands, it is done via Win32 - HeapAlloc, HeapFree, HeapRealloc, HeapSize... sounds similar, doesn't it :)
There is a Win32 function which could be useful for your hacking, it is called HeapWalk (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366710%28v=vs.85%29.aspx). It is placed in Kernel32.dll, the second parameter it has is a bit hardcore :D, but if you manage to translate the PROCESS_HEAP_ENTRY to TB, you should be able to reach information you need.

On the other (dark :)) side. You need to call HeapWalk to get the pointer to data structure somewhere. You will most probably end up at same speed calling just Heap_Size directly...


Petr

ReneMiner
10-08-2013, 20:56
It's not a speed issue in that matter: I think about let oxygen make the calculating - but I need the heap-size urgently to get into oxygen somehow without passing it in each call which would be kind'a stupid because the condition Heap_Size(x) > 0 has to be given - so I could do the whole formula in tb if I had to ask it in advance then. And also would slow down the operation because the function always would have an additional byval-parameter - the other way would be if oxgen would have some own heap- i could let it return the needed stuff if as pointers or data there were some o2-heap - not limited to 512 elements as memory.
John, no quote but a link (http://www.thinbasic.com/community/showthread.php?t=12173&page=5&p=89489#top) - did I understand wrong?

ReneMiner
12-08-2013, 09:48
New functions - new version. More Examples may follow later - I leave old version attached at previous page to run the older examples. I changed parameters order for Heap_NodeAppendAt, changed vartypes used for Indexes from long to dword - since all happens above 0... and also added a few more functions. So this is the arsenal at the time:


functions to variables passed "byName"
VARIABLE_Get$ get string-data from any variable passed "byName"
VARIABLE_GetDataPtr get pointer to data of a certain element of any variable
VARIABLE_GetPtr get pointer to any variable
VARIABLE_SetStr set string-data to any variable
VARIABLE_SetUdtStr set string-data to dynamic string in udts

VARIABLE_GetInfoEx Lib "thinCore.DLL" Alias "thinBasic_VariableGetInfoEX"

restrictions:
=============
for multidimensional arrays
just the first elements pointer can be returned
only first or all elements capture is possible


functions to manage Heap-memory
common:
HEAP_AppendAt append some data to heap and store pointer at specified position
HEAP_Copy create copy of existing heap and return new pointer
HEAP_Fill fills/overwrites heap with some string-data
HEAP_Get$ get entire heap in up to 5 dimensions
HEAP_InsertAt insert data at absolute position
HEAP_Instr retrieve position of a string to find
HEAP_Left$ get left part/get string of desired length with heap content left
HEAP_Mid$ get mid part/get string of desired length and heap within
HEAP_ResizeAt resizes heap, preserving data, resize to 0 will free data
HEAP_Right$ get right part/string of desired lenght with heap-content right
HEAP_SetAt set data to heap and get/store pointer at the specified position

elements stored in "1-dimensional, fixed size heap-array":
HEAP_ElementGet$ returns data of one element
HEAP_ElementGetIndex returns index of data or 0 if not found
HEAP_ElementGetPtr returns pointer to element
HEAP_ElementIDAt returns index of data, creates it if not exists
HEAP_ElementInsertAt insert data as new element
HEAP_ElementRemoveAt will remove one element
HEAP_ElementSet set data of existing element to new content

stored in a tree-structure as nodes
HEAP_NodeAppendAt creates a new node
HEAP_NodeCountChildren returns count of children at this node
HEAP_NodeGetDepth will return "distance" of node from root
HEAP_NodeList$ lists indexes of all visible & expanded nodes
HEAP_NodeSetFlag manipulate a nodes "Flags-property"

deprecated:
HEAP_NodeGet$ retrieve data noded at node - HEAP_Get$(pRoot, Index, 1) to read out data here
HEAP_ElementPeekPtr peek a pointer that is stored as element : replaced/improved by HEAP_GetPtr
HEAP_NodeGetChildPtr retrieve pointer to the first childs index of Node(Index): use Heap_GetPtr(pRoot, Index) + 12
HEAP_NodeGetParentIndex returns index of a nodes parent-node : abuse HEAP_GetPtr(pRoot, Index, 3)
HEAP_NodeGetParentPtr returns pointer to a nodes parent-node: abuse HEAP_GetPtr(pRoot, HEAP_GetPtr(pRoot, Index, 3))
HEAP_NodeGetDataPtr retrieve pointer to noded data-heap : use HEAP_GetPtr(pRoot, Index, 1)
HEAP_ElementFreePtrAt removes a pointer-element and free sub-heap: use HEAP_FreeAt + HEAP_ElementRemoveAt
HEAP_NodeFreeTreeAt free all data noded at the specified root- just use HEAP_FreeAt(pRoot)

NEW:
HEAP_DimAt setup dynamic heap up to 5 base-dimensions
HEAP_FreeAt free all dimensioned and normal heap and update pointer-position
HEAP_GetPos get position in 5 dimensions where to store/find pointer
HEAP_GetPtr get pointer in 5 dimensions -replaces HEAP_ElementPeekPtr


organized in multidimensional storage:
HEAP_OrganizeAddress will return an address where to find/store data
HEAP_OrganizeAt will create organized heap with at least 2 dimensions
HEAP_OrganizerFreeAt will free heap + organized Sub-heap
HEAP_OrganizerGetDim$ returns information about organized heap dimensions

functions to dynamic strings

Dictionary_Len returns size of dictionary-buckets
StrAtPtr$ returns string found at passed position
StrLen limited usage since not works on udt-substrings, shortens StrPtrLen(StrPtr())

pointer-functions

PeekPtrAt safe way to Peek pointers without risk to Peek At 0


Functions theirs names end with "At" await an address where to find a valid pointer and/or to store the new pointer at
Functions theirs names end with "$" return strings
find it HERE (http://www.thinbasic.com/community/showthread.php?t=12174&page=8&p=89533#post89533)

ReneMiner
12-08-2013, 13:55
Noding heap -

EDIT: Example removed because of some changes: find a Nodes-example on the next page.

The image below is to illustrate how those nodes work.
The root-heap is some row of pointers-elements. At position 1 is stored the pointer to "node 1", at position 2 will the pointer to "node 2" be stored etc.

The node heap consists of at least 3 Dwords. At the first position the pointer to the data can be stored.
The second dword is to hold some flags, f.e. is that node expanded etc.
The third dword will hold the position (Index) where to find the parents-pointer in root-heap. The first node does not have a parent...
All following dwords (if some) will hold the Indexes of noded children.

So green numerals in root show the Index - which holds a pointer.
All what's named "...Index" holds an Index = the (element-)position where to find pointer to parent or children in root-heap.

Petr Schreiber
12-08-2013, 18:15
Hi Rene,

looking at the code, what is faster in you experience:


Peek(Dword, ... )


or



DWord something At 0
SetAt(something, ...)



Petr

ReneMiner
13-08-2013, 08:17
There are a couple of reasons:

1. I just want to have be the best basic available in this corner of the milky way on my drive...

2. Look here! Its possible that easy - even someone like me can do it!

3. Nananananana :onthequiet:

Back to serious: I made some test to compare speed of virtual read-out and Peek-methods. Be surprised about the result!


Uses "Console"

%MAX_Tests = 100000

DWord testfield = HEAP_AllocByStr(Repeat$(%MAX_Tests, MKDWD$(1234)))
DWord dRead
DWord X At 0

Quad tStart,tEnd
Double tTime 'for obtain elapsed time
Long i


' -- Initialize high precision timer
HiResTimer_Init


'---------------------------------------------------------------------
PrintL "Peek-speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start"
WaitKey
tStart = HiResTimer_Get
For i = 0 To %Max_Tests - 1
dRead = TestPeek( testField + i * 4 )
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF

'---------------------------------------------------------------------
PrintL "Press a Key to start virtual method"
WaitKey
tStart = HiResTimer_Get
For i = 0 To %Max_Tests - 1
dRead = TestVirtual( testField + i * 4 )
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
PrintL "Press a Key to exit"
WaitKey

'---------------------------------------------------------------------
Function TestPeek(ByVal pos As DWord) As DWord

Return Peek(DWord, pos)

End Function

'---------------------------------------------------------------------
Function TestVirtual(ByVal pos As DWord) As DWord
' Dword x At pos = MUCHO SLOWLY

SetAt( x, Pos )
Return x

End Function




Now - who would have thought how clear without ambiguity that result would be...
Yesterday I feared I had to rewrite lots of code. Today I know...
If use the result just once - stick to peek. Else use the other way so not needed to store result locally. If x wouldn't have been defined at 0 in advance it would need almost double the time.

ReneMiner
13-08-2013, 11:30
I made a few changes again. Mostly I changed some ...At-functions internally to work using a virtual overlay instead of local variables if possible.
Another change to function HEAP_ElementPeekPtr which now accepts an optional second index so it's possible to peek out a pointer in the "second dimension" in one call.

more new possibilites through this to Noded-heap:

HEAP_ElementPeekPtr( pRoot, Index, 1) equals HEAP_NodeGetDataPtr(pRoot, Index) -but keep this- it's one parameter less and a faster, often used function
HEAP_ElementPeekPtr( pRoot, Index, 2) would substitute not existing HEAP_NodeGetFlags(pRoot, Index)
HEAP_ElementPeekPtr( pRoot, Index, 3) equals HEAP_NodeGetParentIndex(pRoot, Index) - obsolete now, low amount of usages
HEAP_ElementPeekPtr( pRoot, Index, 4) returns Index of first child if one, else 0
while
HEAP_ElementPeekPtr( pRoot, Index) + 12 returns pointer to where index of first child is stored
HEAP_ElementPeekPtr( pRoot, Index, >4) returns Index of another child if one, else 0...

This lead to functions
HEAP_NodeGetParentIndex ( returns index of a nodes parent-node )
can be replaced by "abuse of" HEAP_ElementPeekPtr(pRoot, Index, 3) since these Indexes are stored as Dword-Elements too
and
HEAP_NodeGetParentPtr ( returns pointer to a nodes parent-node )
can be replaced by "abusing" HEAP_ElementPeekPtr(pRoot, HEAP_ElementPeekPtr(pRoot, Index, 3))
being obsolete.

Alias HEAP_ElementPeekPtr As HEAP_ElementPeekDwd...deprecated already !!!


attached: example-script in new syntax (changed keywords) that covers variable-functions

ReneMiner
14-08-2013, 08:30
You are right in all points - except the speed- I have not tested yet but I fear it's still slower than the built-in variables because it's not compiled. Also a - smaller - problem is that local function-variables-names in the unit-file are within the same global scope as the running main-script. If by coincidence a user chooses a globals name that matches some functions variables name it can lead to unforseen results. That's also a reason to compile it besides the speed-issue.

I mostly did heap-stuff because I need something like



Type t_vertexList
Vertex() as t_Vec3d ' dynamic amount of elements needed here
Normal() as t_Vec3d ' also here
UV() as t_Texcoord2d ' and here
VColor() as t_RGB ' here too
End Type


and I need to attach those lists of "limbs" to some "body" - where not all bodies have the same amount of sublists. And each limb needs to be noded to some controller-block to determine it's size, rotation, vertex-order etc. So therefor I need the nodes. The rest came by the idea to cover all commonly needed aspects of managing data storage as comfy as even possible without becoming too complicated on the user-side.
Currently tB has 5 functions to "manage" heap. As you can imagine - it does store/release your data - but anything else each and every user has to think about and to find out himself how to make this dynamic or multidimensional or to node it somehow together if this user not just wants to store a rectangular grid or a row of even sized elements. It becomes "confusing" already if that grid is just supposed to store pointers to more allocated heap - one had to create a few functions to access or store data there.

Having this managed in advance leads tB-users to be faster in developing their stuff. Those who read examples and function-descriptions might understand pretty fast how "easy" it works and can either instantly use it or are able to develop their own memory-management-stuff (even in another language) by copying needed functionalities or just by getting inspired.
So it's in all cases a base to start from.

The variables-functions came by the idea to create some GUI in TBGL. Since that is not managed like windows-UI-controls and they have to be drawn each frame by TBGL I had either to create a new GUI-system for each use - or I do it once to be multiple useable and assign the values to draw/print by variables-names instead of pointers, so even if the user changes some string-content or redim's any variable and the pointer changes - the GUI-control is always up-to-date without calling any refresh nor having to update it "manually". The only thing that still disturbs me is have to pass the sizeOf(type) in almost every call because I've not found a method yet to read it out somewhere. thinBasic_ArrayGetInfo will return total size of an array - but the problem here is: if there's a dynamic string involved the size of one element can not be calculated correctly through dividing totalsize by elementcount...

Also - back to heap again- I wanted to have a "maintype GUI_Control"-array which can have totally different sized subtypes - without to unite these which is an enormous waste of space if all controls would allocate the space that's needed for the largest one.

The other string & pointer-functions came to shorten often needed calls and formulas that are related to both so code becomes better readable and other functions results can be used instantly without need to recheck if they are valid.

TBGL-3d-Editor is not the final goal but just a tool I need to get there...

ReneMiner
15-08-2013, 06:05
I'll leave it like that for a while and play a few games in the meantime. Maybe it comes alive - but if the brain is already dead then there's not much hope and I'll have to defile another tomb

ReneMiner
15-08-2013, 17:10
New version again- guess what 4 new functions that allow to manage dynamic heap up to 5 base-dimensions. You might setup one dimension less if you use fixed-size elements so you can place a virtual layover onto a whole row

new:

HEAP_DimAt setup dynamic heap up to 5 base-dimensions
HEAP_FreeAt free all dimensioned and normal heap and update pointer-position
HEAP_GetPos get position in 5 dimensions where to store/find pointer
HEAP_GetPtr get pointer in 5 dimensions - may replace HEAP_ElementPeekPtr

- have to re-think the organizer-stuff now... organizer needs less memory but is not as dynamic as this way. And this could also be improved to allow more than 5 dimensions...

simple example:


Uses "console"
#INCLUDE "lazyFun.tBasicU"


DWord foo
' create 4*5 pointer-spaces
If Heap_DimAt(VarPtr foo, 4, 5) Then
' ask for position of pointer in second dimension
HEAP_SetAt HEAP_GetPos( foo, 2, 3), "Hello, I am 2,3"
HEAP_SetAt HEAP_GetPos( foo, 4, 5), "Hello, I am 4,5"
' ask for pointer stored in second dimension
PrintL HEAP_Get$ HEAP_GetPtr(foo, 2,3)
PrintL HEAP_Get$ HEAP_GetPtr(foo, 4,5)

' free all and update the pointer contained in foo:
Heap_FreeAt VarPtr foo
EndIf

PrintL
' 3 dimensions
If Heap_DimAt(VarPtr foo, 4, 5, 6) Then

HEAP_SetAt HEAP_GetPos( foo, 2, 4, 5), "Hello, I am 2, 4, 5"

PrintL HEAP_Get$ HEAP_GetPtr(foo, 2, 4, 5)

' add more elements

HEAP_AppendAt HEAP_GetPos(foo, 3, 4), MKDWD$(HEAP_AllocByStr("I am new 3,4,7"))
HEAP_AppendAt HEAP_GetPos(foo, 3, 5), MKDWD$(HEAP_AllocByStr("I am new 3,5,7"))
HEAP_AppendAt HEAP_GetPos(foo, 3, 5), MKDWD$(HEAP_AllocByStr("I am new 3,5,8"))


PrintL HEAP_Get$ HEAP_GetPtr(foo, 3, 4, 7)
PrintL HEAP_Get$ HEAP_GetPtr(foo, 3, 5, 7)
PrintL HEAP_Get$ HEAP_GetPtr(foo, 3, 5, 8)

Heap_FreeAt VarPtr foo

EndIf

PrintL

DWord dummy

If Heap_DimAt(VarPtr foo, 3, 4, 5, 6) Then

' resize to foo(4,4,5,6) now:

If Heap_DimAt(VarPtr dummy, 4, 5, 6) Then

'append the pointer stored in dummy to heap(foo)
'- so first dimension has 4 elements now:
HEAP_AppendAt VarPtr foo, MKDWD$(dummy)

HEAP_SetAt Heap_GetPos(foo, 4, 4, 4, 4), "Hi, I am 4,4,4,4"

PrintL HEAP_Get$ HEAP_GetPtr(foo, 4, 4, 4, 4)
EndIf

Heap_FreeAt VarPtr foo
EndIf

PrintL $CRLF + Repeat$(50,"-") + $CRLF
PrintL "key to end" + $CRLF
WaitKey

ReneMiner
15-08-2013, 20:10
one post more or less...

still busy as a beaver

latest changes:

HEAP_Get$ accepts Indexes for up to 5 dimensions now also, which makes HEAP_NodeGet$ obsolete
HEAP_GetPtr replaces HEAP_ElementPeekPtr and HEAP_NodeGetDataPtr can be achieved Heap_GetPtr(pRoot, Index, 1)

the example above would now read like this:


Uses "console"
#INCLUDE "lazyFun.tBasicU"

DWord foo
' create 4*5 pointer-spaces
If Heap_DimAt(VarPtr foo, 4, 5) Then
' ask for position of pointer in second dimension
HEAP_SetAt HEAP_GetPos( foo, 2, 3), "Hello, I am 2,3"
HEAP_SetAt HEAP_GetPos( foo, 4, 5), "Hello, I am 4,5"

' now instantly retrieve data through HEAP_Get$:
PrintL HEAP_Get$( foo, 2,3 )
PrintL HEAP_Get$( foo, 4,5 )

Heap_FreeAt VarPtr foo
EndIf

WaitKey '...


PS. If 5 pointer-dimensions + 1 elements-dimension are not enough just tell it. I could raise this up to probably 31 pointer-dimensions- more parameters would just need another approach to pass them all ;)

ReneMiner
16-08-2013, 08:50
additional example attached.

I'm in doubt about Function HEAP_ElementFreePtrAt wich will free the heap thats pointer is stored in passed element-position and will delete also the pointer-space. Could lead to enormous leaks through wrong usage...but honestly that can happen with almost all functions if not used correctly. But this function is somewhat unique of a kind and behaviour - I'm not sure about keeping it - if this is really desired it can be done with slightly more effort by combination of HEAP_FreeAt + HEAP_ElementRemoveAt.

Edit: Function HEAP_DimAt has some local variable too much: newPtr is not needed - but I won't update the file because of this little "issue" right now

ReneMiner
18-08-2013, 09:36
cosmetics and some changes again.
Dropped functions HEAP_ElementFreePtrAt and HEAP_NodeFreeTreeAt.

I recognized functions as HEAP_Get$ which take optional parameters now, have to use parenthesis in order to work correctly.
So some of the examples have to be re-written. But no big deal...

Attached: a new version, updated doc and two examples. One shows usage of HEAP_Node...-stuff once more, using new functions as HEAP_GetPos/HEAP_GetPtr and HEAP_FreeAt on nodes - not a new one - but rewritten to work correctly.

For the 2D-Array-Example you'll need thinBasic Version 1.9.8. - else the data gets corrupted through the ReDim-behaviour at absolute variables in tB-Versions 1.9.7. and previous. Please be patient until the wizard has done his magic :wizard:

Edit: Doc updated because found some typos...

ReneMiner
19-08-2013, 11:18
Somewhat rare in tB-history: I used "UI" to create some documentation with a little more overview. Just run the attached file.

#MinVersion 1.9.5

Petr Schreiber
19-08-2013, 12:15
Good job Rene!,

very nice help system - structured, colored... I like it :)


Petr

ErosOlmi
19-08-2013, 12:23
Yes, very very nice !!!!

ReneMiner
19-08-2013, 13:34
Sorry- I had some bug inside - :oops: - forgot to exchange some old functions name (HEAP_ArrayFreeAt) inside Function HEAP_DimAt - I had it in there more than once so my spellchecker did not detect it and this only gets called if allocation fails due some lack of memory - so never happened yet...

#MinVersion 1.9.7.0 - Get it here (http://www.thinbasic.com/community/showthread.php?t=12141)
FileVersion 0.5 19-08-2013

ErosOlmi
19-08-2013, 13:44
René,

I'm stealing some of your HEAP_* great functions to add them as native thinCore functions.
Hope you will not ask me for royalties :drink:

Ciao
Eros

ReneMiner
19-08-2013, 14:23
René,

I'm stealing some of your HEAP_* great functions to add them as native thinCore functions.
Hope you will not ask me for royalties :drink:

Ciao
Eros

Are you kidding me? I feel highly honored :yahoo:
The "Ideas-forum" was a good idea.

PS. this Support-Thread (http://www.thinbasic.com/community/project.php?issueid=412) can be marked as "Done" then

ReneMiner
19-08-2013, 17:29
Eros, one question to this:

Is there a formula/ a FAST (!!!) way to retrieve the position where HEAP_Size is stored? Would be interesting to access heap from oxygen without have always to pass the size but just the pointer - If one had to search through a directory-alike list it would be certainly too slow.

ErosOlmi
19-08-2013, 19:20
Eros, one question to this:

Is there a formula/ a FAST (!!!) way to retrieve the position where HEAP_Size is stored? Would be interesting to access heap from oxygen without have always to pass the size but just the pointer - If one had to search through a directory-alike list it would be certainly too slow.

Reneé,

Heap memory is handled directly by the operating system using some KERNEL functions.
More info at: http://msdn.microsoft.com/en-us/library/windows/apps/aa366711(v=vs.85).aspx

The first thing to do before handling Heap memory blocks is to create a heap handle using HeapCreate or GetProcessHeap functions.
Once you have that handle, you can use HeapAlloc, HeapFree, HeapReAlloc, HeapSize functions.
thinBasic hide all the complexity (at the end it is not so complex) of those functions giving a more comfortable syntax.
I've never used other Heap functions.

But if you read Heap documentation you will see that there are some other functions that can be used to walk though Heap memory blocks: HeapValidate and HeapWalk. More info at:
http://msdn.microsoft.com/en-us/library/windows/apps/aa366708(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/apps/aa366798(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/apps/aa366710(v=vs.85).aspx

That is all I know.

Ciao
Eros

ReneMiner
19-08-2013, 19:27
I just read there, Heap_Size may contain bogous data? I always assumed if heap x does not exist HEAP_Size(x) would return 0... :|
I hope at least in tB it works that way...
Do HEAP_Alloc/HEAP_ReAlloc/HEAP_AllocByStr allocate continous data as I thought? Else the overlay stuff is kind'a screwed...

John, it's "Open-to-contribute" :)

FIX: to insert into function HEAP_DimAt - after


Dword hPtr At vPtr
' --------
' begin insert

If Heap_Size(hPtr) Then Return 0 ' memory already allocated!

' end insert
' -------
Local i As DWord

ReneMiner
20-08-2013, 09:00
I'm up since 6 in the morning already and playing with samples shipped with tB. I've found one that lists equates of all modules. Now I changed it a little making use of some Variables-functions. Now it lists not just equates names but also their values... Found a few that don't get bold.


'---Load all modules in order to get all equates

Uses "ADO" '<<< have not found this in help-file

Uses "BIFF", "BUNDLE"
Uses "CGI", "COM", "COMM", "Console", "Crypto"
Uses "Dictionary", "DT"
Uses "Eval", "EXE"
Uses "File", "FileLine", "FTP"
Uses "GDIp"
Uses "iComplex", "INet", "INI"
Uses "LAN", "LL"
Uses "MATH", "WinMM"
Uses "OnlineScores", "OS", "Oxygen"
uses "PC"
Uses "RAS", "Registry" ' have not found "RAS" in help neither
Uses "SAPI", "SMTP", "Stat"
Uses "TBAI", "TBASS", "TBDI", "TBEM", "TBGL", "TCPUDP", "TImage", "Tokenizer"', "Trace"?
Uses "UI", "UIAdv"
Uses "VBRegExp"
Uses "WMI"
Uses "XPRINT"
Uses "ZLib"

#INCLUDE "LazyFun.tBasicU" ' watch it: these equates also listed

Dim sKeys As String
Dim aKeys() As String
Dim nKeys, lVal As Long
Dim Count, i, char As Long
Dim sOut As String
Dim sLine As String
Dim sLastPrefix As String

'---Get a string with equates separated by $TAB
sKeys = APP_ListEquates

'---Parse string into an array
PARSE sKeys, aKeys, $TAB

'---Creates output buffer
nKeys = UBOUND(aKeys(1))
For Count = 1 To nKeys
sLine = aKeys(Count)

If StrLen(sLine) Then
If Peek(StrPtr(sLine)) = 37 Then ' % - prefixed
If char <> Peek(StrPtr(sLine)+1 ) Then
' new char
char = Peek(StrPtr(sLine)+1 )
sOut = sOut + "'[] " + Chr$(char) + $CRLF
EndIf

For i = 1 To StrLen(sLine) - 1
If Peek(i + StrPtr(sLine)) = 95 Then ' "_" (underscore)
If StrLen(sLastPrefix) < i Then
sLastPrefix = Memory_Get(StrPtr(sLine), i )
sOut = sOut + "' " + Repeat$(50,"-") + $CRLF
Else
If Memory_Differs(StrPtr(sLine), StrPtr(sLastPrefix), i ) Then
sLastPrefix = Memory_Get(StrPtr(sLine), i )
sOut = sOut + "' " + Repeat$(50,"-") + $CRLF
EndIf
EndIf
Exit For
EndIf
Next

If i >= StrLen(sLine) Then
If StrLen(sLastPrefix) Then
sOut = sOut + "' " + Repeat$(50,"-") + $CRLF
sLastPrefix = ""
EndIf
EndIf

lVal = Peek(Long, VARIABLE_GetPtr(sLine) )
sLine = sLine + Repeat$(50 - StrLen(sLine), " ") + " = &H" + Hex$(lVal, 8)
EndIf
EndIf

PrintL sLine
sOut = sOut & sLine & $CRLF
NEXT

'---Save buffer into .INC file
FILE_Save(APP_SourcePath & "EquatesList.inc", sOut)

PrintL $CRLF + "Done. Any key to end."
WaitKey

After running succesful you'll find some .inc-file in program folder.