﻿#AutoIt3Wrapper_UseX64=n                          ; 32Bit-Modus!
#include "AssembleIt2\assembleit2_64.au3"         ; <- Achtung! Pfad evtl. anpassen!
#include <Memory.au3>

#Region ASM-Code
#cs StringCompare
    Use32                                         ; 32Bit Modus!
    mov esi,[esp+4]                               ; esi = String1 (Pointer)
    mov edi,[esp+8]                               ; edi = String2 (Pointer)
	mov eax,esi
	call strlen
	mov ebx,eax
;~ 	_asmdbg_()
	mov eax,edi
	call strlen
	mov ecx,eax
	cmp ecx,ebx
	ja @f
		mov ecx,ebx
	@@:
	cld                                           ; Direction-Flag loeschen
    repe cmpsb                                    ; die Strings vergleichen (repe = wiederhole so viele Zeichen, wie in ecx vorgegeben)
    jb @below                                     ; wenn kleiner, dann springe zu @below
    ja @above                                     ; wenn groesser, dann springe zu @above
        mov eax,1                                 ; wenn String1 = String2, dann eax = 1
        ret                                       ; zurueck zu AutoIt
    @above:
        mov eax,2                                 ; wenn String1 > String2, dann eax = 2
        ret                                       ; zurueck zu AutoIt
    @below:
        mov eax,0                                 ; wenn String1 < String2, dann eax = 0
        ret                                       ; zurueck zu AutoIt

	; strlenSSE2.asm
	; Author:           Agner Fog
	; Date created:     2008-07-06
	; Last modified:    2008-07-06
	strlen:
		mov ecx,eax                              ; copy pointer
		pxor xmm0,xmm0                           ; set to zero
		and ecx,15                               ; lower 4 bits indicate misalignment
		and eax,-16                              ; align pointer by 16
		movdqa xmm1,[eax]                        ; read from nearest preceding boundary
		pcmpeqb xmm1,xmm0                        ; compare 16 bytes with zero
		pmovmskb edx,xmm1                        ; get one bit for each byte result
		shr edx,cl                               ; shift out false bits
		shl edx,cl                               ; shift back again
		bsf edx,edx                              ; find first 1-bit
		jnz @L2                                  ; found
		@L1:                                     ; Main loop, search 16 bytes at a time
			add eax,16                           ; increment pointer by 16
			movdqa xmm1,[eax]                    ; read 16 bytes aligned
			pcmpeqb xmm1,xmm0                    ; compare 16 bytes with zero
			pmovmskb edx,xmm1                    ; get one bit for each byte result
			bsf edx,edx                          ; find first 1-bit
			jz @L1                               ; loop if not found
		@L2:                                     ; Zero-byte found. Compute string length
			sub eax,[esp+4]                      ; subtract start address
			add eax,edx                          ; add byte index
			ret
#ce
#EndRegion ASM-Code

#region AssembleIt ; wenn diese 3 Zeilen aktiv sind, dann wird der obige ASM-Code in Binaercode umgewandelt
;~ $binarycode = _AssembleIt2('retbinary', 'StringCompare') ; gibt nur den assemblierten code zurück
;~ ConsoleWrite('$binarycode = "' & $binarycode & '"' & @CRLF)
;~ Exit
#EndRegion AssembleIt

#Region ASM-Binaercode ; $__g_bASMCode entspricht dem obigen ASM-Code im Binaerformat
Global Const $__g_bASMCode = '0x8B7424048B7C240889F0E82A00000089C389F8E82100000089C139D9770289D9FCF3A6720E7706B801000000C3B802000000C3B800000000C389C1660FEFC083E10F83E0F0660F6F08660F74C8660FD7D1D3EAD3E20FBCD2751483C010660F6F08660F74C8660FD7D10FBCD274EC2B44240401D0C3'
Global Const $__g_iMemSize = StringLen($__g_bASMCode) / 2 - 1 ; Codelaenge ermitteln
Global Const $__g_pMem = _MemVirtualAlloc(0, $__g_iMemSize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) ; Virtuellen Speicher reservieren
If $__g_pMem = 0 Then Exit MsgBox(16, 'Error!', "Can't allocate virtual memory!")
Global $__g_tASMCode = DllStructCreate('byte[' & $__g_iMemSize & ']', $__g_pMem) ; Structur fuer den Binaercode erstellen
DllStructSetData($__g_tASMCode, 1, $__g_bASMCode) ; den Binaercode in die Structur schreiben
Global $__g_pASMCode = DllStructGetPtr($__g_tASMCode) ; den Pointer der Structur holen
ConsoleWrite(StringFormat('ASM-Code-Size:\t%i Bytes\n', $__g_iMemSize))
#EndRegion ASM-Binaercode

Global Const $aCompare[] = ['<', '=', '>']
Global $sTest = ''
For $i = 0 To 9999999
	$sTest &= Chr(Random(65, 122, 1))
Next
ConsoleWrite(StringFormat('Teststring:\t%i Chars\n\n', StringLen($sTest)))
;~ Global $aString[2] = ['Das ist ein Text.12', 'Das ist ein Text.1']
Global $aString[2] = [$sTest, $sTest & '1']
$tStruct1 = _String2Struct($aString[0])
$pStruct1 = DllStructGetPtr($tStruct1)
$tStruct2 = _String2Struct($aString[1])
$pStruct2 = DllStructGetPtr($tStruct2)

ConsoleWrite(StringFormat('AutoIt-StringCompare:\n'))
$iTimer = TimerInit()
$ret = StringCompare($aString[0], $aString[1])
ConsoleWrite(StringFormat('Zeit:    \t%.3f ms\n', Round(TimerDiff($iTimer), 3)))
ConsoleWrite(StringFormat('Ergebnis:\tString1 %s String2\n\n', $aCompare[$ret+1]))

ConsoleWrite(StringFormat('ASM-StringCompare:\n'))
$iTimer = TimerInit()
$ret = DllCallAddress('uint:cdecl', $__g_pASMCode, 'ptr', $pStruct1, 'ptr', $pStruct2)
$ret = $ret[0]
;~ $ret = _AssembleIt2('dword', 'StringCompare', 'ptr', $pStruct1, 'ptr', $pStruct2)
ConsoleWrite(StringFormat('Zeit:    \t%.3f ms\n', Round(TimerDiff($iTimer), 3)))
ConsoleWrite(StringFormat('Ergebnis:\tString1 %s String2\n', $aCompare[$ret]))


If $__g_pMem > 0 Then _MemVirtualFree($__g_pMem, $__g_iMemSize, $MEM_DECOMMIT)

Func _String2Struct($sString)
    $sString &= Chr(0)
    Local $tStruct = DllStructCreate('char[' & StringLen($sString) & ']')
    DllStructSetData($tStruct, 1, $sString)
    Return $tStruct
EndFunc