Code: Select all
! macro EndMacro {}
; Assembler macro to align code on a given boundary,
; aligning loop starts on 8 byte boundaries can speed up the code
; by about 1.5 to 2 times!
! macro calignjmp value
! {
! local dest
!
! if ((value - 1) - ((($ - $$) + value - 1) mod value)) > 3
! makeDest equ 1
! jmp dest
! else
! makeDest equ 0
! end if
!
! rept value
! \{
! if ($ - $$) mod value
! nop
! end if
! \}
! dest:
! } EndMacro
; Uncommend the next 3 lines, if you want to replace
; Mid with FMid in all places:
; Macro Mid(string, start, length)
; FMid(@string,start,length)
; EndMacro
CompilerIf #PB_Compiler_Unicode
Procedure.s FMid(*srcPtr.Word, start.l, length.l)
!MOV edx,[p.p_srcPtr]
!MOV ecx,[p.v_length]
!TEST edx,edx
!JZ l_fmid_empty
!TEST ecx,ecx
!JLE l_fmid_empty
!MOV ecx,[p.v_start]
!CMP ecx,1
!JLE l_fmid_return
!XOR eax,eax
!DEC ecx
!calignjmp 4
fmid_scan:
!CMP [edx],ax
!JE l_fmid_scanend
!ADD edx,2
!DEC ecx
!JNZ l_fmid_scan
fmid_scanend:
!MOV [p.p_srcPtr],edx
fmid_return:
ProcedureReturn PeekS(*srcPtr, length)
fmid_empty:
ProcedureReturn ""
EndProcedure
CompilerElse
Procedure.s FMid(*srcPtr.Byte, start.l, length.l)
!MOV edx,[p.p_srcPtr]
!MOV ecx,[p.v_length]
!TEST edx,edx
!JZ l_fmid_empty
!TEST ecx,ecx
!JLE l_fmid_empty
!MOV ecx,[p.v_start]
!CMP ecx,1
!JLE l_fmid_return
!XOR eax,eax
!DEC ecx
!calignjmp 4
fmid_scan:
!CMP [edx],al
!JE l_fmid_scanend
!INC edx
!DEC ecx
!JNZ l_fmid_scan
fmid_scanend:
!MOV [p.p_srcPtr],edx
fmid_return:
ProcedureReturn PeekS(*srcPtr, length)
fmid_empty:
ProcedureReturn ""
EndProcedure
CompilerEndIf
Code: Select all
EnableExplicit
;IncludePath #PBIncludePath
XIncludeFile "FMid.pbi"
OpenConsole()
Global tStart.l, tStart2.l, tDiff.d
Global str1.s, str1Pos.l, str1Len.l = 16384, str1Mid.s
Global i.l, iEnd.l, strCh.l
strCh = 1
For i = 1 To str1Len
str1 + Chr(strCh)
strCh + 1
If strCh > 255: strCh = 1: EndIf
Next i
iEnd = 10000000
str1Pos = 1
While str1Pos <= str1Len
tStart2 = ElapsedMilliseconds(): Repeat: tStart = ElapsedMilliseconds(): Until tStart <> tStart2
For i = 1 To iEnd
str1Mid = Mid(str1, str1Pos, 1)
Next i
tDiff = (ElapsedMilliseconds() - tStart) / 1000.0
If tDiff >= 1: iEnd / tDiff: EndIf
PrintN(Right(" " + Str(str1Pos), 7) + ": " + StrD(tDiff, 3) + " sec., Ops per sec.: " + StrD(iEnd / tDiff, 3) + " " + Str(Asc(str1Mid)))
str1Pos + str1Pos
Wend
PrintN("")
iEnd = 1000000
str1Pos = 1
While str1Pos <= str1Len
tStart2 = ElapsedMilliseconds(): Repeat: tStart = ElapsedMilliseconds(): Until tStart <> tStart2
For i = 1 To iEnd
str1Mid = FMid(@str1, str1Pos, 1)
Next i
tDiff = (ElapsedMilliseconds() - tStart) / 1000.0
If str1Mid <> Mid(str1, str1Pos, 1): PrintN("Error"): EndIf
If tDiff >= 1: iEnd / tDiff: EndIf
PrintN(Right(" " + Str(str1Pos), 7) + ": " + StrD(tDiff, 3) + " sec., Ops per sec.: " + StrD(iEnd / tDiff, 3) + " " + Str(Asc(str1Mid)))
str1Pos + str1Pos
Wend
PrintN("")
PrintN(#CRLF$ + "Done")
While Inkey() = "": Delay(100): Wend
but FMid() is even faster on extracting from the start of a string,
for longer string the speed gain is between 2-3 times for positions above
64 for ascii strings, and about 1.5 - 2 for unicode strings.