The following is CLOSER TO perfect :3 (comparing with previous dirty version).
You can easily change that code to be thread-safe, or pack it into module, and so on with what is needed
Code: Select all
EnableExplicit
;{ StrFastConcat }
; v 1.0.0.5
; 2017 (c) Luna Sole
Structure STRFASTOBJ
*Data
EndStructure
; Starts new concatenation. Lot of them may exists and be threaded
; RETURN: strfast object on success
Procedure StrFastNew()
Protected *StrFast.STRFASTOBJ = AllocateStructure(STRFASTOBJ)
If *StrFast
*StrFast\Data = AllocateMemory(4 + 10240*SizeOf(Character))
If *StrFast\Data
PokeL(*StrFast\Data, 0) ; bytes 1-4 storing current len (chars)
ProcedureReturn *StrFast
Else
FreeStructure(*StrFast)
EndIf
EndIf
EndProcedure
; Concatenate strings quite optimized way
; *String pointer to a string
; Len *String len (chars). If set, len is not calculated here, which brings some more speed in some cases
; RETURN: none
Procedure StrFastAddEx (*StrFast.STRFASTOBJ, *String, Len = 0)
Protected NewLenB, *FastLen.Long
If *StrFast
If Len <= 0
Len = MemoryStringLength(*String)
EndIf
If Len
*FastLen = *StrFast\Data
NewLenB = (*FastLen\l + Len)*SizeOf(Character)
If NewLenB > (MemorySize(*StrFast\Data)-4)
; every time buffer size is set to required size*2. that GREATLY raises both memory overhead and speed, comparing to use of small/medium fixed step
; idea stolen from @Karig variant ^^
*StrFast\Data = ReAllocateMemory(*StrFast\Data, 4 + NewLenB*1.28, #PB_Memory_NoClear)
*FastLen = *StrFast\Data
EndIf
CopyMemory(*String, *StrFast\Data+4 + *FastLen\l*SizeOf(Character), Len*SizeOf(Character))
*FastLen\l + Len
EndIf
EndIf
EndProcedure
; Wrapper for a cases where pointer is not applicable.
; It is much slower than StrFastAddEx(), but only comparing to it. Itself is still very fast.
; String$ a string to add
; Len String$ len (chars). If set, len is not calculated here, which brings some more speed in some cases
; RETURN: none
Procedure StrFastAdd(*StrFast.STRFASTOBJ, String$, Len = 0)
StrFastAddEx(*StrFast, @String$, Len)
EndProcedure
; Returns concatenated string
; RETURN: string
Procedure$ StrFastGet(*StrFast.STRFASTOBJ)
If *StrFast
ProcedureReturn PeekS(*StrFast\Data+4, PeekL(*StrFast\Data))
EndIf
EndProcedure
; Release specified fast string
; RETURN: none
Procedure StrFastFree(*StrFast.STRFASTOBJ)
If *StrFast
FreeMemory(*StrFast\Data)
FreeStructure(*StrFast)
EndIf
EndProcedure
;}
;;; Example
; Allocate this fast stuff
Define FS = StrFastNew()
; 1) Typical usage
StrFastAdd(FS, "test ")
; 2) Sometime this is faster, when is reasonable
StrFastAdd(FS, "this ", 5)
; 3) Using pointer + fixed len, fastest option here
StrFastAddEx(FS, @"ssst++", 4)
; Get Result & Release
Debug StrFastGet(FS)
StrFastFree(FS)