Skip to content

Repository files navigation

Github Repository BadgeIssues BadgeReleases BadgeUnlicense Badge

VBA / VB6 mscorlib's ArrayList drop-in replacement with proper memory management and orders of magnitude faster than mscorlib.ArrayList, making use of twinBASIC's new language features and memory management techniques from VBA-MemoryTools.

Initially, this drop-in replacement for mscorlib.ArrayList was just to get rid of the 423 MB VMem overhead added to VBA projects when using its ArrayList implementation. But it also turned out to exceed the speed performance of mscorlib.ArrayList by far, along with a proper memory release/deallocation when destroyed or it goes out of scope. Which can't even be manually achieved with mscorlib.ArrayList as setting it to Nothing or .Clear 'ing it doesn't free any memory.

Features / Improvements

  • IntelliSense support.

  • Takes less than 0.35 MB of VMem to load on first use instead of the 423 MB taken by mscorlib. VBA apps in Win32 are limited to 2 GB, if you also add the non-existing memory deallocation of mscorlib.ArrayList, continued operations on mid to large datasets are a dead-end in using mscorlib.ArrayList.

  • As a drop-in replacement, it is expected to provide the exact same output and functionality as when using mscorlib.ArrayList whithin VBA. Static members such as .Adapter or .Repeat can't be used from VBA so they're not included, nor the Type parameter in .ToArray(), which can't be used either. Additionally, all other members that can could be called or accessed even though they are totally useless from the VBA side, are included but hidden, as in duplicated members with similar names to overcome the missing method overloading feature in COM, such as .Sort_2.

  • Unlike mscorlib.ArrayList, it allows plain VBA Arrays and other enumerable objects as input in parameters expecting a collection-like object (Of ICollection Type in mscorlib's ArrayList.cs).

    ' Example:.AddRange(Array(_"String at index 0",_Array(34,"Lorem Ipsum"),_Array(Now(),"Hello World!"),_256))
  • Provides an advanced Enumerator allowing the use of For Each within subranges, backwards enumeration, custom iteration steps and direct access to the backing enumerator instance allowing an even wider set of possibilities while iterating the Enumerator.

  • The Enumerator class is publicly accessible so you can reuse it anywhere else in your code.

  • Using multidimensional arrays as elements is not supported by mscorlib.ArrayList but ArrayList seems to have no reason for that, they just work like any other value or reference types when being added as elements. (If anyone encounters with such problems in ArrayList please post an issue)

Documentation

  • ArrayList docs are available here but, as a drop-in replacement, you can also use the ones from the official .NET Documentation which has lots of usage examples, just ignore static members as they can't be called from VBA. You might also like to have a look directly at the source code of mscorlib.ArrayList in CSharp.

Performance Tests Results

Percentages are calculated against mscorlib.ArrayList's timings from corresponding Win64 or Win32 results.

The lower the percentage, the better. 20% equals to a 5 times faster performance while 500% would be 5 times slower than their corresponding Win64 or Win32 execution time in mscorlib.ArrayList.

ArrayList Classmscorlib.ArrayListVBA.Collection
x64x32x64x32x64x32
.Add
(x5000)
0 ms6%0 ms4%17 ms23 ms0 ms6%1 ms4%
.Add
(250x5000)
134 ms4%181 ms3%3579 ms6302 ms186 ms5%184 ms3%
.Clone
(50x5000)
3 ms100%5 ms167%3 ms3 ms2773 ms92433%2674 ms89133%
.Insert Index:=0
(20x1000)
9 ms4%10 ms6%209 ms181 ms3 ms1%4 ms2%
.Insert Index:=RND
(2x5000)
37 ms49%43 ms41%75 ms104 ms147 ms196%124 ms119%
.Item
(Read) SEQ (20x5000)
9 ms2%10 ms2%421 ms644 ms1125 ms267%1052 ms163%
.Item
(Read) SEQ+RND (20x5000)
19 ms3%21 ms2%735 ms1135 ms2198 ms299%2142 ms189%
.RemoveAt Index:=0
(x5000)
5 ms22%4 ms13%23 ms31 ms1 ms4%1 ms3%
.RemoveAt Index:=RND
(x12000)
70 ms34%42 ms20%203 ms209 ms910 ms448%675 ms323%
.RemoveAt Index:=LAST
(x12000)
1 ms3%2 ms3%33 ms58 ms508 ms1539%340 ms586%
.GetRange Index:=RND
(1000x5000)
2 ms18%3 ms16%11 ms19 ms
.AddRange Range
(x1000)
77 ms31%176 ms103%249 ms171 ms
.GetEnumerator
(For Each) (10x100000)
111 ms14%114 ms17%775 ms659 ms25 ms3%25 ms4%
.Sort
(100000)
167 ms293%181 ms503%57 ms36 ms
.Sort w/ Comparer
(100000)
494 ms37%453 ms18%1320 ms2473 ms

Where .Add(250x5000) equals to the following code.

Fore=0ToIterations-1' Iterations = 250Fori=0ToUBound(t)' UBound(t) = 5000 - 1.Addt(i)NextiNexte

That's a total of 1,250,000 calls to .Add, taking only 134ms (Win64) instead of 3,579ms in mscorlib.ArrayList.

While the .Add method of VBA.Collection has similar performance as in our ArrayList, reading/accessing their values is potentially slow and gets exponentially worse depending on the number of elements it contains. A simple sequential read of 5,000 items in a VBA.Collection takes 59 ms, reading 10,000 items takes 266 ms, which is almost 5 times more with just twice the size but reading 100,000 items, takes 36,069 ms, 135 times slower just increasing 10 times it's size. Our ArrayList only takes 9 ms to read 100,000 items, increasing linearly, taking 94 ms to read 1,000,000 items.

So in order to include VBA.Collection in the table above, tests are iterated multiple times over 5,000 items instead of using bigger sizes.

Acknowledgments

  • To @CristianBuse's VBA-MemoryTools, from which I discovered a whole new level in VBA programming, is what runs the most performance-critical parts behind ArrayList, and himself for his amazing and extensive support.

License

About

VBA / VB6 ArrayList implementation w/ proper memory management and orders of magnitude faster than mscorlib.ArrayList

Topics

Resources

Stars

6 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages