Posted: Mon Feb 04, 2008 3:42 am
Isn't the OP's suggestion causing a memory leak due to the allocated memory he then copies with PeekS on return ? .. IMO that's not cool.
http://www.purebasic.com
https://www.purebasic.fr/english/
Otherwise, I can't release the memoryThe Split function currently looks like this: (But I want to clean it up and merge the midmem() into it and get rid of the function call)
Code: Select all
Procedure.s MidFast(dwSrc.l, dwStart.l, dwEnd.l)
If dwSrc
If (dwEnd > 0) And (dwStart > 0)
Define.s szRet
szRet = Space(dwEnd)
CopyMemory(dwSrc + dwStart -1, @szRet, dwEnd)
ProcedureReturn szRet
EndIf
EndIf
EndProcedure
str.s = "Hello World"
Debug MidFast(@str, 1, 4)
Debug MidFast(@str, 8, 2)
Debug MidFast(@str, 7, 5)
Debug "-----------------"
Debug Mid(str, 1, 4)
Debug Mid(str, 8, 2)
Debug Mid(str, 7, 5)
Code: Select all
Procedure.s MidMem(*MainMem, StartPos.l, GetLen.l)
If *MainMem = 0 Or GetLen = 0
ProcedureReturn ""
EndIf
*RetMem = AllocateMemory(GetLen)
CopyMemory(*MainMem + StartPos -1, *RetMem, GetLen)
ReturnString.s = PeekS(*RetMem,GetLen)
FreeMemory(*RetMem)
ProcedureReturn ReturnString
EndProcedure
Code: Select all
EnableExplicit
Macro MidMemLightning(string,startpos,length)
PeekS(@string+(startpos*SizeOf(Character))-SizeOf(Character),length)
EndMacro
Procedure.s MidMem(*MainMem, StartPos.l, GetLen.l)
Protected *RetMem,ReturnString.s
If *MainMem = 0 Or GetLen = 0
ProcedureReturn ""
EndIf
*RetMem = AllocateMemory(GetLen)
CopyMemory(*MainMem + StartPos -1, *RetMem, GetLen)
ReturnString = PeekS(*RetMem,GetLen)
FreeMemory(*RetMem)
ProcedureReturn ReturnString
EndProcedure
Define str$,TestString$,Output$,Start1.l,Start2.l,Start3.l,Start4.l,i.l
str$ = "Hello World"
Debug MidMem(@str$, 1, 4)
Debug MidMem(@str$, 8, 2)
Debug MidMem(@str$, 7, 5)
Debug "-----------------"
Debug Mid(str$, 1, 4)
Debug Mid(str$, 8, 2)
Debug Mid(str$, 7, 5)
Debug "-----------------"
Debug MidMemLightning(str$, 1, 4)
Debug MidMemLightning(str$, 8, 2)
Debug MidMemLightning(str$, 7, 5)
DisableDebugger
TestString$ = Space(20000000)
Start1 = ElapsedMilliseconds()
For i = 1 To 100000
Output$ = "!" + Midmem(@TestString$,i*100,10) + "!"
Next
Start2 = ElapsedMilliseconds()
For i = 1 To 10000
Output$ = "!" + Mid(TestString$,i*100,10) + "!"
Next
Start3 = ElapsedMilliseconds()
For i = 1 To 100000
Output$ = "!" + MidMemLightning(TestString$,i*100,10) + "!"
Next
Start4 = ElapsedMilliseconds()
EnableDebugger
MessageRequester("Mid vs MidMem vs MidMemLightning", "Mid() = " + Str(Start3-Start2) + " (10000 rounds only as it's so slow)" + #CRLF$ + "MidMem() = " + Str(Start2-Start1) + " (100000 rounds)" + #CRLF$ + "MidMemLightning() ="+Str(Start4-Start3) + " (100000 rounds)" )
Code: Select all
EnableExplicit
Macro MidMemLightning(string,startpos,length)
PeekS((@string)+((startpos)*SizeOf(Character))-SizeOf(Character),(length))
EndMacro
Structure MemoryArray
Byte.c[0]
word.w[0]
EndStructure
Procedure.l SplitFaster(StringArray.s(1), Text2Split.s, Delim.s) ;return count
Protected FindLen.l,MainLen.l,StringCount.l,*MainByteArray.MemoryArray,FoundPos.l
Protected *FindByteArray.MemoryArray,PrevPos.l,i.l,MainArrayLoop.l,EndSearchPos.l
FindLen = Len(Delim)
MainLen = Len(Text2Split)
Dim StringArray.s(1000)
StringCount = 0
*MainByteArray = @Text2Split ;*MainMem
*FindByteArray = @Delim ;*FindMem
PrevPos = 1
; Build BadChr Array
Dim BadChar.l(255)
; set all alphabet to max shift pos (length of find string plus 1)
For i = 0 To 255
BadChar(i) = FindLen + 1
Next
;Update chars that are in the find string to their position from the end.
For i = 0 To FindLen -1
BadChar(*FindByteArray\byte[i]) = FindLen - i
Next
MainArrayLoop = 1
EndSearchPos = MainLen - (FindLen -1)
While MainArrayLoop <= EndSearchPos
If CompareMemory(@Text2Split + MainArrayLoop, @Delim, FindLen) = 1
FoundPos = MainArrayLoop + 1
If StringCount % 1000 = 0 ; not really needed, doesn't have much of a speed increase. This used to do a lot in the old VB days
ReDim StringArray.s(StringCount + 1000)
EndIf
StringArray(StringCount) = MidMemLightning(Text2Split, Prevpos, Foundpos - PrevPos) ;Mid(Text2Split, Prevpos, Foundpos - PrevPos) ;"HEllo, this is some text" + #TAB$ + " " + #TAB$ + "esdfsdf"
StringCount = StringCount + 1
PrevPos = foundpos + Findlen
EndIf
;Didn't find the string so shift as per the table.
MainArrayLoop + BadChar(*MainByteArray.MemoryArray\byte[MainArrayLoop + FindLen])
Wend
;catch end
ReDim StringArray.s(StringCount)
StringArray(StringCount) = MidMemLightning(Text2Split, Prevpos, MainLen - PrevPos +1)
StringCount = StringCount + 1
ReDim StringArray.s(StringCount)
ProcedureReturn StringCount
EndProcedure
Procedure.l SplitLightning(StringArray.s(1),text$,delimiter$) ;returns stringcount
Protected delimiterlen.l,textlen.l,stringcount.l,stringindex.l=0
Protected *text.Character,*textend,*delimiter.Character,*delimiterend
delimiterlen=Len(delimiter$)
textlen=Len(text$)
If textlen And delimiterlen
stringcount=0
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
stringcount+1
Break
EndIf
Next
Next
If stringcount
Dim StringArray.s(stringcount-1) ;starts at index 0
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))-SizeOf(Character)
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))-SizeOf(Character)
textlen=0
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+SizeOf(Character)
Break
EndIf
Next
textlen+1
Next
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
EndIf
EndIf
ProcedureReturn stringcount
EndProcedure
Procedure.l SplitLightning2(StringArray.s(1),text$,delimiter$) ;returns stringcount
Protected delimiterlen.l,textlen.l,stringcount.l,stringindex.l=0
Protected *text.Character,*textend,*delimiter.Character,*delimiterend
delimiterlen=Len(delimiter$)
textlen=Len(text$)
If textlen And delimiterlen
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))-SizeOf(Character)
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))-SizeOf(Character)
textlen=0
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
ReDim StringArray.s(stringindex+1)
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+SizeOf(Character)
Break
EndIf
Next
textlen+1
Next
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
EndIf
ProcedureReturn stringindex
EndProcedure
Define i.l,n.l,start1.l,start2.l,start3.l,start4.l
Dim StringArray.s(0)
Debug "Split()"
n=SplitFaster(StringArray(),"this,is,a,test,string",",")
If n
For i=0 To n
Debug Str(i)+" = "+StringArray(i)
Next
EndIf
Debug ""
Debug "SplitLightning()"
n=SplitLightning(StringArray(),"this,is-a.test,string",",.-")
If n
n-1
For i=0 To n
Debug Str(i)+" = "+StringArray(i)
Next
EndIf
DisableDebugger
start1=ElapsedMilliseconds()
For i=1 To 100000
n=SplitFaster(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string",",")
Next
start2=ElapsedMilliseconds()
For i=1 To 100000
n=SplitLightning(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string",",")
Next
start3=ElapsedMilliseconds()
For i=1 To 100000
n=SplitLightning2(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string",",")
Next
start4=ElapsedMilliseconds()
EnableDebugger
MessageRequester("Split() vs SplitLightning()", "Split() = " + Str(start2-start1)+#CRLF$+"SplitLightning() = "+Str(start3-start2)+#CRLF$+"SplitLightning2() = "+Str(start4-start3))
Code: Select all
EnableExplicit
Macro MidMemLightning(string,startpos,length)
PeekS((@string)+((startpos)*SizeOf(Character))-SizeOf(Character),(length))
EndMacro
Structure MemoryArray
Byte.c[0]
word.w[0]
EndStructure
Procedure.l SplitFaster(StringArray.s(1), Text2Split.s, Delim.s) ;return count
Protected FindLen.l,MainLen.l,StringCount.l,*MainByteArray.MemoryArray,FoundPos.l
Protected *FindByteArray.MemoryArray,PrevPos.l,i.l,MainArrayLoop.l,EndSearchPos.l
FindLen = Len(Delim)
MainLen = Len(Text2Split)
Dim StringArray.s(1000)
StringCount = 0
*MainByteArray = @Text2Split ;*MainMem
*FindByteArray = @Delim ;*FindMem
PrevPos = 1
; Build BadChr Array
Dim BadChar.l(255)
; set all alphabet to max shift pos (length of find string plus 1)
For i = 0 To 255
BadChar(i) = FindLen + 1
Next
;Update chars that are in the find string to their position from the end.
For i = 0 To FindLen -1
BadChar(*FindByteArray\byte[i]) = FindLen - i
Next
MainArrayLoop = 1
EndSearchPos = MainLen - (FindLen -1)
While MainArrayLoop <= EndSearchPos
If CompareMemory(@Text2Split + MainArrayLoop, @Delim, FindLen) = 1
FoundPos = MainArrayLoop + 1
If StringCount % 1000 = 0 ; not really needed, doesn't have much of a speed increase. This used to do a lot in the old VB days
ReDim StringArray.s(StringCount + 1000)
EndIf
StringArray(StringCount) = MidMemLightning(Text2Split, Prevpos, Foundpos - PrevPos) ;Mid(Text2Split, Prevpos, Foundpos - PrevPos) ;"HEllo, this is some text" + #TAB$ + " " + #TAB$ + "esdfsdf"
StringCount = StringCount + 1
PrevPos = foundpos + Findlen
EndIf
;Didn't find the string so shift as per the table.
MainArrayLoop + BadChar(*MainByteArray.MemoryArray\byte[MainArrayLoop + FindLen])
Wend
;catch end
ReDim StringArray.s(StringCount)
StringArray(StringCount) = MidMemLightning(Text2Split, Prevpos, MainLen - PrevPos +1)
StringCount = StringCount + 1
ReDim StringArray.s(StringCount)
ProcedureReturn StringCount
EndProcedure
;mode 0 (default) supports multi delimiter, where each character is a delimiter
;mode 1 supports a case sensitive string delimiter, where the delimiter is treated as a full string
;mode 2 supports a case insensitive string delimiter, where the delimiter is treated as a full string
Procedure.l SplitLightning(StringArray.s(1),text$,delimiter$,mode.l=0) ;returns stringcount
Protected delimiterlen.l,textlen.l,stringcount.l,stringindex.l=0,casesensitive.l=0
Protected *text.Character,*textend,*delimiter.Character,*delimiterend
delimiterlen=Len(delimiter$)
textlen=Len(text$)
If textlen And delimiterlen
stringcount=0
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))
If mode=0
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
stringcount+1
*text+SizeOf(Character)
Break
EndIf
Next
Next
ElseIf (mode=1) Or (mode=2)
If mode=2 : casesensitive=1 : EndIf
If delimiterlen>textlen : delimiterlen=textlen : EndIf
For *text=@text$ To *textend Step SizeOf(Character)
If Not CompareMemoryString(*text,@delimiter$,casesensitive,delimiterlen)
stringcount+1
*text+(delimiterlen*SizeOf(Character))
EndIf
Next
EndIf
If stringcount
If mode<>0
stringcount+1
EndIf
Dim StringArray.s(stringcount-1) ;starts at index 0
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))-SizeOf(Character)
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))-SizeOf(Character)
textlen=0
If mode=0
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+SizeOf(Character)
Break
EndIf
Next
textlen+1
Next
Else
For *text=@text$ To *textend Step SizeOf(Character)
If Not CompareMemoryString(*text,@delimiter$,casesensitive,delimiterlen)
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+(delimiterlen*SizeOf(Character))
EndIf
textlen+1
Next
EndIf
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
EndIf
EndIf
ProcedureReturn stringcount
EndProcedure
;mode 0 (default) supports multi delimiter, where each character is a delimiter
;mode 1 supports a case sensitive string delimiter, where the delimiter is treated as a full string
;mode 2 supports a case insensitive string delimiter, where the delimiter is treated as a full string
Procedure.l SplitLightning2(StringArray.s(1),text$,delimiter$,mode.l=0) ;returns stringcount
Protected delimiterlen.l,textlen.l,stringcount.l,stringindex.l=0,casesensitive.l=0
Protected *text.Character,*textend,*delimiter.Character,*delimiterend
delimiterlen=Len(delimiter$)
textlen=Len(text$)
If textlen And delimiterlen
*text=@text$
*textend=@text$+(textlen*SizeOf(Character))-SizeOf(Character)
*delimiterend=@delimiter$+(delimiterlen*SizeOf(Character))-SizeOf(Character)
If mode=0
textlen=0
For *text=@text$ To *textend Step SizeOf(Character)
For *delimiter=@delimiter$ To *delimiterend Step SizeOf(Character)
If *text\c=*delimiter\c
ReDim StringArray.s(stringindex+1)
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+SizeOf(Character)
Break
EndIf
Next
textlen+1
Next
Else
If mode=2 : casesensitive=0 : EndIf
If delimiterlen>textlen : delimiterlen=textlen : EndIf
textlen=0
For *text=@text$ To *textend Step SizeOf(Character)
If Not CompareMemoryString(*text,@delimiter$,casesensitive,delimiterlen)
ReDim StringArray.s(stringindex+1)
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
textlen=0
*text+(delimiterlen*SizeOf(Character))
EndIf
textlen+1
Next
EndIf
If stringindex
StringArray(stringindex)=PeekS(*text-(textlen*SizeOf(Character)),textlen)
stringindex+1
EndIf
EndIf
ProcedureReturn stringindex
EndProcedure
Define i.l,n.l,start1.l,start2.l,start3.l,start4.l
Dim StringArray.s(0)
Debug "Split()"
n=SplitFaster(StringArray(),"this,is,a,test,string,this,is,a,test,string","string")
If n
For i=0 To n
Debug Str(i)+" = "+StringArray(i)
Next
EndIf
Debug ""
Debug "SplitLightning()"
n=SplitLightning(StringArray(),"this,is,a,test,string,this,is,a,test,string","string",1)
If n
n-1
For i=0 To n
Debug Str(i)+" = "+StringArray(i)
Next
EndIf
DisableDebugger
start1=ElapsedMilliseconds()
For i=1 To 100000
n=SplitFaster(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string","string")
Next
start2=ElapsedMilliseconds()
For i=1 To 100000
n=SplitLightning(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string","string",1)
Next
start3=ElapsedMilliseconds()
For i=1 To 100000
n=SplitLightning2(StringArray(),"this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string,this,is,a,test,string","string",1)
Next
start4=ElapsedMilliseconds()
EnableDebugger
MessageRequester("Split() vs SplitLightning()", "Split() = " + Str(start2-start1)+#CRLF$+"SplitLightning() = "+Str(start3-start2)+#CRLF$+"SplitLightning2() = "+Str(start4-start3))