Page 1 of 1

FindMemory() FindMemoryString()

Posted: Sat Mar 30, 2024 11:19 pm
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

Re: FindMemory() FindMemoryString()

Posted: Sun Mar 31, 2024 3:28 am
by idle
very useful and quick

Re: FindMemory() FindMemoryString()

Posted: Sun Mar 31, 2024 7:14 pm
by skywalk
This is the 1st Easter egg for my basket.

Re: FindMemory() FindMemoryString()

Posted: Mon May 13, 2024 6:52 pm
by Kwai chang caine
Works nice here
Thanks for this precious code 8)

Re: FindMemory() FindMemoryString()

Posted: Mon May 13, 2024 8:22 pm
by STARGĂ…TE
I didn't noticed this code before, but now I wonder about some parts of this code:
FindMemory() has an argument MemoryLength which is never used in the procedure.
I guess, it should replace MemorySize(*Memory) when it is passed.