Page 1 of 1

MidFast() - A much faster Mid() alternative

Posted: Tue Feb 01, 2011 4:59 pm
by c4s
MidFast() is faster than Mid() in general use and gets thousand times faster with very large texts (try #TestLen=2500, #TestCount=1): The longer the text, the faster MidFast() gets...

Code: Select all

#TestLen = 10
#TestCount = 10000

Define Text.s, C.s, i, iMax


For i = 1 To #TestLen
	Text + "testTesttEsttestTESTtesttestteSt"
Next

ts1 = ElapsedMilliseconds()
For j = 1 To #TestCount
i = 0
iMax = Len(Text)
Repeat
	i + 1
	C = Mid(Text, i, 1)
Until i >= iMax
Next
te1 = ElapsedMilliseconds()


Macro MidFast(String, StartPos, Length)
	PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length)
EndMacro

ts2 = ElapsedMilliseconds()
For j = 1 To #TestCount
i = 0
iMax = Len(Text)
Repeat
	i + 1
	C = MidFast(Text, i, 1)
Until i >= iMax
Next
te2 = ElapsedMilliseconds()


MessageRequester("Result", "Mid() - " + Str(te1 - ts1) + #CRLF$ + "MidFast() - " + Str(te2 - ts2))
Edit:
Trond notes that it's just faster because this method doesn't check for valid position/length, so keep that in mind...

Re: MidFast() - A much faster Mid() alternative

Posted: Tue Feb 01, 2011 6:54 pm
by cas
c4s wrote:Does anyone know what internal parameter PeekS() uses to determine that "Length" isn't set? Unluckily it doesn't seem to be #PB_Default
It is #PB_Default (-1), but you can set it to -1 only if you specify 'Flags' parameter:
PB Manual wrote:When the 'Flags' parameter is specified, the 'Length' can be put to -1, to read the string until a null character is found.

Code: Select all

Macro MidFast(String, StartPos, Length=-1,Mode=#PB_Ascii)
  PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, Mode)
EndMacro

Re: MidFast() - A much faster Mid() alternative

Posted: Tue Feb 01, 2011 9:49 pm
by c4s
Oh well... Thanks for the hint. I thought I've tested it.

Re: MidFast() - A much faster Mid() alternative

Posted: Tue Feb 01, 2011 10:24 pm
by skywalk
Well, this MidFast() is the same or slower than Mid() on my x86 system with the optional parameters included?
No debugger and either unicode=ON or OFF.

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 12:29 am
by STARGÅTE
Youre Macro with Unicode:

Code: Select all

Macro MidFast(String, StartPos, Length=-1,Mode=#PB_Ascii)
  PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, Mode)
EndMacro 
String.s = "HalloWorldHallo"
Debug MidFast(String, 6, 5)
Debug Mid(String, 6, 5)
W
World
so, its better to use:

Code: Select all

CompilerIf #PB_Compiler_Unicode
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Unicode)
  EndMacro 
CompilerElse
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Ascii)
  EndMacro  
CompilerEndIf

String.s = "HalloWorldHallo"
Debug MidFast(String, 6, 5)
Debug Mid(String, 6, 5)
Debug MidFast(String, 6)
Debug Mid(String, 6)

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 2:16 am
by Guimauve
skywalk wrote:Well, this MidFast() is the same or slower than Mid() on my x86 system with the optional parameters included?
No debugger and either unicode=ON or OFF.
Yes me too, on my Linux Ubuntu x64. But when I change the "Length" to 1 instead of -1 The MidFast() it's much faster than Mid() function.

Result with Length = -1

- Mid() - 583
- MidFast() - 1587

Result with Length = 1

- Mid() - 592
- MidFast() - 120

No debbuger in both case.

Best regards.
Guimauve

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 2:57 am
by skywalk
Thanks STARGÅTE!
MidFast() is only slower when the Length = -1, not sure why, but it is worth the extra speed for other cases.
This now makes sense to use. :)

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 10:39 am
by c4s
STARGÅTE wrote:so, its better to use:

Code: Select all

CompilerIf #PB_Compiler_Unicode
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Unicode)
  EndMacro 
CompilerElse
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Ascii)
  EndMacro  
CompilerEndIf

String.s = "HalloWorldHallo"
Debug MidFast(String, 6, 5)
Debug Mid(String, 6, 5)
Debug MidFast(String, 6)
Debug Mid(String, 6)
PureBasic does this automatically so the mode parameter isn't needed at all and if it's slower with "-1" for length then better don't use it, so that it will remind you.

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 5:05 pm
by Vitor_Boss®

Code: Select all

#TestLen = 10
#TestCount = 1000
Define Text.s, C.s, C1.s, i, iMax
For i = 1 To #TestLen
   Text + "testTesttEsttestTESTtesttestteSt"
Next
ts1 = ElapsedMilliseconds()
For j = 1 To #TestCount
i = 0
iMax = Len(Text)
Repeat
   i + 1
   C1 = Mid(Text, i)
Until i >= iMax
Next
te1 = ElapsedMilliseconds()
CompilerIf #PB_Compiler_Unicode
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Unicode)
  EndMacro 
CompilerElse
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Ascii)
  EndMacro  
CompilerEndIf
ts2 = ElapsedMilliseconds()
For j = 1 To #TestCount
i = 0
iMax = Len(Text)
Repeat
   i + 1
   C = MidFast(Text, i)
Until i >= iMax
Next
te2 = ElapsedMilliseconds()
MessageRequester("Result", "Mid() - " + Str(te1 - ts1) + #CRLF$ + "MidFast() - " + Str(te2 - ts2) + #CRLF$ + #CRLF$ + "Text = C : "+Str(C=C1))
On my PC(Win7 x64) the MidFast was faster on both cases
Result with Length = -1
- Mid() - 468
- MidFast() - 312

Result with Length = 1
- Mid() - 102
- MidFast() - 31

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 5:27 pm
by IdeasVacuum
... I wonder if pcfreak could make an even faster MidFast with assembler?

http://www.purebasic.fr/english/viewtop ... 85#p345585

Re: MidFast() - A much faster Mid() alternative

Posted: Wed Feb 02, 2011 8:57 pm
by Trond
Just a side note: The reason the normal Mid() is slow is because it does bound checking (so you don't access memory outside the string). To use a Mid() without bound checking safely you would most often need to check the length beforehand, which would nullify the speed gain.

Re: MidFast() - A much faster Mid() alternative

Posted: Thu Feb 03, 2011 7:40 am
by skywalk
c4s wrote:Note: Passing constant strings (like "text") doesn't work because it's a macro.
What do you mean "doesn't work"?

Code: Select all

CompilerIf #PB_Compiler_Unicode
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Unicode)
  EndMacro 
CompilerElse
  Macro MidFast(String, StartPos, Length=-1)
    PeekS(@String + ((StartPos - 1) * SizeOf(Character)), Length, #PB_Ascii)
  EndMacro  
CompilerEndIf
Define.s C, Text = "Text"
C = MidFast(Text, 2):   Debug C
C = MidFast("Text", 2): Debug C     ;<-- This works on v4.51 x86

Re: MidFast() - A much faster Mid() alternative

Posted: Thu Feb 03, 2011 8:08 pm
by c4s
Seems that I did something wrong during my testings, now it works here as well. I edited my first post to not confuse others and also added Trond's note.