Fast Array Copy

Category: Arrays

Date: 02-16-2022

Return to Index


 
'Often, a programmer needs to make a copy of an array. Here are a
'couple of ways to do the trick.
 
'Primary Code:
'A simple For/Next loop will work just fine:
For i = 0 to UBound(MyArray)
   NewArray(i) = MyArray(i)
Next i
 
'A faster approach is to do a block copy using Peek$/Poke$
Source& = VarPTR(OriginalArray%(1))
Dest& = VarPTR(NewArray%(1))
ArrayLen& = Elements& * 2 'byte length of array
Poke$ Dest&, Peek$(Source&, ArrayLen&) 'copy block
 
'The PowerBASIC MAT statement works even faster
Mat NewArray() = MyArray()
 
'Compilable Example:  (Jose Includes)
#Compiler PBWin 9, PBWin 10
#Compile EXE
#Dim All
%Unicode=1
 
Type MyType
   x As Long
   s As String * 5
End Type
 
   #Include "Win32API.inc"
   Global hDlg As Dword, MyArray(), NewArray() As Long
 
Function PBMain() As Long
   Dim MyArray(10000) As Long, NewArray(10000) As Long
   Dialog New Pixels, 0, "Test Code",300,300,300,200, %WS_OverlappedWindow To hDlg
   Control Add Button, hDlg, 100,"For/Next Loop", 20,20,120,20
   Control Add Button, hDlg, 200,"Block Copy", 20,50,120,20
   Control Add Button, hDlg, 300,"MAT Copy", 20,80,120,20
   Control Add Button, hDlg, 400,"CopyMemory Copy", 20,110,120,20
   Dialog Show Modal hDlg Call DlgProc
End Function
 
CallBack Function DlgProc() As Long
   Local i,j,iStart, iEnd As Long
   If Cb.Msg = %WM_Command And Cb.Ctl = 100 And Cb.CtlMsg = %BN_Clicked Then
      For i = 0 To UBound(MyArray) : MyArray(i) = Rnd(1,1000) : Next i
      iStart = GetTickCount
      For i = 1 To 100000
         For j = 0 To UBound(MyArray)
            NewArray(j) = MyArray(j)
         Next j
      Next i
      iEnd = GetTickCount
      MsgBox Format$((iEnd - iStart)/1000,3) & " seconds"
   End If
   If Cb.Msg = %WM_Command And Cb.Ctl = 200 And Cb.CtlMsg = %BN_Clicked Then
      Local Source&, Dest&, ArrayLen&
      For i = 0 To UBound(MyArray) : MyArray(i) = Rnd(1,1000) : Next i
      iStart = GetTickCount
      For i = 1 To 100000
         '         Source& = VarPTR(MyArray(0))
         '         Dest& = VarPTR(NewArray(0))
         '         ArrayLen& = (UBound(MyArray)+1) * SizeOf(MyArray(0))    'byte length of zero-based array
         '         Poke$ Dest&, Peek$(Source&, ArrayLen&)                  'copy block
         Poke$ VarPtr(NewArray(0)), Peek$(VarPtr(MyArray(0)), (UBound(MyArray)+1) * SizeOf(MyArray(0)))                  'copy block
      Next i
      iEnd = GetTickCount
      MsgBox Format$((iEnd - iStart)/1000,3) & " seconds"
   End If
   If Cb.Msg = %WM_Command And Cb.Ctl = 300 And Cb.CtlMsg = %BN_Clicked Then
      For i = 0 To UBound(MyArray) : MyArray(i) = Rnd(1,1000) : Next i
      iStart = GetTickCount
      For i = 1 To 100000
         Mat NewArray() = MyArray()
      Next i
      iEnd = GetTickCount
      MsgBox Format$((iEnd - iStart)/1000,3) & " seconds"
      For i = 0 To UBound(NewArray)    'verify results
         If NewArray(i) <> MyArray(i) Then ? "not equal" : Exit For
      Next i
   End If
   If Cb.Msg = %WM_Command And Cb.Ctl = 400 And Cb.CtlMsg = %BN_Clicked Then
      For i = 0 To UBound(MyArray) : MyArray(i) = Rnd(1,1000) : Next i
      iStart = GetTickCount
      For i = 1 To 100000
         CopyMemory VarPtr(NewArray(0)), VarPtr(MyArray(0)), ArrayAttr(MyArray(),5) * ArrayAttr(MyArray(),4)
      Next i
      iEnd = GetTickCount
      MsgBox Format$((iEnd - iStart)/1000,3) & " seconds"
      For i = 0 To UBound(NewArray)    'verify results
         If NewArray(i) <> MyArray(i) Then ? "not equal" : Exit For
      Next i
   End If
End Function
'gbs_00565
'Date: 03-10-2012


created by gbSnippets
http://www.garybeene.com/sw/gbsnippets.htm