Primitive containsAny & containsNone in Eclipse Collections

When Eclipse Collections 11.0.0 is released, it will now include the containsAny and containsNone methods on its primitive collections.

Mirror Lake in Yosemite National Park
Mirror Lake in Yosemite National Park

The functionality offered by these methods was previously available through the use of the anySatisfy and noneSatisfy methods. However, the new methods will have performance benefits baked in and offer some new method signatures.

Overview

Only int will be used for demonstration purposes in this article, but these are available for all of the other primitive collections.

The type signatures for these new methods are:

  • boolean containsAny(int… source)
  • boolean containsAny(IntIterable source)
  • boolean containsNone(int… source)
  • boolean containsNone(IntIterable source)

These methods are also tuned for performance when dealing with larger collection sizes. In those circumstances if the calling collection isn’t a Set, then a Set will be created to improve the speed of the lookup operations. A memory cost will be incurred to improve the overall performance of these methods.

default boolean containsAny(int... source)
{
IntIterable inside = this;
if (this.size() > 32 && source.length > 32 && !(this instanceof IntSet))
{
inside = this.toSet();
}
for (int i = 0; i < source.length; i++)
{
if (inside.contains(source[i]))
{
return true;
}
}
return false;
}

Above is the snippet for containsAny, but the containsNone is identical except for the return statements being swapped.

Happy Accidents

One awesome aspect of contributing to open source is that there are often side effects that make themselves known when you set out to do the work. As a result, there were a couple of things I was able to improve that weren’t explicitly defined in my ticket.

Performance of containsAll

As part of my original merge request, it was noted that the current implementation of containsAll was badly implemented and runs in O(n²). With the help of one of the committers, I ended up optimizing the method as part of a different merge request. The optimization was incredible when running an acceptance test with two lists containing a million elements each. On my machine the old implementation took 110 seconds, while the new implementation only took 200 milliseconds. Yet another performance improvement you can look forward to in Eclipse Collections 11.0.0!

Bug in noneSatisfy implementation of ImmutableBooleanEmptySet

When testing the containsAny and containsNone changes, I chanced across another bug that had to do with the return type of noneSatisfy on the ImmutableBooleanEmptySet object. My test assertions were not being honored, so when I dug into the code base I noticed that for this object the return type for both noneSatisfy and anySatisfy was false! This should definitely not be the case since they are direct opposites. Luckily my tests exposed this inconsistency and I was able to include this fix as part of my merge request.

This whole experience was a nice reminder for me that open source benefits contributors and projects equally. An active and open project culture helps find bugs and performance issues by illuminating sections of code that might not have been looked at in long time.