CopyMemoryString() Number of bytes to copy

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

CopyMemoryString() Number of bytes to copy

Post by Oso »

For working with fixed-size blocks of data, it would be useful to be able to use CopyMemoryString() with specified maximum number of bytes. We can instead use CopyMemory() which provides a size parameter, but it doesn't stop on null termination. Without a maximum, the example copies the 58-byte input to the 10-byte output. This addition would be very useful as it is likely to be faster than working directly with strings.

Code: Select all

*InputB  = AllocateMemory(1000)
PokeS(*InputB, "Long input stream of data is longer than the output buffer", -1, #PB_Ascii)

*Output = AllocateMemory(10)                      ; Output block size limited to 10 bytes
*OutPtr = *Output

CopyMemoryString(*InputB, @*OutPtr)               ; Copy *InputB contents to 10-byte output block
ShowMemoryViewer(*Output,100)
A workaround is to temporarily set the null. Incidentally, it is necessary to set the double unicode null.

Code: Select all

PokeS(*InputB + 10, #Null$, -1)
https://www.purebasic.com/documentation ... tring.html
User avatar
Mijikai
Addict
Addict
Posts: 1517
Joined: Sun Sep 11, 2016 2:17 pm

Re: CopyMemoryString() Number of bytes to copy

Post by Mijikai »

Maybe:

Code: Select all

EnableExplicit

Procedure.i CopyString(*Src,*Dst,Size.i,Unicode.i)
  !mov rsi,[p.p_Src]
  !mov rdi,[p.p_Dst]
  !mov rcx,[p.v_Size]
  !cmp qword[p.v_Unicode],0
  !jne @f
  !dec rcx
  !cld
  !rep movsb
  !mov byte[rdi],0
  !xor rax,rax
  ProcedureReturn
  !@@:
  !shr rcx,1;<- assumes size is a multiple of 2
  !dec rcx
  !cld
  !rep movsw
  !mov word[rdi],0
  !xor rax,rax
  ProcedureReturn
EndProcedure

Procedure.i Main()
  Protected *in
  Protected *out
  *in = AllocateMemory(1000)
  PokeS(*in, "Long input stream of data is longer than the output buffer", -1, #PB_Ascii)
  *out = AllocateMemory(10)
  CopyString(*in,*out,10,#False)
  ShowMemoryViewer(*out,10)
EndProcedure

Main()

End
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: CopyMemoryString() Number of bytes to copy

Post by Oso »

Mijikai wrote: Mon Dec 19, 2022 12:53 pm Maybe:

Code: Select all

  CopyString(*in,*out,10,#False)
It works very well Mijikai, thanks. It's fast too, despite the overhead of needing to count the bytes. The only problem is that I don't follow Assembler, beyond a very foggy level of understanding, so adding it to code that I need to support would be a bit of an unknown to me :D
User avatar
Mijikai
Addict
Addict
Posts: 1517
Joined: Sun Sep 11, 2016 2:17 pm

Re: CopyMemoryString() Number of bytes to copy

Post by Mijikai »

Without fasm:

Code: Select all

Macro CopyString(_src_,_dst_,_siz_,_type_);<- size in bytes
  FillMemory(_dst_,_siz_)
  CopyMemory(_src_,_dst_,_siz_ - (1 + Bool(_type_ = #PB_Unicode)))
EndMacro
User avatar
mk-soft
Always Here
Always Here
Posts: 6209
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: CopyMemoryString() Number of bytes to copy

Post by mk-soft »

That is not what was meant. I also read it wrong at first.

The point is that CopyMemoryString is not written over the available memory.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Mijikai
Addict
Addict
Posts: 1517
Joined: Sun Sep 11, 2016 2:17 pm

Re: CopyMemoryString() Number of bytes to copy

Post by Mijikai »

Hmm...

This also takes into account the string size (the function returns how many characters where written to memory):

Code: Select all

;Limit = size of memory in bytes
Procedure.i CopyString(*Source.Unicode,*Destination.Unicode,Limit.i);Unicode only!
  Protected copied.i
  If Limit > 2
    Limit - 2
    copied = Limit
    Repeat
      *Destination\u = *Source\u
      *Source + 2
      *Destination + 2
      Limit - 2
    Until Limit = 0 Or *Source\u = 0
    If *Source\u <> 0
      *Destination\u = 0
    EndIf
    ProcedureReturn (copied - Limit) >> 1
  EndIf
  ProcedureReturn #Null
EndProcedure
User avatar
mk-soft
Always Here
Always Here
Posts: 6209
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: CopyMemoryString() Number of bytes to copy

Post by mk-soft »

Copy String to Memory with limit and output format

Update

Code: Select all


Procedure CopyMemoryStringEx(String.s, *DestinationMemory.Integer, *BaseMemory, BaseSize = 0, Format = #PB_Unicode)
  Protected len, len2, MaxSize
  
  If Not *DestinationMemory Or Not *BaseMemory
    ProcedureReturn 0
  EndIf
    
  If Not *DestinationMemory\i
    *DestinationMemory\i = *BaseMemory
  EndIf
  
  If Not BaseSize
    BaseSize = MemorySize(*BaseMemory)
  EndIf
  
  MaxSize = *BaseMemory + BaseSize - *DestinationMemory\i
  len = Len(String)
  len2 = StringByteLength(String, Format)
  If Format = #PB_Unicode
    MaxSize - 2
    If len2 > MaxSize
      len = MaxSize / 2
      len2 = MaxSize
    EndIf
  Else
    MaxSize - 1
    If len2 > MaxSize
      len = MaxSize
      len2 = MaxSize
    EndIf
  EndIf
  If len > 0
    PokeS(*DestinationMemory\i, String, len, Format)
    *DestinationMemory\i + len2
    ProcedureReturn len2
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

InputB.s = "Long input stream of Data is longer than the output buffer"

Define *Output = AllocateMemory(50) 
Define *OutPtr

cnt = CopyMemoryStringEx("Start:", @*OutPtr, *Output, MemorySize(*Output), #PB_Ascii)
Debug cnt
cnt = CopyMemoryStringEx(InputB, @*OutPtr, *Output, MemorySize(*Output), #PB_Ascii)
Debug cnt 
cnt = CopyMemoryStringEx(":End", @*OutPtr, *Output, MemorySize(*Output), #PB_Ascii)
Debug cnt
ShowMemoryViewer(*Output,100)
Last edited by mk-soft on Mon Dec 19, 2022 8:21 pm, edited 2 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: CopyMemoryString() Number of bytes to copy

Post by Oso »

mk-soft wrote: Mon Dec 19, 2022 4:33 pm That is not what was meant. I also read it wrong at first. The point is that CopyMemoryString is not written over the available memory.
Yes, that's more or less it. CopyMemoryString doesn't provide any control over attempting to copy the longer string into a shorter memory buffer, such as when putting data into a fixed-sized blocks. There's a subtle requirement here, which is that it should still terminate on null (which it already does), but also provide a size parameter, which so many of the the other 'Memory' functions already provide (please see list below). CopyMemory is okay to a point, but it doesn't terminate on nulls.

I wrote my code using PokeS() from the start, but I'm just aware that it isn't as fast as direct memory copying. So this is just a feature suggestion. Out of interest, from the list of 'Memory' functions, nine of them already provide a 'Size' parameter, but CopyMemoryString is the exception that doesn't provide it. Even its very close cousin CompareMemoryString() has a size parameter. Below is the list where 'Size' is provided already. I know some of them are obvious because Size is necessary for them, but it's just useful to have an idea of those where the size has been provided...

Code: Select all

AllocateMemory()
CompareMemory()
CompareMemoryString()
CopyMemory()
FillMemory()
MoveMemory()
PeekS()
PokeS()
ReAllocateMemory()
User avatar
mk-soft
Always Here
Always Here
Posts: 6209
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: CopyMemoryString() Number of bytes to copy

Post by mk-soft »

Update
I have reworked it a bit.
Should work like this with zero byte at the end and memory limitation.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Re: CopyMemoryString() Number of bytes to copy

Post by AZJIO »

Oso wrote: Mon Dec 19, 2022 7:58 pm already provide a 'Size' parameter, but CopyMemoryString is the exception that doesn't provide it.
I think that each function is made for a specific task. If you allocate memory that will fit 1000 lines, then you can simply copy the lines each time to the end of the previously copied line. That is, you concatenate a list or array into one long string to save it to a file. And it works great.
As you can understand from the current situation, the CopyMemoryString function does not check the size where it copies. Before copying, your task is to calculate the size of all elements that will be inserted into a certain allocated memory pointer. More precisely, you must calculate in advance the sizes of all copied strings and allocate memory in which they will fit. The second parameter is a pointer to a pointer. This suggests that the function is useful when you repeatedly copy, that is, the function was created for this, since it moves the pointer to the end of the copied string.
Post Reply