Search notes:

VBA: A StringBuffer class for string concatenation

StringBuffer is a simple Visual Basic for Application class that wraps a pre-allocated string buffer.
This class is intended to be used for better performance when lots of strings need to be concatenated.
The test concatenates a string of 26 characters (all lower case of the ASCII alphabet) 25000 times. Without the StringBuffer, this takes approximately 10 seconds on my laptop, with the StringBuffer less than 1 second.

Methods

init(sz) Initializes the string buffer and pre-allocates sz characters
append(txt) Appends txt to the current text. Resizes the string if the current preallocation is too small
value Returns the value of the string currently stored in the buffer. This is the default method, thus .value is not technically required to appear in the source code.

Basic usage

The following simple snippet demonstrates how the string buffer is used:
The class automatically extends the internal buffer when its size becomes too small.
dim strBuf as new StringBuffer

strBuf.init    10000 ' Set initial buffer size

strBuf.append "text"
strBuf.append "more text"
strBuf.append "even more text"

msgBox strBuf.value
msgBox strBuf          ' Alternatively, use class's default member.

Source code

' vi: ft=vb
'
' V0.3

option explicit

private buf     as string
private cur_len as long

public sub init(size as long) ' {

    buf     = space$(size)
    cur_len = 0

end sub ' }

public sub append(text as string) ' {

    dim next_len as long
    next_len = cur_len + len(text)

    if len(buf) < next_len then
       dim cur_text as string
       cur_text = value
       buf = space$(next_len*2)

       mid(buf, 1, next_len) = cur_text & text

       cur_len = next_len
       exit sub
    end if

    mid$(buf, 1+cur_len, next_len) = text
    cur_len = next_len

end sub ' }

public function value as string ' {
    attribute value.vb_UserMemId = 0

    value = mid$(buf, 1, cur_len)
end function ' }
Github repository VBAModules, path: /Common/Text/StringBuffer.cls

Test case

option explicit

sub testStringBuffer () ' {

    dim sb as new StringBuffer : sb.init 5

    sb.append "foo"
    sb.append ", bar"

    if sb <> "foo, bar" then
       msgBox "Expected foo, bar, but got: " & sb
    end if

    sb.append " and baz. And quite a lot more!"

    if sb.value <> "foo, bar and baz. And quite a lot more!" then ' {
       msgBox sb.value
    end if ' }

  '
  ' StringBuffer V0.2: test default attribute:
  '
    if sb <> "foo, bar and baz. And quite a lot more!" then ' {
       msgBox "Accessing default attribute did not succeed"
    end if ' }

    sb.append("<")
    if sb <> "foo, bar and baz. And quite a lot more!<" then ' {
       msgBox "trailing < not found"
    end if ' }

    timeIt

end sub ' }

private sub timeIt ' {

    dim t0 as double

    t0 = timer

    dim i   as long
    dim str as string
    for i = 1 to 25000
        str = str & "abcdefghijklmnopqrstuvwxzy"
    next i

    debug.print "time string      : " & format((timer - t0) / 86400, "hh:mm:ss")

    t0 = timer
    dim strBuf as new stringBuffer : strBuf.init (10000& * 26)
    for i = 1 to 25000
        strBuf.append "abcdefghijklmnopqrstuvwxzy"
    next i

    debug.print "time stringBuffer: " & format((timer - t0) / 86400, "hh:mm:ss")

    if str <> strBuf.value then
       msgBox "str <> strBuf.value"
    end if

end sub ' }
Github repository VBAModules, path: /_test/Common/Text/StringBuffer.vb

History

V0.1
V0.2 Make value the class's default member (attribute value.vb_UserMemId = 0).
V0.3 Fix bug in append()

See also

A class that uses StringBuffer is StringJoiner.
René's VBA Modules
The .NET class System.Text.StringBuilder.

Index