It is currently Tue Jan 19, 2021 9:24 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Stringbuilder
PostPosted: Fri Jan 24, 2014 5:39 pm 
Offline
Enthusiast
Enthusiast

Joined: Wed May 07, 2003 1:45 am
Posts: 102
Location: Germany
Hi,

I'm trying to write my own stringbuilder routine but it won't work as it should. The resulting string differs from the input (I guess while copying it with CopyMemory to the string buffer). Still, I can't figure out why...

Here's the code:
Code:
Structure _structStringManagement
  iBlockSize.i        ; minimum bytes we allocate if we need more space to add a string to the buffer
  iBufferSize.i       ; total memory size we've allocated
  iPositionInBuffer.i ; actual position in the buffer
  iBufferAddress.i    ; address of the buffer (aka allocated memory)
  iInitDone.i         ; true if the string builder has been initilized (memory was reserved)
EndStructure

Procedure _sbInit(iBlocksize.i)
 
  Global _StringBuffer._structStringManagement
 
  With _StringBuffer
    \iBlockSize   = 1024
    \iBufferAddress = AllocateMemory(iBlocksize)
    If \iBufferAddress
      \iInitDone = #True
    EndIf
  EndWith
 
EndProcedure

Procedure.i _sbAddString(sString.s)
  ; --- adds a new string to the buffer
 
  Protected iStringAddress.i
  Protected iStringLength.i
  Protected iNewStringSize.i
  Protected iNewStringBufferAddress.i
 
  iStringAddress = @sString
  iStringLength = MemoryStringLength(iStringAddress, #PB_Unicode)
 
  With _StringBuffer
    iNewStringSize = iStringLength + \iPositionInBuffer

   If iNewStringSize + 1 > \iBlockSize
     
      iNewStringBufferAddress = AllocateMemory(\iBufferSize + \iBlockSize)
      If iNewStringSize
        CopyMemory(\iBufferAddress, iNewStringBufferAddress, \iPositionInBuffer)
        FreeMemory(\iBufferAddress)
        \iBufferAddress = iNewStringBufferAddress
        \iBufferSize    = \iBufferSize + \iBlockSize
      Else
        ProcedureReturn #False
      EndIf
    EndIf
   
    CopyMemory(iStringAddress, \iBufferAddress + \iPositionInBuffer, iStringLength * 2)
       
    \iPositionInBuffer + iStringLength
   
    Debug "string length  = " + iStringLength
    Debug "string4buffer  = " + PeekS(iStringAddress)
    Debug "buffer (ascii) = " + PeekS(\iBufferAddress, -1, #PB_Ascii)
    Debug "buffer (uni)   = " + PeekS(\iBufferAddress, -1, #PB_Unicode)
    Debug "buffer (utf-8) = " + PeekS(\iBufferAddress, -1, #PB_UTF8)
    Debug "buffer (def)   = " + PeekS(\iBufferAddress)
    Debug "bufferpos      = " + \iPositionInBuffer
    Debug ""
  EndWith
 
EndProcedure

_sbInit(4096)

For iCounter = 1 To 100
  _sbAddString(Str(iCounter))
  _sbAddString(" , ")
  _sbAddString(" 123 #'+~")
Next

Debug _sbGetString()

Any idea, where the problem hides??

Greetz,
Fenix


Top
 Profile  
Reply with quote  
 Post subject: Re: Stringbuilder
PostPosted: Fri Jan 24, 2014 8:19 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 3767
Location: Utah, USA
Fenix wrote:
Any idea, where the problem hides??


There seems to be a few areas of concern. But first, is this supposed to be compiled in ASCII or Unicode? I'm guessing it's Unicode.

Second, there is no '_sbGetString()' procedure defined so it is not quite clear what is different in the output compared to the input.


Assuming it is to be compiled in unicode, here is a list of the errors I found:
Code:
;line 35, iPositionInBuffer is in bytes, iStringLength is in characters (2 bytes for unicode)
    iNewStringSize = iStringLength + \iPositionInBuffer

;line 37 ;iNewStringSize would actually be the filled buffersize in bytes, after iBlockSize is reached this will always trigger
    If iNewStringSize + 1 > \iBlockSize
 
;line 39, iNewStringSize may be larger by more than one iBlockSize (use \iNewStringSize instead of \BufferSize), use ReAllocateMemory()
      iNewStringBufferAddress = AllocateMemory(\iBufferSize + \iBlockSize)

;line 40, this should be testing iNewStringBufferAddress
      If iNewStringSize

;line 52, iPositionInBuffer is in bytes, iStringLength is in characters (2 bytes for unicode)
    \iPositionInBuffer + iStringLength


The code with corrections made:
Code:
Structure _structStringManagement
  iBlockSize.i        ; minimum bytes we allocate if we need more space to add a string to the buffer
  iBufferSize.i       ; total memory size we've allocated
  iPositionInBuffer.i ; actual position in the buffer
  iBufferAddress.i    ; address of the buffer (aka allocated memory)
  iInitDone.i         ; true if the string builder has been initilized (memory was reserved)
EndStructure

Procedure _sbInit(iBlocksize.i)
 
  Global _StringBuffer._structStringManagement
 
  With _StringBuffer
    \iBlockSize   = 1024
    \iBufferAddress = AllocateMemory(iBlocksize)
    If \iBufferAddress
      \iInitDone = #True
    EndIf
  EndWith
 
EndProcedure

Procedure.i _sbAddString(sString.s)
  ; --- adds a new string to the buffer
 
  Protected iStringAddress.i
  Protected iStringLength.i
  Protected iNewStringSize.i
  Protected iNewStringBufferAddress.i
 
  iStringAddress = @sString
  iStringLength = MemoryStringLength(iStringAddress, #PB_Unicode)
 
  With _StringBuffer
    iNewStringSize = iStringLength * 2 + \iPositionInBuffer

    If iNewStringSize + 1 - \iBufferSize > \iBlockSize
     
      iNewStringBufferAddress = ReAllocateMemory(\iBufferAddress, iNewStringSize + \iBlockSize)
      If iNewStringBufferAddress
        ;CopyMemory(\iBufferAddress, iNewStringBufferAddress, \iPositionInBuffer)  ;already performed by ReAllocateMemory()
        ;FreeMemory(\iBufferAddress)                                               ;already performed by ReAllocateMemory()
        \iBufferAddress = iNewStringBufferAddress
        \iBufferSize    = MemorySize(\iBufferAddress)
      Else
        ProcedureReturn #False
      EndIf
    EndIf
   
    CopyMemory(iStringAddress, \iBufferAddress + \iPositionInBuffer, iStringLength * 2)
       
    \iPositionInBuffer + iStringLength * 2
   
    Debug "string length  = " + iStringLength
    Debug "string4buffer  = " + PeekS(iStringAddress)
    ;Debug "buffer (ascii) = " + PeekS(\iBufferAddress, -1, #PB_Ascii)    ;data is in unicode not ASCII
    Debug "buffer (uni)   = " + PeekS(\iBufferAddress, -1, #PB_Unicode)
    ;Debug "buffer (utf-8) = " + PeekS(\iBufferAddress, -1, #PB_UTF8)     ;data is in unicode not UTF8
    Debug "buffer (def)   = " + PeekS(\iBufferAddress)
    Debug "bufferpos      = " + \iPositionInBuffer
    Debug ""
  EndWith
 
EndProcedure

_sbInit(4096)

For iCounter = 1 To 100
  _sbAddString(Str(iCounter))
  _sbAddString(" , ")
  _sbAddString(" 123 #'+~")
Next

;Debug _sbGetString()    ;undefined in code

_________________
Image


Top
 Profile  
Reply with quote  
 Post subject: Re: Stringbuilder
PostPosted: Fri Jan 24, 2014 9:46 pm 
Offline
Enthusiast
Enthusiast

Joined: Wed May 07, 2003 1:45 am
Posts: 102
Location: Germany
Demivec wrote:
Fenix wrote:
Any idea, where the problem hides??


There seems to be a few areas of concern. But first, is this supposed to be compiled in ASCII or Unicode? I'm guessing it's Unicode.

Indeed it's compiled in unicode mode. I forgot to mention that.

Demivec wrote:
Second, there is no '_sbGetString()' procedure defined so it is not quite clear what is different in the output compared to the input.

Forgot to copy that procedure. It's just
Code:
ProcedureReturn PeekS(_StringBuffer\iBufferAddress)

I totally got the MemoryStringLength() wrong. Thought it would return the total number of bytes, so for unicode twice the character count :oops: Didn't see that, guess I was staring at the code for too long :lol:

Line 39: You're right, a string could be larger than 1024 bytes. Didn't implement a checking here as I know the strings I'm using in the actual program are limited in size and far less then 1kb. But I keep that in mind for other projects.

Many thanks to you!!

Greetz,
Fenix


Top
 Profile  
Reply with quote  
 Post subject: Re: Stringbuilder
PostPosted: Sat Jan 25, 2014 1:51 am 
Offline
Always Here
Always Here

Joined: Fri Oct 23, 2009 2:33 am
Posts: 6271
Location: Wales, UK
Consider using StringByteLength(), it's much easier.

_________________
IdeasVacuum
If it sounds simple, you have not grasped the complexity.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 59 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye