The solution
There are times when a solution based on passing strings - instead of passing
function pointers or function objects capable of outputting strings - is favorable.
For example, let's say I have a general routine that asks the user to verify
their billing information before they make a purchase, and this routine needs
to output a summary of what the user is buying. You might be tempted to say:
<%
' Output your purchase summary...
' ...then output your billing information verification system.
%>
|
but what if your billing information verification code needs to sprinkle HTML
on boths sides of the purchase summary. Then you're better off passing that purchase
summary - as a string - to the billing information verification code. You could
put together some sort of "object that outputs purchase summaries when this method
is called" type of system - and VBScript allows for this type of system - but
let's keep things simple and pretend we just want to pass in a string and we
need efficient string concatenation.
Enter StrCat.Catter. "Catter" is a C++ COM component
with a very small interface. Here's typical usage of it:
<%
Dim strcat
Set strcat = Server.CreateObject("StrCat.Catter")
Dim rs
Set rs = ExecuteSql("SELECT Username FROM Users")
do until rs.EOF
strcat rs(0) & "<br>" & vbCrLf
rs.MoveNext
loop
Dim some_str
some_str = strcat.Dump
Set strcat = nothing
Response.Write some_str
%>
|
That's pretty simple, isn't it? By having the concatenation method be the
default method, you just say the Catter's name - in this case strcat
- and it just tacks on the string you give it. When you're ready to use the whole
string, call Dump and you've got it!
Next, we'll look at the implementation of our Catter class and
performance tests.
Interface
For those who know IDL - or can fake it - Catter's interface is
as follows:
[id(0), helpstring("Add a string to the
end of this. Like str = str & .")]
HRESULT Cat([in] BSTR strToAdd);
[id(1), helpstring("Compute the total string for this.")]
HRESULT Resolve([out, retval] BSTR* pStrOutput);
[id(2), helpstring("Empty the contents of this.")]
HRESULT Reset();
[propget, id(3), helpstring("Get the current length of the total
string. Like Len, but much faster.")]
HRESULT Length([out, retval] int *pVal);
[id(4), helpstring("Add a string to the front of this. Like str =
& str.")]
HRESULT Prepend([in] BSTR strToPrepend);
[id(5), helpstring("Surround the current contents with a before and
after string. Like str = & str & .")]
HRESULT Surround([in] BSTR strToPrepend, [in] BSTR strToAppend);
[id(6), helpstring("Dump = Resolve then Reset. Returns the total
strings, and empties the contents of this.")]
HRESULT Dump([out, retval] BSTR* pStrOutput);
[id(7), helpstring("Synonym for Cat. Like str = str & .")]
HRESULT Append([in] BSTR strToAdd);
|
As you can see, this is general-purpose string assembly engine. At first there
was just Cat and Resolve. Then I found that I needed
Length, Prepend, and Surround. I mostly
use Dump instead of Resolve because it frees resources
sooner. Append and Reset are included for completeness.