ReneMiner
16-11-2014, 16:28
stack-variables could be very useful if they were built-in. of course one could use an array, but it has to be dynamic then, so for the meantime a stack on some udt-element would be difficult to realize, except one uses some dynamic string or heap memory.
This example uses dynamic String, the only thing that i don't like about it that one has to pass a VarPtr on Stack.PushData() - but i could not find any other dynamic solution without having to pass something like MKx$() nor Memory_Get to be able to Push any type of data onto a stack.
Uses "console"
Type Stack
sData As String
sType As String
lSize As Long
As_Type As Function
PushData As Function
PopData As Function
GetData As Function
End Type
' ---------------------------------------
Function Stack.As_Type(ByVal sType As String) As String
Me.sType = Ucase$(sType) ' save type-names uniform, might be faster to compare
Local data Like sType At 0 ' determine element-size
Me.lSize = SizeOf(data)
Function = Me.sType
End Function
' ---------------------------------------
Function Stack.PushData(ByVal pData As DWord) As Long
' "ByRef data" without any Type sadly not working here
If Me.lSize = 0 Then Exit Function
Me.sData += Memory_Get(pData, Me.lSize)
' returns number of elements stored on stack now
Function = StrPtrLen(StrPtr(Me.sData))/Me.lSize
End Function
' ---------------------------------------
Function Stack.PopData() As Long
' returns number of elements left on stack
If Not Me.lSize Then Return 0
If StrPtrLen(StrPtr(Me.sData)) < Me.lSize Then Return 0
If StrPtrLen(StrPtr(Me.sData)) = Me.lSize Then
Me.sData = ""
Else
Me.sData = LEFT$(Me.sData, StrPtrLen(StrPtr(Me.sData)) - Me.lSize )
EndIf
Function = StrPtrLen(StrPtr(Me.sData))/Me.lSize
End Function
' ---------------------------------------
Function Stack.GetData() As String
If Not Me.lSize Then Exit Function
If StrPtrLen(StrPtr(Me.sData)) < Me.lSize Then Exit Function
Local data Like Me.sType At StrPtr(Me.sData) + StrPtrLen(StrPtr(Me.sData)) - Me.lSize
Function = data
End Function
' ---------------------------------------------------------------------
Dim foo As Stack
Dim i Like foo.As_Type "Long"
For i = 1 To 50 Step 7
foo.PushData(VarPtr i) ' ... still not satisfied because have to pass pointer...
' neither can be an expression here
Next
Do
PrintL foo.GetData
Loop While foo.PopData
PrintL
Dim bac As Stack
Dim d Like bac.As_Type "Double"
For d = 0.25 To 2.0 Step 0.25
bac.PushData(VarPtr d) ' but at least it allows any type this way
Next
Do
PrintL bac.GetData
Loop While bac.PopData
WaitKey
in the end i would like to type in just as simple as this:
Stack foo As Long | Dim foo As Long Stack
Push foo 12345
PrintL foo
Pop foo
'...or like a module:
Dim bac As Long = Stack_Create [As |( ] Double | "Double" [)]
Stack_Push( bac, 123.45 )
Do
PrintL Stack_Get( bac )
Loop While Stack_Pop( bac )
bac = Stack_Destroy( bac ) ' <<< assigns 0
This example uses dynamic String, the only thing that i don't like about it that one has to pass a VarPtr on Stack.PushData() - but i could not find any other dynamic solution without having to pass something like MKx$() nor Memory_Get to be able to Push any type of data onto a stack.
Uses "console"
Type Stack
sData As String
sType As String
lSize As Long
As_Type As Function
PushData As Function
PopData As Function
GetData As Function
End Type
' ---------------------------------------
Function Stack.As_Type(ByVal sType As String) As String
Me.sType = Ucase$(sType) ' save type-names uniform, might be faster to compare
Local data Like sType At 0 ' determine element-size
Me.lSize = SizeOf(data)
Function = Me.sType
End Function
' ---------------------------------------
Function Stack.PushData(ByVal pData As DWord) As Long
' "ByRef data" without any Type sadly not working here
If Me.lSize = 0 Then Exit Function
Me.sData += Memory_Get(pData, Me.lSize)
' returns number of elements stored on stack now
Function = StrPtrLen(StrPtr(Me.sData))/Me.lSize
End Function
' ---------------------------------------
Function Stack.PopData() As Long
' returns number of elements left on stack
If Not Me.lSize Then Return 0
If StrPtrLen(StrPtr(Me.sData)) < Me.lSize Then Return 0
If StrPtrLen(StrPtr(Me.sData)) = Me.lSize Then
Me.sData = ""
Else
Me.sData = LEFT$(Me.sData, StrPtrLen(StrPtr(Me.sData)) - Me.lSize )
EndIf
Function = StrPtrLen(StrPtr(Me.sData))/Me.lSize
End Function
' ---------------------------------------
Function Stack.GetData() As String
If Not Me.lSize Then Exit Function
If StrPtrLen(StrPtr(Me.sData)) < Me.lSize Then Exit Function
Local data Like Me.sType At StrPtr(Me.sData) + StrPtrLen(StrPtr(Me.sData)) - Me.lSize
Function = data
End Function
' ---------------------------------------------------------------------
Dim foo As Stack
Dim i Like foo.As_Type "Long"
For i = 1 To 50 Step 7
foo.PushData(VarPtr i) ' ... still not satisfied because have to pass pointer...
' neither can be an expression here
Next
Do
PrintL foo.GetData
Loop While foo.PopData
PrintL
Dim bac As Stack
Dim d Like bac.As_Type "Double"
For d = 0.25 To 2.0 Step 0.25
bac.PushData(VarPtr d) ' but at least it allows any type this way
Next
Do
PrintL bac.GetData
Loop While bac.PopData
WaitKey
in the end i would like to type in just as simple as this:
Stack foo As Long | Dim foo As Long Stack
Push foo 12345
PrintL foo
Pop foo
'...or like a module:
Dim bac As Long = Stack_Create [As |( ] Double | "Double" [)]
Stack_Push( bac, 123.45 )
Do
PrintL Stack_Get( bac )
Loop While Stack_Pop( bac )
bac = Stack_Destroy( bac ) ' <<< assigns 0