Skip to content

Commit 8db8c11

Browse files
committed
More systematic treatement of IndexedView
Followinf @szeiger's suggestion, equip IndexView with optimized operations for map/drop/take.
1 parent dabf044 commit 8db8c11

File tree

2 files changed

+122
-52
lines changed

2 files changed

+122
-52
lines changed

src/strawman/collections/CollectionStrawMan6.scala

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,17 @@ object CollectionStrawMan6 extends LowPriority {
116116
trait Iterable[+A] extends IterableOnce[A] with IterableLike[A, Iterable] {
117117
/** The collection itself */
118118
protected def coll: this.type = this
119-
}
119+
}
120120

121-
/** Base trait for sequence collections */
122-
trait Seq[+A] extends Iterable[A] with SeqLike[A, Seq] {
123-
def apply(i: Int): A
121+
/** A trait representing indexable collections with finite length */
122+
trait ArrayLike[+A] extends Any {
124123
def length: Int
124+
def apply(i: Int): A
125125
}
126126

127+
/** Base trait for sequence collections */
128+
trait Seq[+A] extends Iterable[A] with SeqLike[A, Seq] with ArrayLike[A]
129+
127130
/** Base trait for linearly accessed sequences that have efficient `head` and
128131
* `tail` operations.
129132
* Known subclasses: List, LazyList
@@ -156,6 +159,8 @@ object CollectionStrawMan6 extends LowPriority {
156159
}
157160
}
158161

162+
type IndexedSeq[+A] = Seq[A] { def view: IndexedView[A] }
163+
159164
/** Base trait for strict collections that can be built using a builder.
160165
* @param A the element type of the collection
161166
* @param Repr the type of the underlying collection
@@ -593,6 +598,7 @@ object CollectionStrawMan6 extends LowPriority {
593598
}
594599

595600
class ArrayBufferView[A](val elems: Array[AnyRef], val start: Int, val end: Int) extends IndexedView[A] {
601+
def length = end - start
596602
def apply(n: Int) = elems(start + n).asInstanceOf[A]
597603
override def className = "ArrayBufferView"
598604
}
@@ -656,7 +662,8 @@ object CollectionStrawMan6 extends LowPriority {
656662
extends AnyVal with IterableOps[Char]
657663
with SeqMonoTransforms[Char, String]
658664
with IterablePolyTransforms[Char, List]
659-
with Buildable[Char, String] {
665+
with Buildable[Char, String]
666+
with ArrayLike[Char] {
660667

661668
protected def coll = new StringView(s)
662669
def iterator = coll.iterator
@@ -671,6 +678,9 @@ object CollectionStrawMan6 extends LowPriority {
671678

672679
protected[this] def newBuilder = new StringBuilder
673680

681+
def length = s.length
682+
def apply(i: Int) = s.charAt(i)
683+
674684
override def knownSize = s.length
675685

676686
override def className = "String"
@@ -720,8 +730,7 @@ object CollectionStrawMan6 extends LowPriority {
720730
}
721731

722732
case class StringView(s: String) extends IndexedView[Char] {
723-
val start = 0
724-
val end = s.length
733+
def length = s.length
725734
def apply(n: Int) = s.charAt(n)
726735
override def className = "StringView"
727736
}
@@ -731,11 +740,15 @@ object CollectionStrawMan6 extends LowPriority {
731740
implicit class ArrayOps[A](val xs: Array[A])
732741
extends AnyVal with IterableOps[A]
733742
with SeqMonoTransforms[A, Array[A]]
734-
with Buildable[A, Array[A]] {
743+
with Buildable[A, Array[A]]
744+
with ArrayLike[A] {
735745

736746
protected def coll = new ArrayView(xs)
737747
def iterator = coll.iterator
738748

749+
def length = xs.length
750+
def apply(i: Int) = xs.apply(i)
751+
739752
override def view = new ArrayView(xs)
740753

741754
def elemTag: ClassTag[A] = ClassTag(xs.getClass.getComponentType)
@@ -757,8 +770,7 @@ object CollectionStrawMan6 extends LowPriority {
757770
}
758771

759772
case class ArrayView[A](xs: Array[A]) extends IndexedView[A] {
760-
val start = 0
761-
val end = xs.length
773+
def length = xs.length
762774
def apply(n: Int) = xs(n)
763775
override def className = "ArrayView"
764776
}
@@ -822,15 +834,17 @@ object CollectionStrawMan6 extends LowPriority {
822834
/** A view that drops leading elements of the underlying collection. */
823835
case class Drop[A](underlying: Iterable[A], n: Int) extends View[A] {
824836
def iterator = underlying.iterator.drop(n)
837+
protected val normN = n max 0
825838
override def knownSize =
826-
if (underlying.knownSize >= 0) underlying.knownSize - n max 0 else -1
839+
if (underlying.knownSize >= 0) (underlying.knownSize - normN) max 0 else -1
827840
}
828841

829842
/** A view that takes leading elements of the underlying collection. */
830843
case class Take[A](underlying: Iterable[A], n: Int) extends View[A] {
831844
def iterator = underlying.iterator.take(n)
845+
protected val normN = n max 0
832846
override def knownSize =
833-
if (underlying.knownSize >= 0) underlying.knownSize min n else -1
847+
if (underlying.knownSize >= 0) underlying.knownSize min normN else -1
834848
}
835849

836850
/** A view that maps elements of the underlying collection. */
@@ -872,29 +886,51 @@ object CollectionStrawMan6 extends LowPriority {
872886
}
873887

874888
/** View defined in terms of indexing a range */
875-
trait IndexedView[+A] extends View[A] { self =>
876-
def start: Int
877-
def end: Int
878-
def apply(i: Int): A
889+
trait IndexedView[+A] extends View[A] with ArrayLike[A] {
879890

880891
def iterator: Iterator[A] = new Iterator[A] {
881-
private var current = start
882-
def hasNext = current < end
892+
private var current = 0
893+
def hasNext = current < length
883894
def next: A = {
884895
val r = apply(current)
885896
current += 1
886897
r
887898
}
888899
}
889900

890-
def reverse = new IndexedView[A] {
891-
def start = self.start
892-
def end = self.end
893-
def apply(i: Int) = self.apply(end - 1 - i)
901+
override def take(n: Int): IndexedView[A] = new IndexedView.Take(this, n)
902+
override def drop(n: Int): IndexedView[A] = new IndexedView.Drop(this, n)
903+
override def map[B](f: A => B): IndexedView[B] = new IndexedView.Map(this, f)
904+
def reverse: IndexedView[A] = new IndexedView.Reverse(this)
905+
}
906+
907+
object IndexedView {
908+
909+
class Take[A](underlying: IndexedView[A], n: Int)
910+
extends View.Take(underlying, n) with IndexedView[A] {
911+
override def iterator = super.iterator
912+
def length = underlying.length min normN
913+
def apply(i: Int) = underlying.apply(i)
894914
}
895915

896-
def length = end - start max 0
897-
override def knownSize = length
916+
class Drop[A](underlying: IndexedView[A], n: Int)
917+
extends View.Take(underlying, n) with IndexedView[A] {
918+
override def iterator = super.iterator
919+
def length = (underlying.length - normN) max 0
920+
def apply(i: Int) = underlying.apply(i + normN)
921+
}
922+
923+
class Map[A, B](underlying: IndexedView[A], f: A => B)
924+
extends View.Map(underlying, f) with IndexedView[B] {
925+
override def iterator = super.iterator
926+
def length = underlying.length
927+
def apply(n: Int) = f(underlying.apply(n))
928+
}
929+
930+
case class Reverse[A](underlying: IndexedView[A]) extends IndexedView[A] {
931+
def length = underlying.length
932+
def apply(i: Int) = underlying.apply(length - 1 - i)
933+
}
898934
}
899935

900936
/* ---------- Iterators ---------------------------------------------------*/
@@ -1002,8 +1038,7 @@ object CollectionStrawMan6 extends LowPriority {
10021038
def next = throw new NoSuchElementException("next on empty iterator")
10031039
}
10041040
def apply[A](xs: A*): Iterator[A] = new IndexedView[A] {
1005-
val start = 0
1006-
val end = xs.length
1041+
val length = xs.length
10071042
def apply(n: Int) = xs(n)
10081043
}.iterator
10091044
}

tests/run/colltest6/CollectionStrawMan6_1.scala

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,17 @@ object CollectionStrawMan6 extends LowPriority {
117117
trait Iterable[+A] extends IterableOnce[A] with IterableLike[A, Iterable] {
118118
/** The collection itself */
119119
protected def coll: this.type = this
120-
}
120+
}
121121

122-
/** Base trait for sequence collections */
123-
trait Seq[+A] extends Iterable[A] with SeqLike[A, Seq] {
124-
def apply(i: Int): A
122+
/** A trait representing indexable collections with finite length */
123+
trait ArrayLike[+A] extends Any {
125124
def length: Int
125+
def apply(i: Int): A
126126
}
127127

128+
/** Base trait for sequence collections */
129+
trait Seq[+A] extends Iterable[A] with SeqLike[A, Seq] with ArrayLike[A]
130+
128131
/** Base trait for linearly accessed sequences that have efficient `head` and
129132
* `tail` operations.
130133
* Known subclasses: List, LazyList
@@ -157,6 +160,8 @@ object CollectionStrawMan6 extends LowPriority {
157160
}
158161
}
159162

163+
type IndexedSeq[+A] = Seq[A] { def view: IndexedView[A] }
164+
160165
/** Base trait for strict collections that can be built using a builder.
161166
* @param A the element type of the collection
162167
* @param Repr the type of the underlying collection
@@ -594,6 +599,7 @@ object CollectionStrawMan6 extends LowPriority {
594599
}
595600

596601
class ArrayBufferView[A](val elems: Array[AnyRef], val start: Int, val end: Int) extends IndexedView[A] {
602+
def length = end - start
597603
def apply(n: Int) = elems(start + n).asInstanceOf[A]
598604
override def className = "ArrayBufferView"
599605
}
@@ -657,7 +663,8 @@ object CollectionStrawMan6 extends LowPriority {
657663
extends AnyVal with IterableOps[Char]
658664
with SeqMonoTransforms[Char, String]
659665
with IterablePolyTransforms[Char, List]
660-
with Buildable[Char, String] {
666+
with Buildable[Char, String]
667+
with ArrayLike[Char] {
661668

662669
protected def coll = new StringView(s)
663670
def iterator = coll.iterator
@@ -672,6 +679,9 @@ object CollectionStrawMan6 extends LowPriority {
672679

673680
protected[this] def newBuilder = new StringBuilder
674681

682+
def length = s.length
683+
def apply(i: Int) = s.charAt(i)
684+
675685
override def knownSize = s.length
676686

677687
override def className = "String"
@@ -721,8 +731,7 @@ object CollectionStrawMan6 extends LowPriority {
721731
}
722732

723733
case class StringView(s: String) extends IndexedView[Char] {
724-
val start = 0
725-
val end = s.length
734+
def length = s.length
726735
def apply(n: Int) = s.charAt(n)
727736
override def className = "StringView"
728737
}
@@ -732,11 +741,15 @@ object CollectionStrawMan6 extends LowPriority {
732741
implicit class ArrayOps[A](val xs: Array[A])
733742
extends AnyVal with IterableOps[A]
734743
with SeqMonoTransforms[A, Array[A]]
735-
with Buildable[A, Array[A]] {
744+
with Buildable[A, Array[A]]
745+
with ArrayLike[A] {
736746

737747
protected def coll = new ArrayView(xs)
738748
def iterator = coll.iterator
739749

750+
def length = xs.length
751+
def apply(i: Int) = xs.apply(i)
752+
740753
override def view = new ArrayView(xs)
741754

742755
def elemTag: ClassTag[A] = ClassTag(xs.getClass.getComponentType)
@@ -758,8 +771,7 @@ object CollectionStrawMan6 extends LowPriority {
758771
}
759772

760773
case class ArrayView[A](xs: Array[A]) extends IndexedView[A] {
761-
val start = 0
762-
val end = xs.length
774+
def length = xs.length
763775
def apply(n: Int) = xs(n)
764776
override def className = "ArrayView"
765777
}
@@ -823,15 +835,17 @@ object CollectionStrawMan6 extends LowPriority {
823835
/** A view that drops leading elements of the underlying collection. */
824836
case class Drop[A](underlying: Iterable[A], n: Int) extends View[A] {
825837
def iterator = underlying.iterator.drop(n)
838+
protected val normN = n max 0
826839
override def knownSize =
827-
if (underlying.knownSize >= 0) underlying.knownSize - n max 0 else -1
840+
if (underlying.knownSize >= 0) (underlying.knownSize - normN) max 0 else -1
828841
}
829842

830843
/** A view that takes leading elements of the underlying collection. */
831844
case class Take[A](underlying: Iterable[A], n: Int) extends View[A] {
832845
def iterator = underlying.iterator.take(n)
846+
protected val normN = n max 0
833847
override def knownSize =
834-
if (underlying.knownSize >= 0) underlying.knownSize min n else -1
848+
if (underlying.knownSize >= 0) underlying.knownSize min normN else -1
835849
}
836850

837851
/** A view that maps elements of the underlying collection. */
@@ -873,29 +887,51 @@ object CollectionStrawMan6 extends LowPriority {
873887
}
874888

875889
/** View defined in terms of indexing a range */
876-
trait IndexedView[+A] extends View[A] { self =>
877-
def start: Int
878-
def end: Int
879-
def apply(i: Int): A
890+
trait IndexedView[+A] extends View[A] with ArrayLike[A] {
880891

881892
def iterator: Iterator[A] = new Iterator[A] {
882-
private var current = start
883-
def hasNext = current < end
893+
private var current = 0
894+
def hasNext = current < length
884895
def next: A = {
885896
val r = apply(current)
886897
current += 1
887898
r
888899
}
889900
}
890901

891-
def reverse = new IndexedView[A] {
892-
def start = self.start
893-
def end = self.end
894-
def apply(i: Int) = self.apply(end - 1 - i)
902+
override def take(n: Int): IndexedView[A] = new IndexedView.Take(this, n)
903+
override def drop(n: Int): IndexedView[A] = new IndexedView.Drop(this, n)
904+
override def map[B](f: A => B): IndexedView[B] = new IndexedView.Map(this, f)
905+
def reverse: IndexedView[A] = new IndexedView.Reverse(this)
906+
}
907+
908+
object IndexedView {
909+
910+
class Take[A](underlying: IndexedView[A], n: Int)
911+
extends View.Take(underlying, n) with IndexedView[A] {
912+
override def iterator = super.iterator
913+
def length = underlying.length min normN
914+
def apply(i: Int) = underlying.apply(i)
895915
}
896916

897-
def length = end - start max 0
898-
override def knownSize = length
917+
class Drop[A](underlying: IndexedView[A], n: Int)
918+
extends View.Take(underlying, n) with IndexedView[A] {
919+
override def iterator = super.iterator
920+
def length = (underlying.length - normN) max 0
921+
def apply(i: Int) = underlying.apply(i + normN)
922+
}
923+
924+
class Map[A, B](underlying: IndexedView[A], f: A => B)
925+
extends View.Map(underlying, f) with IndexedView[B] {
926+
override def iterator = super.iterator
927+
def length = underlying.length
928+
def apply(n: Int) = f(underlying.apply(n))
929+
}
930+
931+
case class Reverse[A](underlying: IndexedView[A]) extends IndexedView[A] {
932+
def length = underlying.length
933+
def apply(i: Int) = underlying.apply(length - 1 - i)
934+
}
899935
}
900936

901937
/* ---------- Iterators ---------------------------------------------------*/
@@ -1003,8 +1039,7 @@ object CollectionStrawMan6 extends LowPriority {
10031039
def next = throw new NoSuchElementException("next on empty iterator")
10041040
}
10051041
def apply[A](xs: A*): Iterator[A] = new IndexedView[A] {
1006-
val start = 0
1007-
val end = xs.length
1042+
val length = xs.length
10081043
def apply(n: Int) = xs(n)
10091044
}.iterator
10101045
}

0 commit comments

Comments
 (0)