StringBuffer

Share your advanced PureBasic knowledge/code with the community.
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

StringBuffer

Post by pcfreak »

just see for yourself :P

Code: Select all

DisableDebugger 

Interface IStringBuffer
 add.i(String$)
 addC.i(Character.c)
 addUniC.i(Character.w)
 clear.i()
 get.s()
 getMem.i()
 copyToMem.i(*mem)
 length.i()
 ;free object
 delete()
EndInterface


Structure StringBufferElement
 *next.StringBufferElement
 *buffer
EndStructure


Structure OStringBuffer
 ;Address to the methods array
 methodAddress.i
 ;Class Attributes
 bufferSize.i
 bufferOffset.i
 *bufferList.StringBufferElement
 *lastBuffer.StringBufferElement
 length.i
EndStructure


Procedure.i StringBuffer_add(*this.IStringBuffer, String$)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object.OStringBuffer = *this
 *buffer.StringBufferElement = *object\lastBuffer
 *in.CHARACTER = @String$
 stringSize.i = StringByteLength(String$)
 While *in - @String$ < stringSize
  If *object\bufferSize <= *object\bufferOffset
   *object\bufferOffset = 0
   *newBuffer = #Null
   While *newBuffer = #Null
    *newBuffer = AllocateMemory(*object\bufferSize)
   Wend
   *newBufferElement = #Null
   While *newBufferElement = #Null
    *newBufferElement = AllocateMemory(*object\bufferSize)
   Wend
   *buffer\next = *newBufferElement
   *buffer = *buffer\next
   *buffer\buffer = *newBuffer
   *object\lastBuffer = *buffer
  EndIf
  *out.WORD = *buffer\buffer + *object\bufferOffset
  *out\w = *in\c
  *object\bufferOffset + 2
  *in + SizeOf(CHARACTER)
  *object\length + 1
 Wend
 *object\lastBuffer = *buffer
 ProcedureReturn #True
EndProcedure


Procedure.i StringBuffer_addC(*this.IStringBuffer, Character.c)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object.OStringBuffer = *this
 *buffer.StringBufferElement = *object\lastBuffer
 If *object\bufferSize <= *object\bufferOffset
  *object\bufferOffset = 0
  *newBuffer = #Null
  While *newBuffer = #Null
   *newBuffer = AllocateMemory(*object\bufferSize)
  Wend
  *newBufferElement = #Null
  While *newBufferElement = #Null
   *newBufferElement = AllocateMemory(*object\bufferSize)
  Wend
  *buffer\next = *newBufferElement
  *buffer = *buffer\next
  *buffer\buffer = *newBuffer
  *object\lastBuffer = *buffer
 EndIf
 *out.WORD = *buffer\buffer + *object\bufferOffset
 *out\w = Character
 *object\bufferOffset + 2
 *object\length + 1
 *object\lastBuffer = *buffer
 ProcedureReturn #True
EndProcedure


Procedure.i StringBuffer_addUniC(*this.IStringBuffer, Character.w)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object.OStringBuffer = *this
 *buffer.StringBufferElement = *object\lastBuffer
 If *object\bufferSize <= *object\bufferOffset
  *object\bufferOffset = 0
  *newBuffer = #Null
  While *newBuffer = #Null
   *newBuffer = AllocateMemory(*object\bufferSize)
  Wend
  *newBufferElement = #Null
  While *newBufferElement = #Null
   *newBufferElement = AllocateMemory(*object\bufferSize)
  Wend
  *buffer\next = *newBufferElement
  *buffer = *buffer\next
  *buffer\buffer = *newBuffer
  *object\lastBuffer = *buffer
 EndIf
 *out.WORD = *buffer\buffer + *object\bufferOffset
 *out\w = Character
 *object\bufferOffset + 2
 *object\length + 1
 *object\lastBuffer = *buffer
 ProcedureReturn #True
EndProcedure


Procedure.i StringBuffer_clear(*this.IStringBuffer)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object.OStringBuffer = *this
 *object\bufferOffset = 0
 *object\lastBuffer = *object\bufferList
 *buffer.StringBufferElement = *object\bufferList
 If *buffer\next
  *buffer = *buffer\next
  Repeat
   *nextBuffer = *buffer\next
   FreeMemory(*buffer\buffer)
   FreeMemory(*buffer)
   *buffer = *nextBuffer
  Until *buffer = #Null Or *buffer\next = #Null
 EndIf
 *object\bufferList\next = #Null
 *object\length = 0
 ProcedureReturn #True
EndProcedure


Procedure.s StringBuffer_get(*this.IStringBuffer)
 If *this = #Null
  ProcedureReturn ""
 EndIf
 *object.OStringBuffer = *this
 *buffer.StringBufferElement = *object\bufferList
 Result$ = ""
 While *buffer\next
  Result$ + PeekS(*buffer\buffer, *object\bufferSize >> 1, #PB_Unicode)
  *buffer = *buffer\next
 Wend
 Result$ + PeekS(*buffer\buffer, *object\bufferOffset >> 1, #PB_Unicode)
 ProcedureReturn Result$
EndProcedure


Procedure.i StringBuffer_getMem(*this.IStringBuffer)
 If *this = #Null
  ProcedureReturn #Null
 EndIf
 *object.OStringBuffer = *this
 *result = AllocateMemory((*object\length + 1) * 2)
 If *result = #Null
  ProcedureReturn #Null
 EndIf
 If *this\copyToMem(*result) = #Null
  ProcedureReturn #Null
 EndIf
 ProcedureReturn *result
EndProcedure


Procedure.i StringBuffer_copyToMem(*this.IStringBuffer, *mem)
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object.OStringBuffer = *this
 If *mem = #Null
  ProcedureReturn (*object\length + 1) * 2
 EndIf
 *buffer.StringBufferElement = *object\bufferList
 While *buffer\next
  CopyMemory(*buffer\buffer, *mem, *object\bufferSize)
  *mem + *object\bufferSize
  *buffer = *buffer\next
 Wend
 CopyMemory(*buffer\buffer, *mem, *object\bufferOffset)
 ProcedureReturn (*object\length + 1) * 2
EndProcedure


Procedure.i StringBuffer_length(*this.IStringBuffer)
 If *this = #Null
  ProcedureReturn -1
 EndIf
 *object.OStringBuffer = *this
 ProcedureReturn *object\length
EndProcedure


Procedure.i StringBuffer_delete(*this.IStringBuffer)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *this\clear()
 *object.OStringBuffer = *this
 FreeMemory(*object\bufferList\buffer)
 FreeMemory(*object\bufferList)
 FreeMemory(*object)
 ProcedureReturn #True
EndProcedure


DataSection
 OStringBuffer_methods:
  Data.i @StringBuffer_add()
  Data.i @StringBuffer_addC()
  Data.i @StringBuffer_addUniC()
  Data.i @StringBuffer_clear()
  Data.i @StringBuffer_get()
  Data.i @StringBuffer_getMem()
  Data.i @StringBuffer_copyToMem()
  Data.i @StringBuffer_length()
  Data.i @StringBuffer_delete()
EndDataSection


Procedure.i newStringBuffer(bufferSize.i = 128) ;KB
 If bufferSize < 1
  ProcedureReturn #Null
 EndIf
 *object.OStringBuffer = AllocateMemory(SizeOf(OStringBuffer))
 If *object = 0
  ProcedureReturn #Null
 EndIf
 *object\methodAddress = ?OStringBuffer_methods
 *object\bufferSize = bufferSize * 1024
 *object\bufferOffset = 0
 *object\bufferList = AllocateMemory(SizeOf(StringBufferElement))
 If *object\bufferList = #Null
  FreeMemory(*object)
  ProcedureReturn #Null
 EndIf
 *object\bufferList\next = 0
 *object\bufferList\buffer = AllocateMemory(*object\bufferSize)
 If *object\bufferList\buffer = #Null
  FreeMemory(*object\bufferList)
  FreeMemory(*object)
  ProcedureReturn #Null
 EndIf
 *object\lastBuffer = *object\bufferList
 *object\length = 0
 ProcedureReturn *object
EndProcedure


OpenConsole() 

Buf$ = "" 
t1 = ElapsedMilliseconds() 
For i = 0 To 10230 
 Buf$ + "aaaaaaaaaa" 
Next 
t1 = ElapsedMilliseconds() - t1 
l1 = Len(Buf$) 
Buf$ = "" 

b.IStringBuffer = newStringBuffer() 
t2 = ElapsedMilliseconds() 
For i = 0 To 10230 
 b\add("aaaaaaaaaa") 
Next 
Buf$ = b\get() 
t2 = ElapsedMilliseconds() - t2 
l2 = Len(Buf$) 
b\delete() 
Buf$ = "" 

PrintN("PureBasic: " + Str(t1) + " ms (" + Str(l1) + " characters)") 
PrintN("StringBuffer: " + Str(t2) + " ms (" + Str(l2) + " characters)") 

Input()
Edit: added some additional methods
Last edited by pcfreak on Tue Feb 17, 2009 11:18 am, edited 1 time in total.
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Post by milan1612 »

I didn't take a closer look yet, but that looks really great! I always wanted to code
something like this, really useful for a lot of codes of mine! Thanks for sharing... :P
Windows 7 & PureBasic 4.4
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

a sort of Stringbuilder(.NET) for Pure.
Amazing work PCFreak .
specially if you increase stringsize,
your routines are very very fast.
SPAMINATOR NR.1
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

bet that made you smile, much faster!

It's a good example of using OO too.

thanks for sharing.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Elegant and nice :D

Thanks for sharing with us.
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

Code: Select all

For i = 0 To 10230
:o
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Wow, very nice.

Thanks for sharing.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

You need to disable the debugger properly (from the menu) before doing speed tests.
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

Trond wrote:You need to disable the debugger properly (from the menu) before doing speed tests.
sure ?
pcfreak wrote:...

Code: Select all

DisableDebugger
.
.
.
[code][/quote]
SPAMINATOR NR.1
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

Post by Motu »

hi pcfreak,

great and speedy code, nice :-)

anyway, I guess there is a reason why PB does not handle strings that way. Change the end of your code to that:

Code: Select all

Global Buf.s = "" 
Global Test.s = ""
t1 = ElapsedMilliseconds() 
For i = 0 To 10230 
 Buf + "aaaaaaaaaa" 
 Test = Buf
Next 
t1 = ElapsedMilliseconds() - t1 
l1 = Len(Buf$) 
Buf$ = "" 

b.IStringBuffer = newStringBuffer() 
t2 = ElapsedMilliseconds() 
For i = 0 To 10230 
 b\add("aaaaaaaaaa") 
 Test = b\get() 
Next 
t2 = ElapsedMilliseconds() - t2 
l2 = Len(Buf$) 
b\delete() 
Buf$ = "" 

PrintN("PureBasic: " + Str(t1) + " ms (" + Str(l1) + " characters)") 
PrintN("StringBuffer: " + Str(t2) + " ms (" + Str(l2) + " characters)") 

and you'll see PB getting faster. You insert is really fast, but you have to pay the bill when calling the \get.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Rings wrote:
Trond wrote:You need to disable the debugger properly (from the menu) before doing speed tests.
sure ?
pcfreak wrote:...

Code: Select all

DisableDebugger
.
.
.
[code][/quote][/quote]No, you need to disable the debugger from the menu or from the toolbar.
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

Post by pcfreak »

and you'll see PB getting faster. You insert is really fast, but you have to pay the bill when calling the \get.
true, but this code isn't to replace purebasic's string handling, it's just to build strings fast. in many cases you just add up small parts of strings to one string, if you make a html output from some database entries for example. just use it when needed :P
Post Reply