Sometimes I need to create a long string by repeating a particular shorter string n times.
That's why I wrote a function RepeatString(n, s$) for my private standard library.
When s$ only consists of 1 character, the new string can be created very quickly by (ab)using LSet(), so I wrote a special function RepeatChar(n, s$) for this.
The following code implemets speed tests. RepeatString1() is the fastest RepeatString version tested here.
Can anyone provide a cross-platform version that is even faster?
PS: I deliberately didn't write a version of RepeatString that uses ReplaceString() with #PB_String_InPlace, because Fred has removed that option in PureBasic 6.40.
Code: Select all
; PB 6.30 (x64)
CompilerIf #PB_Compiler_Debugger
CompilerError "For speed testing, switch the debugger off"
CompilerEndIf
EnableExplicit
Macro RepeatChar (_count_, _char_=" ")
; This is *very* fast, but '_char_' can only contain
; 1 character (any following characters are ignored).
LSet("", _count_, _char_)
EndMacro
Procedure.s RepeatString1 (count.i, text$)
; RepeatChar() is considerably faster, but this
; procedure can repeat more than 1 character.
Protected _, numChars.i, stepp.i, *p, ret$
If count < 0
ProcedureReturn "" ; error
EndIf
numChars = Len(text$)
stepp = numChars * SizeOf(Character)
ret$ = Space(count * numChars)
*p = @ret$
For _ = 1 To count
PokeS(*p, text$)
*p + stepp
Next
ProcedureReturn ret$
EndProcedure
Procedure.s RepeatString2 (count.i, text$)
Protected numChars.i, ret$
If count < 0
ProcedureReturn "" ; error
EndIf
numChars = Len(text$)
ret$ = Space(count * numChars)
ProcedureReturn ReplaceString(ret$, Space(numChars), text$)
EndProcedure
Procedure.s RepeatString3 (count.i, text$)
Protected ret$
If count < 0
ProcedureReturn "" ; error
EndIf
ret$ = Space(count)
ProcedureReturn ReplaceString(ret$, " ", text$)
EndProcedure
Define r$, c$, s$
Define.i _, loops, n
Define.i t0, t1, t2, t3
loops = 20000
; -----------------------------------------------------------------------------
n = 40000
c$ = "x"
t0 = ElapsedMilliseconds()
For _ = 1 To loops
r$ = RepeatChar(n, c$)
Next
t0 = ElapsedMilliseconds() - t0
t1 = ElapsedMilliseconds()
For _ = 1 To loops
r$ = RepeatString1(n, c$)
Next
t1 = ElapsedMilliseconds() - t1
MessageRequester("Test #1: repeat 1 character",
"t0 = " + StrD(t0/1000, 1) + " sec." + #LF$ + ; -> 0.2 sec.
"t1 = " + StrD(t1/1000, 1) + " sec.") ; -> 3.0 sec.
; -----------------------------------------------------------------------------
n = 10000
s$ = "abcde"
t1 = ElapsedMilliseconds()
For _ = 1 To loops
r$ = RepeatString1(n, s$)
Next
t1 = ElapsedMilliseconds() - t1
t2 = ElapsedMilliseconds()
For _ = 1 To loops
r$ = RepeatString3(n, s$)
Next
t2 = ElapsedMilliseconds() - t2
t3 = ElapsedMilliseconds()
For _ = 1 To loops
r$ = RepeatString2(n, s$)
Next
t3 = ElapsedMilliseconds() - t3
MessageRequester("Test #2: repeat " + Len(s$) + " characters",
"t1 = " + StrD(t1/1000, 1) + " sec." + #LF$ + ; -> 2.0 sec.
"t2 = " + StrD(t2/1000, 1) + " sec." + #LF$ + ; -> 2.4 sec.
"t3 = " + StrD(t3/1000, 1) + " sec.") ; -> 3.9 sec.
