Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize containsAll on RichIterable. #1344 #1353

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

youssef-abdallah
Copy link

Signed-off-by: YoussefAbdallah [email protected]

@@ -295,17 +295,38 @@ else if (inside.size() > 32 && !(inside instanceof SetIterable))
/**
* Returns true if all elements in source are contained in this collection.
*
* @since 1.0
* @since 11.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't change since tags. This method really was here since version 1.0.

if (this.size() < inside.size())
{
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On line 306, we've already called size() on both collections. If the sizes are unequal, we can return false. In other words, replace < with !=.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be correct? A.containsAll(B) should return true iff all the elements of B are contained in A, so A and B don't necessarily have the same size.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If A and B don't have the same size then they are definitely not equal.

{
if (source instanceof RichIterable)
{
RichIterable<?> outside = this;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already know that this is a RichIterable, because we're inside the interface. No need to assign it to another variable.

if (outside.size() > 32 && !(outside instanceof SetIterable))
{
outside = outside.toSet();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you pick 32?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the implementation consistent with RichIterable#containsNoneIterable.

{
outside = outside.toSet();
}
return inside.allSatisfy(outside::contains);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use Iterate.allSatisfy() then you don't need to check whether source is a RichIterable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@motlin Iterate.allSatisfy() can't be used in RichIterable as it is an implementation class.

Copy link
Contributor

@motlin motlin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm skeptical that this is an optimization, and suspect it's slower in some cases. There are no JMH tests or other performance tests or commentary explaining why it's faster. The purpose of this change seems to be purely to optimize code since it is more verbose than the previous implementation. I don't think we ought to merge this until we can be confident it's an optimization.

{
RichIterable<?> outside = this.toSet();
return StreamSupport.stream(source.spliterator(), false).allMatch(outside::contains);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a set, then calling toSet() is unnecessary, and this implementation is slower than necessary. I think we should leave this abstract on RichIterable.

{
return source instanceof RichIterable ? this.containsAllIterable(source)
: source.stream().allMatch(this::contains);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the conditional here. What does it matter if source is a RichIterable? It's being passed to a method that takes Iterable.

In addition, containsAllIterable() may convert this to a set, but if the collection is a plain one, not a RichIterable, then we don't convert anything to a set. Why the difference? If it's for performance, this inconsistency doesn't make sense to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants