- Only arrays of elements of simple datatype are supported (not objects), such as numeric data, fix-len zstring, UDTs that do not involve constructors / destructors, and pointers as member fields (for example, strings are forbidden).
- The destination array must be a dynamic array (var-len) with a number of dimensions not declared or equal to that of the source array (the source array can be a fix-len array or a var-len array), but the other case where the destination array is a fix-len array also works provided that this array has the same number of dimensions and all same Lbounds and Ubounds than those of the source array.
- When the data blocks of the two arrays occupy an equal size (in bytes) in memory, the copying procedure is optimal, because there is no reallocation of the destination array in memory, but only the update of its descriptor (see Note below) and the raw copy of the data block.
- For each type of data chosen (among the simple data types), a macro defines the corresponding overloaded copy procedure.
- Another short macro with an associated function provides the address of the array descriptor.
Note:
When the data blocks of the two arrays occupy an equal size (in bytes) in memory, the reallocation/resizing of the destination array is useless.
In addition to the copy of the data block from the source array to the one of the destination array, this just also needs to copy the contents of the source array descriptor into that of the destination array, except for:
- the second field of destination array descriptor (pointer to the first real element: '@array (lbound1, lbound2, ...)') which must not be modified,
- the first field of destination array descriptor (pointer to the real or virtual element: '@array(0, 0,...)') which must be recalculated (same offset with the second field of array descriptor as for the source array).
Code: Select all
'---------- Code for quick procedure ----------
#include "crt/string.bi"
Function arrayDescriptorPtrFunction (Byval p As Any Ptr) As Any Ptr
Return p
End function
#macro arrayDescriptorPtr(array, p)
Scope
Dim As Function (() As Typeof((array))) As Any Ptr f
f = Cast(Function (() As Typeof((array))) As Any Ptr, @arrayDescriptorPtrFunction)
p = f(array())
End Scope
#endmacro
#macro quickArrayCopyDefine(arrayType)
Sub quickArrayCopy Overload (dest() As arrayType, src() As arrayType)
Type dimension
Dim As Uinteger elementNumber
Dim As Integer lowBound
Dim As Integer upBound
End Type
Type descriptor
Dim As Any Ptr ptr0
Dim As Any Ptr ptrLbound
Dim As Uinteger globalSize
Dim As Uinteger elementSize
Dim As Uinteger dimensionNumber
Dim As dimension d(1 To 8)
End Type
Dim As descriptor Ptr pdescriptorDest
arrayDescriptorPtr(dest, pdescriptorDest)
Dim As descriptor Ptr pdescriptorSrc
arrayDescriptorPtr(src, pdescriptorSrc)
If pdescriptorDest <> pdescriptorSrc Then
If (pdescriptorDest->dimensionNumber = 0) Orelse (pdescriptorDest->dimensionNumber = pdescriptorSrc->dimensionNumber) Then
If pdescriptorSrc->globalSize = 0 Then
Erase dest
Else
If pdescriptorDest->globalSize <> pdescriptorSrc->globalSize Then
Select Case As Const pdescriptorSrc->dimensionNumber
Case 1
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound)
Case 2
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound)
Case 3
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound)
Case 4
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound, _
pdescriptorSrc->d(4).lowBound To pdescriptorSrc->d(4).upBound)
Case 5
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound, _
pdescriptorSrc->d(4).lowBound To pdescriptorSrc->d(4).upBound, _
pdescriptorSrc->d(5).lowBound To pdescriptorSrc->d(5).upBound)
Case 6
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound, _
pdescriptorSrc->d(4).lowBound To pdescriptorSrc->d(4).upBound, _
pdescriptorSrc->d(5).lowBound To pdescriptorSrc->d(5).upBound, _
pdescriptorSrc->d(6).lowBound To pdescriptorSrc->d(6).upBound)
Case 7
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound, _
pdescriptorSrc->d(4).lowBound To pdescriptorSrc->d(4).upBound, _
pdescriptorSrc->d(5).lowBound To pdescriptorSrc->d(5).upBound, _
pdescriptorSrc->d(6).lowBound To pdescriptorSrc->d(6).upBound, _
pdescriptorSrc->d(7).lowBound To pdescriptorSrc->d(7).upBound)
Case 8
Redim dest(pdescriptorSrc->d(1).lowBound To pdescriptorSrc->d(1).upBound, _
pdescriptorSrc->d(2).lowBound To pdescriptorSrc->d(2).upBound, _
pdescriptorSrc->d(3).lowBound To pdescriptorSrc->d(3).upBound, _
pdescriptorSrc->d(4).lowBound To pdescriptorSrc->d(4).upBound, _
pdescriptorSrc->d(5).lowBound To pdescriptorSrc->d(5).upBound, _
pdescriptorSrc->d(6).lowBound To pdescriptorSrc->d(6).upBound, _
pdescriptorSrc->d(7).lowBound To pdescriptorSrc->d(7).upBound, _
pdescriptorSrc->d(8).lowBound To pdescriptorSrc->d(8).upBound)
End Select
Else
Dim As Any Ptr ptrLbound = pdescriptorDest->ptrLbound
memcpy(pdescriptorDest, pdescriptorSrc, Offsetof(descriptor, d(pdescriptorSrc->dimensionNumber)) + Sizeof(dimension))
pdescriptorDest->ptrLbound = ptrLbound
pdescriptorDest->ptr0 = ptrLbound + (pdescriptorSrc->ptr0 - pdescriptorSrc->ptrLbound)
End If
memcpy(pdescriptorDest->ptrLbound, pdescriptorSrc->ptrLbound, pdescriptorSrc->globalSize)
End If
End If
End If
End Sub
#endmacro
'----------------------------------------------
'---------- Example 1 ----------
Dim As Short arrays1(1 To 8, 1 To 5)
For I As Integer = Lbound(arrays1, 1) To Ubound(arrays1, 1)
For J As Integer = Lbound(arrays1, 2) To Ubound(arrays1, 2)
arrays1(I,J) = 10 * I + J
Next J
Next I
Redim As Short arrays2()
quickArrayCopyDefine(Short)
Print "Initial address of destination array: " & @arrays2(Lbound(arrays2, 1), Lbound(arrays2, 2))
quickArrayCopy(arrays2(), arrays1())
Print "Final address of destination array : " & @arrays2(Lbound(arrays2, 1), Lbound(arrays2, 2))
Erase arrays1
For I As Integer = Lbound(arrays2, 1) To Ubound(arrays2, 1)
For J As Integer = Lbound(arrays2, 2) To Ubound(arrays2, 2)
Print "(" & I & "," & J & ")=" & arrays2(I, J),
Next J
Print
Next I
Print
'-------------------------------
'---------- Example 2 ----------
Dim As Zstring* 3 arrayz1(1 To 8, 1 To 5)
For I As Integer = Lbound(arrayz1, 1) To Ubound(arrayz1, 1)
For J As Integer = Lbound(arrayz1, 2) To Ubound(arrayz1, 2)
arrayz1(I,J) = Chr(64 + I) & Chr(96 + J)
Next J
Next I
Redim As Zstring * 3 arrayz2(-2 To 5, -3 To 1)
quickArrayCopyDefine(Zstring * 3)
Print "Initial address of destination array: " & @arrayz2(Lbound(arrayz2, 1), Lbound(arrayz2, 2))
quickArrayCopy(arrayz2(), arrayz1())
Print "Final address of destination array : " & @arrayz2(Lbound(arrayz2, 1), Lbound(arrayz2, 2))
Erase arrayz1
For I As Integer = Lbound(arrayz2, 1) To Ubound(arrayz2, 1)
For J As Integer = Lbound(arrayz2, 2) To Ubound(arrayz2, 2)
Print "(" & I & "," & J & ")=" & arrayz2(I, J),
Next J
Print
Next I
Print
'-------------------------------
Sleep
Code: Select all
Initial address of destination array: 0
Final address of destination array : 8989312
(1,1)=11 (1,2)=12 (1,3)=13 (1,4)=14 (1,5)=15
(2,1)=21 (2,2)=22 (2,3)=23 (2,4)=24 (2,5)=25
(3,1)=31 (3,2)=32 (3,3)=33 (3,4)=34 (3,5)=35
(4,1)=41 (4,2)=42 (4,3)=43 (4,4)=44 (4,5)=45
(5,1)=51 (5,2)=52 (5,3)=53 (5,4)=54 (5,5)=55
(6,1)=61 (6,2)=62 (6,3)=63 (6,4)=64 (6,5)=65
(7,1)=71 (7,2)=72 (7,3)=73 (7,4)=74 (7,5)=75
(8,1)=81 (8,2)=82 (8,3)=83 (8,4)=84 (8,5)=85
Initial address of destination array: 8989400
Final address of destination array : 8989400
(1,1)=Aa (1,2)=Ab (1,3)=Ac (1,4)=Ad (1,5)=Ae
(2,1)=Ba (2,2)=Bb (2,3)=Bc (2,4)=Bd (2,5)=Be
(3,1)=Ca (3,2)=Cb (3,3)=Cc (3,4)=Cd (3,5)=Ce
(4,1)=Da (4,2)=Db (4,3)=Dc (4,4)=Dd (4,5)=De
(5,1)=Ea (5,2)=Eb (5,3)=Ec (5,4)=Ed (5,5)=Ee
(6,1)=Fa (6,2)=Fb (6,3)=Fc (6,4)=Fd (6,5)=Fe
(7,1)=Ga (7,2)=Gb (7,3)=Gc (7,4)=Gd (7,5)=Ge
(8,1)=Ha (8,2)=Hb (8,3)=Hc (8,4)=Hd (8,5)=He
- How accessing to the array's descriptor structure?
- Simplistic copy for dynamic array fields when assigning between UDT instances
[edit]
"arrayCopy..." renamed to "quickArrayCopy..."