Jump to content

Recommended Posts

Posted

As @Jon decided not to provide Array pointer, here's a small UDF to convert an array to a SafeArray and vice versa.
You can get the SafeArray.au3 from https://www.autoitscript.com/forum/topic/200660-variants-and-safearrays/

 

#include <Array.au3>
#include "SafeArray.au3"
#include "ArrayPointer UDF.au3"

__Example_0A()
Func __Example_0A()
    Local $Ary_0 = [[123456, 12.34, 'how are you?', -0.1234], [-100.001, 0.00009, "", 'Is it working?']]
    _ArrayDisplay( $Ary_0 )

    Local $t_SAobj
    Local $o_SAobj = __SafeArray_Dummy_Obj($t_SAobj)

    ;~~ Convert Array to SafeArray Pointer
    ;~~ Now you can pass the SafeArray pointer($psa) to any language, such as C, Python..........
    Local $psa
    $o_SAobj.Array_to_SafeArray($Ary_0, $psa)
    SafeArrayUnaccessData( $psa )

    ;~~ convert SafeArray Pointer to Array
    Local $p_Array_Copy
    $o_SAobj.SafeArray_to_Array($psa, $p_Array_Copy)
    SafeArrayDestroy($psa)      ;~~ delete the safeArray pointer when done.
    _ArrayDisplay( $p_Array_Copy )

    $o_SAobj = 0
    __Delete_SafeArray_ObjectFromTag( $t_SAobj )
EndFunc

 

ArrayPointer UDF.au3

Posted

1) Convert DllStruct of int to Array

#include <Array.au3>
#include "SafeArray.au3"
#include "Variant.au3"
#include "ArrayPointer UDF.au3"

__Example_1A()
Func __Example_1A()
    Local $n = 10
    Local $t_DllStruct = DllStructCreate( "int[" & $n & "]" )
    Local $p_DllStruct = DllStructGetPtr( $t_DllStruct )
    Local $nSize = DllStructGetSize($t_DllStruct)
    ConsoleWrite("+ " & $nSize & @CRLF)

    For $i = 1 To $n
        DllStructSetData($t_DllStruct, 1, $i, $i)
    Next

    Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND )
    DllStructSetData( $tsaBound, "cElements", $n )
    DllStructSetData( $tsaBound, "lLbound", 0 )
    Local $psa = SafeArrayCreate( $VT_I4, 1, $tsaBound )

    Local $psaData
    SafeArrayAccessData( $psa, $psaData )

    Local $tSafeArrayBytes = DllStructCreate( "byte[" & $nSize & "]", $psaData )
    DllStructSetData( $tSafeArrayBytes, 1, DllStructGetData( DllStructCreate( "byte[" & $nSize & "]", $p_DllStruct ), 1 ) )
    SafeArrayUnaccessData( $psa )

    Local $t_SF_Obj
    Local $o_SF_Obj = __SafeArray_Dummy_Obj($t_SF_Obj)
    If Not IsObj($o_SF_Obj) Then Return

    Local $p_Array
    $o_SF_Obj.SafeArray_to_Array($psa, $p_Array)

    SafeArrayDestroy($psa)
    _ArrayDisplay( $p_Array )

    $o_SF_Obj = 0
    __Delete_SafeArray_ObjectFromTag( $t_SF_Obj )
EndFunc

 

2) Convert DllStruct of char to Array

#include <Array.au3>
#include "SafeArray.au3"
#include "Variant.au3"
#include "ArrayPointer UDF.au3"

__Example_1B()
Func __Example_1B()
    Local $t_DllStruct = DllStructCreate("wchar var1[20];char var2[20];char var3[20]")
    DllStructSetData($t_DllStruct, "var1", "How are you?")
    DllStructSetData($t_DllStruct, "var2", "Is it working?")
    DllStructSetData($t_DllStruct, "var3", "Hope, so....")
    Local $p_DllStruct = DllStructGetPtr($t_DllStruct)
    Local $nSize = DllStructGetSize($t_DllStruct)

    Local $nFields = 3
    Local $tsaBound = DllStructCreate($tagSAFEARRAYBOUND)
    DllStructSetData($tsaBound, "cElements", $nFields)
    DllStructSetData($tsaBound, "lLbound", 0)
    Local $psa = SafeArrayCreate($VT_BSTR, 1, $tsaBound)

    Local $psaData
    SafeArrayAccessData($psa, $psaData)

    Local $bstr
    Local $tSafeArrayStrings = DllStructCreate("ptr[" & $nFields & "]", $psaData)
    For $i = 1 To $nFields
        $bstr = SysAllocString(DllStructGetData($t_DllStruct, $i))
        DllStructSetData($tSafeArrayStrings, 1, $bstr, $i)
        $bstr = 0
    Next
    SafeArrayUnaccessData($psa)

    Local $t_SF_Obj
    Local $o_SF_Obj = __SafeArray_Dummy_Obj($t_SF_Obj)
    If Not IsObj($o_SF_Obj) Then Return

    Local $p_Array
    $o_SF_Obj.SafeArray_to_Array($psa, $p_Array)

    SafeArrayDestroy($psa)
    _ArrayDisplay($p_Array)

    $o_SF_Obj = 0
    __Delete_SafeArray_ObjectFromTag($t_SF_Obj)
EndFunc

 

  • 3 weeks later...
Posted (edited)

_ArrayDelete  ( Delete Row of 1D and 2D Array )

I considered doing this using ASM code, but @Jos raised a question, so I discarded that method.
https://www.autoitscript.com/forum/topic/212996-asm-help-using-string/

You can perform array Add, Insert, Merge, Slice operations using the same technique shown below.

The problem is that to manipulate a SafeArray by column using RtlMoveMemory, you need to write C code.

 

#include <Array.au3>
#include "SafeArray.au3"
#include "Variant.au3"
#include "ArrayPointer UDF.au3"

;__Example_A()
__Example_B()

Func __Example_A()
    Local $Ary_0 = [['A1', 'A2', 'A3', 'A4'], ['B1', 'B2', 'B3', 'B4'], ['C1', 'C2', 'C3', 'C4'], ['D1', 'D2', 'D3', 'D4'], ['E1', 'E2', 'E3', 'E4'], _
                    ['F1', 'F2', 'F3', 'F4'], ['G1', 'G2', 'G3', 'G4'], ['H1', 'H2', 'H3', 'H4'], ['I1', 'I2', 'I3', 'I4'], ['J1', 'J2', 'J3', 'J4']]

;   Local $Ary_0 = ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']
    _ArrayDisplay( $Ary_0 )

;   $hTime_B = TimerInit()
;   _ArrayDelete($Ary_0, '0;3;5;7;8')
;   ConsoleWrite(">  _ArrayDelete:  " & TimerDiff($hTime_B)&@CRLF)

    $hTime_C = TimerInit()
    __Delete_1D_2D_Row($Ary_0, '0,3,5,7,8')
    ConsoleWrite(">  __Delete_1D_2D_Row:  " & TimerDiff($hTime_C)&@CRLF)

    _ArrayDisplay( $Ary_0 )
EndFunc

Func __Example_B()
    $hTime_A = TimerInit()
    Local $Ary_0[5000][100]
    For $i = 0 To UBound($Ary_0, 1) - 1
        For $j = 0 To UBound($Ary_0, 2) - 1
            $Ary_0[$i][$j] = $i & "-" & $j
        Next
    Next
    ConsoleWrite(">  Array_Create:  " & TimerDiff($hTime_A)&@CRLF)

;   $hTime_B = TimerInit()
;   _ArrayDelete($Ary_0, '0;3;5;7;8')
;   ConsoleWrite(">  _ArrayDelete:  " & TimerDiff($hTime_B)&@CRLF)

    $hTime_C = TimerInit()
    __Delete_1D_2D_Row($Ary_0, '0,3,5,7,8')
    ConsoleWrite(">  __Delete_1D_2D_Row:  " & TimerDiff($hTime_C)&@CRLF)
EndFunc


; #FUNCTION# =============================================================================
; Name...........: __Delete_1D_2D_Row
; @jugador
; ========================================================================================
Func __Delete_1D_2D_Row(Byref $Array, $row_to_delete)
    Local $t_SAobj
    Local $o_SAobj = __SafeArray_Dummy_Obj($t_SAobj)

;   Local $SafeArray_time_A = TimerInit()
    Local $psa_A
    $o_SAobj.Array_to_SafeArray($Array, $psa_A)
    SafeArrayUnaccessData( $psa_A )
;   ConsoleWrite("!  Time taken to pass Array through Com object:  " & TimerDiff($SafeArray_time_A) &@CRLF)

;   Local $SafeArray_time_taken_toDelete = TimerInit()
    Local $New_PsaCopy
    __SafeArray_Delete_Row($psa_A, $New_PsaCopy, $row_to_delete)
;   ConsoleWrite("+  __SafeArray_Delete_Row:  " & TimerDiff($SafeArray_time_taken_toDelete) &@CRLF)

;   Local $SafeArray_time_B = TimerInit()
    Local $Array_Copy
    $o_SAobj.SafeArray_to_Array($New_PsaCopy, $Array_Copy)
;   ConsoleWrite("!  Time taken to pass SafeArray through Com object:  " & TimerDiff($SafeArray_time_B) &@CRLF)

    SafeArrayDestroy($New_PsaCopy)
    SafeArrayDestroy($psa_A)

    $o_SAobj = 0
    __Delete_SafeArray_ObjectFromTag( $t_SAobj )

    $Array = $Array_Copy
EndFunc

; #FUNCTION# =============================================================================
; Name...........: __SafeArray_Delete_Row
; @jugador
; ========================================================================================
Func __SafeArray_Delete_Row(Byref $pSafearray, Byref $pFreshCopy, $row_to_delete)
    Local $vt_Size = 16
    Local $n_Row, $n_Column

    Local $tSafeArray = DllStructCreate( $tagSAFEARRAY, $pSafearray )
    Local $cDims = DllStructGetData( $tSAFEARRAY, "cDims" )

    If $cDims = 1 Then
        $n_Row = DllStructGetData( $tSAFEARRAY, "cElements" )
        $n_Column = 1

        Local $t_New_SArray = DllStructCreate( $tagSAFEARRAYBOUND)
        DllStructSetData( $t_New_SArray, 1, $n_Row )
        DllStructSetData( $t_New_SArray, 2, 0 )
        $pFreshCopy = SafeArrayCreate( $VT_VARIANT, 1, $t_New_SArray )
    Endif

    If $cDims = 2 Then
        Local $RC_array = __Get_SafeArray_Number_of_Row_Column($pSafearray)
        $n_Row = $RC_array[0]
        $n_Column = $RC_array[1]

        Local $t_New_SArray = DllStructCreate( $tagSAFEARRAYBOUND  & $tagSAFEARRAYBOUND)
        DllStructSetData( $t_New_SArray, 1, $n_Column )
        DllStructSetData( $t_New_SArray, 2, 0 )
        DllStructSetData( $t_New_SArray, 3, $n_Row )
        DllStructSetData( $t_New_SArray, 4, 0 )
        $pFreshCopy = SafeArrayCreate( $VT_VARIANT, 2, $t_New_SArray )
    Endif

    If $cDims > 2 Then Return

    Local $Psa_Source, $Psa_Destination
    SafeArrayAccessData( $pSafearray, $Psa_Source )
    SafeArrayAccessData( $pFreshCopy, $Psa_Destination )

    Local $Total_Row = $n_Row - 1
    Local $a_Row_to_Delete = StringSplit($row_to_delete, ',', 2)

    Local $R_flag = False, $Row_Hold = ''
    Local $to_Delete_Row_Number, $Row_for_Sanity_Check = ''
    Local $No_of_Row_toCopy = 0, $Source_Row_No = 0, $Destination_Row_No = 0
    For $i = 0 To UBound($a_Row_to_Delete) - 1
        $to_Delete_Row_Number = $a_Row_to_Delete[$i]
        If $to_Delete_Row_Number = $Row_for_Sanity_Check Then
            $R_flag = False
            $Row_Hold = $i
        Else
            $Source_Row_No = ($R_flag ? $a_Row_to_Delete[$i - 1] + 1 : (($i = 0) ? 0 : $a_Row_to_Delete[$Row_Hold] + 1))

            $Destination_Row_No += $No_of_Row_toCopy
            $No_of_Row_toCopy = $to_Delete_Row_Number - $Row_for_Sanity_Check
            If $to_Delete_Row_Number <> 0 Then
                DllCall("kernel32.dll", "none", "RtlMoveMemory", _
                            "ptr", $Psa_Destination + (($Destination_Row_No * $n_Column) * $vt_Size), _
                            "ptr", $Psa_Source + (($Source_Row_No * $n_Column) * $vt_Size), _
                            "dword", (($No_of_Row_toCopy * $n_Column) * $vt_Size))
            Endif
            $R_flag = True
        Endif
        $Row_for_Sanity_Check = $to_Delete_Row_Number + 1
    Next

    Local $Re_dim = $Destination_Row_No + $No_of_Row_toCopy
    If ($Total_Row - $to_Delete_Row_Number) > 0 Then
        DllCall("kernel32.dll", "none", "RtlMoveMemory", _
                    "ptr", $Psa_Destination + (($Re_dim * $n_Column) * $vt_Size), _
                    "ptr", $Psa_Source + ((($to_Delete_Row_Number + 1) * $n_Column) * $vt_Size), _
                    "dword", ((($Total_Row - $to_Delete_Row_Number) * $n_Column) * $vt_Size))

        $Re_dim = $Re_dim + ($Total_Row - $to_Delete_Row_Number)
    Endif

    SafeArrayUnaccessData($pFreshCopy)

    Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND)
    DllStructSetData( $tsaBound, 1, $Re_dim )
    DllStructSetData( $tsaBound, 2, 0 )
    SafeArrayRedim( $pFreshCopy, $tsaBound )
EndFunc

; #FUNCTION# =============================================================================
; Name...........: __Get_SafeArray_Number_of_Row_Column
; ========================================================================================
Func __Get_SafeArray_Number_of_Row_Column(Byref $pSafearray)
    Local $irow_UBound, $icolumn_UBound
    Local $irow_LBound, $icolumn_LBound
    Local $tArray[2]
    SafeArrayGetUBound($pSafearray, 2, $irow_UBound)
    SafeArrayGetLBound($pSafearray, 2, $irow_LBound)
    SafeArrayGetUBound($pSafearray, 1, $icolumn_UBound)
    SafeArrayGetLBound($pSafearray, 1, $icolumn_LBound)

    $tArray[0] = ($irow_UBound + $irow_LBound) + 1
    $tArray[1] = ($icolumn_UBound + $icolumn_LBound) + 1
    Return $tArray
EndFunc

 

__Example_B()  ConsoleWrite:

__Example_B()
>  Array_Create:  1145.71739533647
!  Time taken to pass Array through Com object:  537.44615029274        <<= can't do anyting about this as this is AutoIt internal thing
+  __SafeArray_Delete_Row:  5.64971355980248            ;<============= this the original time taken to delete given row
!  Time taken to pass SafeArray through Com object:  266.234002568688   <<= can't do anyting about this as this is AutoIt internal thing
>  __Delete_1D_2D_Row:  868.525524148816

So to delete row of Array[5000][100], actual time taken just 5.64971355980248 :)

Edited by jugador

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...