Page 1 of 1
CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 8:26 am
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.
https://www.purebasic.com/documentation ... tring.html
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 12:53 pm
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
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 3:00 pm
by Oso
Mijikai wrote: Mon Dec 19, 2022 12:53 pm
Maybe:
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

Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 3:43 pm
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
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 4:33 pm
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.
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 6:39 pm
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
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 7:52 pm
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)
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 7:58 pm
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()
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 8:23 pm
by mk-soft
Update
I have reworked it a bit.
Should work like this with zero byte at the end and memory limitation.
Re: CopyMemoryString() Number of bytes to copy
Posted: Mon Dec 19, 2022 9:43 pm
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.