FindMemory() FindMemoryString()

Share your advanced PureBasic knowledge/code with the community.
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

FindMemory() FindMemoryString()

Post by infratec »

I thought here is a better place to publish it.
It is not assembler optimized, but it is flexible and cross platform.
FindMemoryString() is only for unicode strings, but it is twice faster, since the memory step is 2 and not 1. :wink:

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
  
  DisableDebugger
CompilerEndIf


Procedure.i FindMemory(*Memory, *ToFind.Ascii, FindFromEnd.i=#False, MemoryLength.i=0, ToFindLength.i=0, ReturnOffset.i=#False, *StartPtr.Ascii=#Null)
  
  Protected.i ByteLength, Result
  Protected *MemoryEnd, *Ptr.Ascii, *FoundPtr, *Ptr2.Ascii, *ToFindTmp.Ascii, *ToFindEnd
  
  
  If ToFindLength = 0
    ByteLength = MemorySize(*ToFind)
  Else
    ByteLength = ToFindLength
  EndIf
  
  *ToFindTmp = *ToFind
  *ToFindEnd = *ToFind + ByteLength
  
  If FindFromEnd
    
    If *StartPtr
      *Ptr = *StartPtr - ByteLength
    Else
      *Ptr = *Memory + MemorySize(*Memory) - ByteLength
    EndIf
    
    Repeat
      
      If *Ptr\a = *ToFindTmp\a
        *Ptr2 = *Ptr + 1
        *ToFindTmp + 1
        While *Ptr2\a = *ToFindTmp\a
          *Ptr2 + 1
          *ToFindTmp + 1
          If *ToFindTmp = *ToFindEnd
            *FoundPtr = *Ptr
            Break 2
          EndIf
        Wend
        *ToFindTmp = *ToFind
      EndIf
      
      *Ptr - 1
    Until *Ptr <= *Memory
    
  Else
    
    *MemoryEnd = *Memory + MemorySize(*Memory) - ByteLength
    
    If *StartPtr
      If *StartPtr\a = *ToFind\a
        *Ptr = *StartPtr + 1
      Else
        *Ptr = *StartPtr
      EndIf
    Else
      *Ptr = *Memory
    EndIf
    
    Repeat
      
      If *Ptr\a = *ToFindTmp\a
        *Ptr2 = *Ptr + 1
        *ToFindTmp + 1
        While *Ptr2\a = *ToFindTmp\a
          *Ptr2 + 1
          *ToFindTmp + 1
          If *ToFindTmp = *ToFindEnd
            *FoundPtr = *Ptr
            Break 2
          EndIf
        Wend
        *ToFindTmp = *ToFind
      EndIf
      
      *Ptr + 1
    Until *Ptr >= *MemoryEnd
    
  EndIf
  
  If ReturnOffset
    Result = *FoundPtr - *Memory
  Else
    Result = *FoundPtr
  EndIf
  
  ProcedureReturn Result
  
EndProcedure



Procedure.i FindMemoryString(*Memory, String$, FindFromEnd.i=#False, ReturnOffset.i=#False, *StartPtr.Character=#Null)
  
  Protected.i StringByteLength, Result
  Protected *MemoryEnd, *Ptr.Character, *FoundPtr, *Ptr2.Character, *String.Character
  
  
  StringByteLength = StringByteLength(String$)
  *String = @String$
  
  If FindFromEnd
    
    If *StartPtr
      *Ptr = *StartPtr - StringByteLength
    Else
      *Ptr = *Memory + MemorySize(*Memory) - StringByteLength
    EndIf
    
    Repeat
      
      If *Ptr\c = *String\c
        *Ptr2 = *Ptr + 2
        *String + 2
        While *Ptr2\c = *String\c
          *Ptr2 + 2
          *String + 2
        Wend
        If *String\c = #Null
          *FoundPtr = *Ptr
          Break
        EndIf
        *String = @String$
      EndIf
      
      *Ptr - 2
    Until *Ptr <= *Memory
    
  Else
    
    *MemoryEnd = *Memory + MemorySize(*Memory) - StringByteLength
    
    If *StartPtr
      If *StartPtr\c = *String\c
        *Ptr = *StartPtr + 2
      Else
        *Ptr = *StartPtr
      EndIf
    Else
      *Ptr = *Memory
    EndIf
    
    Repeat
      
      If *Ptr\c = *String\c
        *Ptr2 = *Ptr + 2
        *String + 2
        While *Ptr2\c = *String\c
          *Ptr2 + 2
          *String + 2
        Wend
        If *String\c = #Null
          *FoundPtr = *Ptr
          Break
        EndIf
        *String = @String$
      EndIf
      
      *Ptr + 2
    Until *Ptr >= *MemoryEnd
    
  EndIf
  
  If ReturnOffset
    Result = *FoundPtr - *Memory
  Else
    Result = *FoundPtr
  EndIf
  
  ProcedureReturn Result
  
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  
  Define.q StartTime, EndTime, Summ
  Define HW$, Result$
  Define *Memory, *Here, *HW
  
  
  HW$ = "Hello World of "
  *Memory = AllocateMemory(50 * 1024 * 1024)  ; 50MB
  If *Memory
    PokeS(*Memory + 18205400, HW$ + "Europe !")
    PokeS(*Memory + 26055450, HW$ + "America!")
    PokeS(*Memory + 36750820, HW$ + "Asia   !")
    PokeS(*Memory + 39046460, HW$ + "Africa !")
    PokeS(*Memory + 46750820, HW$ + "Oceania!")
    
    Result$ = "Forward string search:" + #LF$
    Repeat
      StartTime = ElapsedMilliseconds()
      *Here = FindMemoryString(*Memory, HW$, #False, #False, *Here)
      EndTime = ElapsedMilliseconds()
      If *Here
        Result$ + PeekS(*Here + StringByteLength(HW$), 7) + " in " + Str(EndTime - StartTime) + "ms" + #LF$
        Summ + (EndTime - StartTime)
      EndIf
    Until Not *Here
    Result$ + "Summ: " + Str(Summ) + "ms" + #LF$
    
    
    Result$ + #LF$ + "Reverse string search:" + #LF$
    
    *Here = #Null
    Summ = 0
    Repeat
      StartTime = ElapsedMilliseconds()
      *Here = FindMemoryString(*Memory, HW$, #True, #False, *Here)
      EndTime = ElapsedMilliseconds()
      If *Here
        Result$ + PeekS(*Here + StringByteLength(HW$), 7) + " in " + Str(EndTime - StartTime) + "ms" + #LF$
        Summ + (EndTime - StartTime)
      EndIf
    Until Not *Here
    Result$ + "Summ: " + Str(Summ) + "ms" + #LF$
    
    FreeMemory(*Memory)
  EndIf
  
  
  *HW = UTF8(HW$)
  If *HW
    *Memory = AllocateMemory(50 * 1024 * 1024)  ; 50MB
    If *Memory
      PokeS(*Memory + 18205400, HW$ + "Europe !", -1, #PB_UTF8|#PB_String_NoZero)
      PokeS(*Memory + 26055450, HW$ + "America!", -1, #PB_UTF8|#PB_String_NoZero)
      PokeS(*Memory + 36750820, HW$ + "Asia   !", -1, #PB_UTF8|#PB_String_NoZero)
      PokeS(*Memory + 39046460, HW$ + "Africa !", -1, #PB_UTF8|#PB_String_NoZero)
      PokeS(*Memory + 46750820, HW$ + "Oceania!", -1, #PB_UTF8|#PB_String_NoZero)
      
      Result$ + #LF$ + "Forward byte search:" + #LF$
      
      Repeat
        StartTime = ElapsedMilliseconds()
        *Here = FindMemory(*Memory, *HW, #False, 0, MemorySize(*HW) - 1, #False, *Here)
        EndTime = ElapsedMilliseconds()
        If *Here
          Result$ + PeekS(*Here + MemorySize(*HW) - 1, 7, #PB_UTF8) + " in " + Str(EndTime - StartTime) + "ms" + #LF$
          Summ + (EndTime - StartTime)
        EndIf
      Until Not *Here
      Result$ + "Summ: " + Str(Summ) + "ms" + #LF$
      
      
      Result$ + #LF$ + "Reverse byte search:" + #LF$
      
      *Here = #Null
      Summ = 0
      Repeat
        StartTime = ElapsedMilliseconds()
        *Here = FindMemory(*Memory, *HW, #True, 0, MemorySize(*HW) - 1, #False, *Here)
        EndTime = ElapsedMilliseconds()
        If *Here
          Result$ + PeekS(*Here + MemorySize(*HW) - 1, 7, #PB_UTF8) + " in " + Str(EndTime - StartTime) + "ms" + #LF$
          Summ + (EndTime - StartTime)
        EndIf
      Until Not *Here
      Result$ + "Summ: " + Str(Summ) + "ms" + #LF$
      
      FreeMemory(*Memory)
    EndIf
    FreeMemory(*HW)
  EndIf
  
  
  EnableDebugger
  
  Debug Result$
  
CompilerEndIf
User avatar
idle
Always Here
Always Here
Posts: 5095
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: FindMemory() FindMemoryString()

Post by idle »

very useful and quick
User avatar
skywalk
Addict
Addict
Posts: 3999
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: FindMemory() FindMemoryString()

Post by skywalk »

This is the 1st Easter egg for my basket.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply