-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[backport] List.filter optimizations from 2.13.x #8226
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -15,9 +15,10 @@ package collection | |||||
|
||||||
import generic._ | ||||||
import mutable.Builder | ||||||
import scala.annotation.migration | ||||||
import scala.annotation.unchecked.{ uncheckedVariance => uV } | ||||||
import scala.annotation.{migration, tailrec} | ||||||
import scala.annotation.unchecked.{uncheckedVariance => uV} | ||||||
import parallel.ParIterable | ||||||
import scala.collection.immutable.{::, List, Nil} | ||||||
import scala.language.higherKinds | ||||||
|
||||||
/** A template trait for traversable collections of type `Traversable[A]`. | ||||||
|
@@ -246,11 +247,95 @@ trait TraversableLike[+A, +Repr] extends Any | |||||
} | ||||||
|
||||||
private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { | ||||||
val b = newBuilder | ||||||
for (x <- this) | ||||||
if (p(x) != isFlipped) b += x | ||||||
this match { | ||||||
case as: List[A] => | ||||||
filterImplList(as, p, isFlipped).asInstanceOf[Repr] | ||||||
case _ => | ||||||
val b = newBuilder | ||||||
for (x <- this) | ||||||
if (p(x) != isFlipped) b += x | ||||||
|
||||||
b.result | ||||||
} | ||||||
} | ||||||
|
||||||
b.result | ||||||
private[this] def filterImplList[A](self: List[A], p: A => Boolean, isFlipped: Boolean): List[A] = { | ||||||
|
||||||
// everything seen so far so far is not included | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
@tailrec def noneIn(l: List[A]): List[A] = { | ||||||
if (l.isEmpty) | ||||||
Nil | ||||||
else { | ||||||
val h = l.head | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only used once - inline? |
||||||
val t = l.tail | ||||||
if (p(h) != isFlipped) | ||||||
allIn(l, t) | ||||||
else | ||||||
noneIn(t) | ||||||
} | ||||||
} | ||||||
|
||||||
// everything from 'start' is included, if everything from this point is in we can return the origin | ||||||
// start otherwise if we discover an element that is out we must create a new partial list. | ||||||
@tailrec def allIn(start: List[A], remaining: List[A]): List[A] = { | ||||||
if (remaining.isEmpty) | ||||||
start | ||||||
else { | ||||||
val x = remaining.head | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only used once - inline? |
||||||
if (p(x) != isFlipped) | ||||||
allIn(start, remaining.tail) | ||||||
else | ||||||
partialFill(start, remaining) | ||||||
} | ||||||
} | ||||||
|
||||||
// we have seen elements that should be included then one that should be excluded, start building | ||||||
def partialFill(origStart: List[A], firstMiss: List[A]): List[A] = { | ||||||
val newHead = new ::(origStart.head, Nil) | ||||||
var toProcess = origStart.tail | ||||||
var currentLast = newHead | ||||||
|
||||||
// we know that all elements are :: until at least firstMiss.tail | ||||||
while (!(toProcess eq firstMiss)) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason to |
||||||
val newElem = new ::(toProcess.head, Nil) | ||||||
currentLast.tl = newElem | ||||||
currentLast = newElem | ||||||
toProcess = toProcess.tail | ||||||
} | ||||||
|
||||||
// at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss. | ||||||
// currentLast is the last element in that list. | ||||||
|
||||||
// now we are going to try and share as much of the tail as we can, only moving elements across when we have to. | ||||||
var next = firstMiss.tail | ||||||
var nextToCopy = next // the next element we would need to copy to our list if we cant share. | ||||||
while (!next.isEmpty) { | ||||||
// generally recommended is next.isNonEmpty but this incurs an extra method call. | ||||||
val head: A = next.head | ||||||
if (p(head) != isFlipped) { | ||||||
next = next.tail | ||||||
} else { | ||||||
// its not a match - do we have outstanding elements? | ||||||
while (!(nextToCopy eq next)) { | ||||||
D87C | val newElem = new ::(nextToCopy.head, Nil) | |||||
currentLast.tl = newElem | ||||||
currentLast = newElem | ||||||
nextToCopy = nextToCopy.tail | ||||||
} | ||||||
nextToCopy = next.tail | ||||||
next = next.tail | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we assign one of these to the other rather than calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not tweak the code I'm backporting here (unless we spot an error of course). I think JIT or the CPU caches will make this sort of micro opt unnecessary from a performance perspective. |
||||||
} | ||||||
} | ||||||
|
||||||
// we have remaining elements - they are unchanged attach them to the end | ||||||
if (!nextToCopy.isEmpty) | ||||||
currentLast.tl = nextToCopy | ||||||
|
||||||
newHead | ||||||
} | ||||||
|
||||||
val result = noneIn(self) | ||||||
NthPortal marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
result | ||||||
} | ||||||
|
||||||
/** Selects all elements of this $coll which satisfy a predicate. | ||||||
|
Uh oh!
There was an error while loading. Please reload this page.