Smith
Smith

Reputation: 5959

Faster string comparison in vb6

Am trying to make my vb6 app run faster, the reason is that am populating vbaccelerators sgrid with about 10k items all at once (this is a requirement from client).

I had to populate about 20 columns for each of the 10k items, and i have to perform string comparison in about more than half of them, so i wrote a string comparison function and did profiling

Function IsEqual(byval value1 as string, Byval value2 as string) as boolean

    ' content, various versions are below

End function

currently the items = 5000 and each of the time below shows the time it took and various versions of the function:

LCase$(Value1) = LCase$(value2)

time: 29149 ms

(StrComp(Value1, value2, 1) = 0 )

time: 30836 ms

If StrComp(Value1, value2, 1) = 0 Then
    IsEqual = True
Else
    IsEqual = False
End If

time 34180 ms

If StrComp(Value1, value2, 1) = 0 Then IsEqual = True

time 28387 ms

Timing is done with:

Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Declare Function timeGetTime Lib "winmm.dll" () As Long

which returns the time in milliseconds.

Is there anyway to make the comparison faster?

Upvotes: 2

Views: 9625

Answers (5)

Occluded Sky
Occluded Sky

Reputation: 11

This should be pretty fast.

Option Explicit

Private Declare Sub DerefByte Lib "msvbvm60" Alias "GetMem1" (ByVal Add As Long, ByRef Value As Byte)
Private Declare Sub DerefLong Lib "msvbvm60" Alias "GetMem4" (ByVal Add As Long, ByRef Value As Long)

Private Sub Form_Load()

    Debug.Print IsEqual("Hello", "hello")
    Debug.Print IsEqualB("Hello", "hello")

End Sub

Public Function IsEqualB(Str1 As String, Str2 As String) As Boolean

    Dim lpS1 As Long, lpS2 As Long
    Dim t1 As Byte, t2 As Byte
    Dim lSz As Long
    Dim i As Long

    IsEqualB = True

    lpS1 = StrPtr(Str1)
    lpS2 = StrPtr(Str2)
    DerefLong lpS1 - 4, lSz

    If lSz = LenB(Str2) Then
        For i = 0 To lSz - 1 Step 2
            DerefByte lpS1 + i, t1
            DerefByte lpS2 + i, t2
            If Not (t1 = t2) Then
                IsEqualB = False
                Exit For
            End If
        Next
    Else
        IsEqualB = False
    End If

End Function

Public Function IsEqual(Str1 As String, Str2 As String) As Boolean

    Dim lpS1 As Long, lpS2 As Long
    Dim t1 As Byte, t2 As Byte
    Dim lSz As Long
    Dim i As Long

    IsEqual = True

    lpS1 = StrPtr(Str1)
    lpS2 = StrPtr(Str2)
    DerefLong lpS1 - 4, lSz

    If lSz = LenB(Str2) Then
        For i = 0 To lSz - 1 Step 2
            DerefByte lpS1 + i, t1
            DerefByte lpS2 + i, t2
            If Not (t1 Or &H20) = (t2 Or &H20) Then
                IsEqual = False
                Exit For
            End If
        Next
    Else
        IsEqual = False
    End If

End Function

The basic premise here is to do byte by byte comparison mod 2 over the Unicode strings. One of the above functions is case sensitive, IsEqualB, then other is insensitive IsEqual.

Of course, it uses a couple of undocumented functions in the Visual Basic 6 runtime: but if you want speed, that's what you have to do, unfortunately.

Upvotes: 1

gbrooksman
gbrooksman

Reputation: 115

look at the LockWindowUpdate() WinAPI call. This can really help grids when you are populating them . Make sure you call it once to lock the window and once to unlock it.

Upvotes: 0

George Mastros
George Mastros

Reputation: 24506

You can probably cut your execution time in half by using "OPTION COMPARE TEXT". Place this line at the top of your code module.

OPTION COMPARE TEXT

This line, when used, will cause string compare within the code module be case insensitive. Because of this, you can simply use:

Function IsEqual(byval value1 as string, Byval value2 as string) as boolean

    IsEqual = (Value1 = Value2)

End Function

Upvotes: 0

Adrian
Adrian

Reputation: 2354

Things that might improve performance include..

  • Change your parameters to ByRef
    • Using ByVal parameters copies the variables onto the stack. While this is a generally a good idea, if your comparison function is well-behaved and doesn't change the variables, making an extra copy of the data is not necessary.
  • Populate the grid on demand,
    • Only populate the parts of the grid that are showing on screen - track this with grid movement events. There are even grid controls for VB6 that facilitate this by letting you define "virtual" items and raising events to let you know which ones you need to populate. TList is the one I'm familiar with - I'll temper that suggestion with the caveat that it's licensing model can be a real PITA to work with.

Upvotes: 2

Tom Studee
Tom Studee

Reputation: 10452

Have you tried:

Function IsEqual(byval value1 as string, Byval value2 as string) as boolean

    Return StrComp(LCase$(Value1), LCase$(value2), vbBinaryCompare) = 0

End function

Upvotes: 0

Related Questions