@@ -391,6 +391,88 @@ sealed abstract class List[+A] extends AbstractSeq[A]
391
391
}
392
392
}
393
393
394
+ override def filter (p : A => Boolean ): List [A ] = filterImpl(p, isFlipped = false )
395
+
396
+ override def filterNot (p : A => Boolean ): List [A ] = filterImpl(p, isFlipped = true )
397
+
398
+ private [this ] def filterImpl (p : A => Boolean , isFlipped : Boolean ): List [A ] = {
399
+
400
+ // everything seen so far so far is not included
401
+ @ tailrec def noneIn (l : List [A ]): List [A ] = {
402
+ if (l.isEmpty)
403
+ Nil
404
+ else {
405
+ val h = l.head
406
+ val t = l.tail
407
+ if (p(h) != isFlipped)
408
+ allIn(l, t)
409
+ else
410
+ noneIn(t)
411
+ }
412
+ }
413
+
414
+ // everything from 'start' is included, if everything from this point is in we can return the origin
415
+ // start otherwise if we discover an element that is out we must create a new partial list.
416
+ @ tailrec def allIn (start : List [A ], remaining : List [A ]): List [A ] = {
417
+ if (remaining.isEmpty)
418
+ start
419
+ else {
420
+ val x = remaining.head
421
+ if (p(x) != isFlipped)
422
+ allIn(start, remaining.tail)
423
+ else
424
+ partialFill(start, remaining)
425
+ }
426
+ }
427
+
428
+ // we have seen elements that should be included then one that should be excluded, start building
429
+ def partialFill (origStart : List [A ], firstMiss : List [A ]): List [A ] = {
430
+ val newHead = new :: (origStart.head, Nil )
431
+ var toProcess = origStart.tail
432
+ var currentLast = newHead
433
+
434
+ // we know that all elements are :: until at least firstMiss.tail
435
+ while (! (toProcess eq firstMiss)) {
436
+ val newElem = new :: (toProcess.head, Nil )
437
+ currentLast.tl = newElem
438
+ currentLast = newElem
439
+ toProcess = toProcess.tail
440
+ }
441
+
442
+ // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss.
443
+ // currentLast is the last element in that list.
444
+
445
+ // now we are going to try and share as much of the tail as we can, only moving elements across when we have to.
446
+ var next = firstMiss.tail
447
+ var nextToCopy = next // the next element we would need to copy to our list if we cant share.
448
+ while (! next.isEmpty) {
449
+ // generally recommended is next.isNonEmpty but this incurs an extra method call.
450
+ val head : A = next.head
451
+ if (p(head) != isFlipped) {
452
+ next = next.tail
453
+ } else {
454
+ // its not a match - do we have outstanding elements?
455
+ while (! (nextToCopy eq next)) {
456
+ val newElem = new :: (nextToCopy.head, Nil )
457
+ currentLast.tl = newElem
458
+ currentLast = newElem
459
+ nextToCopy = nextToCopy.tail
460
+ }
461
+ nextToCopy = next.tail
462
+ next = next.tail
463
+ }
464
+ }
465
+
466
+ // we have remaining elements - they are unchanged attach them to the end
467
+ if (! nextToCopy.isEmpty)
468
+ currentLast.tl = nextToCopy
469
+
470
+ newHead
471
+ }
472
+
473
+ noneIn(repr)
474
+ }
475
+
394
476
override def reverse : List [A ] = {
395
477
var result : List [A ] = Nil
396
478
var these = this
0 commit comments