I could have opened another thread for the following but it's an extension of the previous and all grows on the results of this thread, especially on the new Like-keyword.
Who has read it knows that I already made Items which allow to append elements or 1-dimensional arrays of elements to any quad-variable, so for example an array of some maintype can have attached different sized 1-dimensional subarrays or single elements of different subtypes without having to change anything about the maintype.
Long Read ' keep that forum-variable in mind!
Repeat
Now I created MD_Items = multidimensional items.
MD_Items need a size of 28 bytes in the first place but they have a few heaps attached to store the bounds (12 Bytes per dimension) and SizeOf(datatype)*ElementsTotal anyway.
They allow to append data of any type stored in up to a quarter million dimensions which is very naturalistic, true-to-life and often needed. No, just kidding- it leaves you the freedom to have any reasonable amount of dimensions without a limitation to care about...
A minimum of 2 dimensions is required, for 1-dimensional just stick to simple Items or set the low+high-bounds both to 1 for one of the two dimensions.
Each dimensions bounds can be in a range from -2,147,483,648 to 2,147,483,647 so means they allow to dim for example elements alike
#pseudo-syntax !!!
Dim foo(-123 to 25, 44 to 76, -99 to -13, 15)
' first dimension in a range from -123 to 25,
' second dimension in a range from 44 to 76
' third dimension in a range from -99 to -13
' fourth dimension in a range from 1 to 15
the code above is not the real syntax but just to demonstrate how one would have to understand it.
For dynamically passing indexes I simply Aliased the MKL$-functionality As MKIndex, so this allows to pass any amount of dimensions and their indexes in one parameter.
To create some multidimensional array of any type it needs to specify the type which will be enumerated by EnumType-Function, so one passes the result of EnumType together with the boundaries. There are two ways to specify bounds:
Either pass Ubounds of all dimensions only, so all dimensions indexes are 1-based as usual. That would mean to pass just one time MKIndex(...) after the EnumType().
Optional you may pass low-bounds and high-bounds so all dimensions indexes start at the passed low-bound and end at the passed high-bound.
The number of passed indexes has to match the number of dimensions always in this case, so even if lowbound of only one dimension starts with 1 you need to pass it then.
Now for the example above - this would be the syntax to use:
Dim foo as MD_Item
foo.Create( EnumType ("typename_here"), MKIndex( -123, 44, -99, 1), MKIndex( 25, 76, -13, 15) )
The first MKIndex() usually are the lowbounds and the second MKIndex() describes the upper bounds, but the create-function will take care of if you pass a higher number as first, so you can do it as you want, even mixed- as long as both have the same amount of dimensions.
To access some element of the multidimensional array you can retrieve a pointer to it using
dataPtr = <MD_Item-variable>.GetPtr( MKIndex(indexOfDimension1, indexOfDimension2 [,...]) )
or you can place some overlay like this
Local myElement Like foo.GetType At foo.GetPtr( MKIndex(1,2[,3[,...]]) )
'now can treat myElement as defined in Type
Usage-example:
#INCLUDE "Item.tBasicU"
Uses "console"
Global Function_CalledFrom As DWord ' this global will tell a type-function where to find data
' have some example-type t_Test:
Type t_test
I1 As Long ' we simply store dimensions indexes here
I2 As Long ' to recheck if all done correctly
I3 As Long
Identify As Function
SetTo As Function
End Type
Function t_Test.Identify()
If Function_CalledFrom Then
' not called from a variable of this type but from a pointer
' so Me is not dimensioned yet...
Local Me As t_Test At Function_CalledFrom
Function_CalledFrom = 0
EndIf
PrintL "My Index: (" & Me.I1 & ", " & Me.I2 & ", " & Me.I3 & ")"
End Function
Function t_Test.SetTo(ByVal I1 As Long, ByVal I2 As Long, ByVal I3 As Long)
If Function_CalledFrom Then
Local Me As t_Test At Function_CalledFrom
Function_CalledFrom = 0
EndIf
Me.I1 = I1
Me.I2 = I2
Me.I3 = I3
End Function
' ------------------------------------------------------
' now create some multi-dimensional Item
Dim foo As MD_Item
foo.Create( EnumType("t_Test"), _ ' of type t_test
MKIndex(-1,-2, -3), _ ' lowbounds (3 dimensions)
MKIndex( 1, 2, 3 ) _ ' highbounds (3 dimensions)
)
'should have "foo(-1 to 1, -2 to 2, -3 to 3)" now
' 3 * 5 * 7
' ======================
' 105 elements of t_Test
Dim e, i, j, k As Long
For i = 1 To foo.nDims ' .nDims tells us the number of dimensions
PrintL "Dimension " & i & ": " & foo.GetLowBound(i) & " To " & foo.GetHiBound(i)
Next
PrintL
PrintL "Have a total of " & foo.ElementsTotal & " elements of " & foo.GetType
PrintL $CRLF + Repeat$(42, "-")
PrintL $CRLF + "Press any key to continue" + $CRLF
WaitKey
For i = foo.GetLowBound(1) To foo.GetHiBound(1)
For j = foo.GetLowBound(2) To foo.GetHiBound(2)
For k = foo.GetLowBound(3) To foo.GetHiBound(3)
e += 1
PrintL "Element " & e & $TAB & i, j, k
' request pointer to element(i,j,k) and store to global:
Function_CalledFrom = Foo.GetPtr( MKIndex(i, j, k) )
' call type-function, stored global will be used in that function to place Me:
Call "t_Test.SetTo"(i, j, k)
Next
Next
Next
PrintL $CRLF & "do some checks now:" & $CRLF
' check element 0,0,0
PrintL "should print: My Index: (0, 0, 0)"
Function_CalledFrom = Foo.GetPtr( MKIndex(0, 0, 0) )
Call "t_Test.Identify"
' check element 1,1,1
PrintL "should print: My Index: (1, 1, 1)"
Function_CalledFrom = Foo.GetPtr( MKIndex(1, 1, 1) )
Call "" & foo.GetType & ".Identify"
' check element -1,-1,-1
PrintL "should print: My Index: (-1, -1, -1)"
Function_CalledFrom = Foo.GetPtr( MKIndex(-1, -1, -1) )
Call "t_Test.Identify"
' check element "not specified"
PrintL "this is the very first element:"
Function_CalledFrom = Foo.GetPtr()
Call "t_Test.Identify"
PrintL $CRLF + Repeat$(42, "-")
PrintL $CRLF + "Press the famous ANY-key to end"
WaitKey
There's no Redim-functionality for MD_Items but for non-preserve simply destroy and create new.
Also Redim Preserve can be achieved:
As first create temporary a new MD_Item in the desired new dimensions, then for-next-loop through all dimensions in boundaries that are common to both data-fields and place the data to preserve to the temp-element using
Memory_Set( <tempMD_Item>.GetPtr( MKIndex(i,ii[,...]) ), _
Memory_Get( <myMD_Item>.GetPtr( MKIndex(i,ii[,...]) ), SizeOf(typename_here) ) _
)
finally:
Memory_Swap( Varptr(<myMD_Item>), Varptr(<tempMD_Item>), SizeOf(MD_Item) )
' can destroy the temporary MD_Item which contains the "old information & data" now
<tempMD_Item>.Destroy()
and Redim Preserve is done...
incr Read
Until Read >= %Understand
The attached unit contains both, Items and MD_Items
#MinVersion 1.9.12.0
Bookmarks