|
| 1 | +/* |
| 2 | + * Scala (https://www.scala-lang.org) |
| 3 | + * |
| 4 | + * Copyright EPFL and Lightbend, Inc. |
| 5 | + * |
| 6 | + * Licensed under Apache License 2.0 |
| 7 | + * (http://www.apache.org/licenses/LICENSE-2.0). |
| 8 | + * |
| 9 | + * See the NOTICE file distributed with this work for |
| 10 | + * additional information regarding copyright ownership. |
| 11 | + */ |
| 12 | + |
| 13 | +package scala |
| 14 | +package collection |
| 15 | + |
| 16 | +import scala.annotation.{nowarn, tailrec} |
| 17 | +import scala.collection.Searching.{Found, InsertionPoint, SearchResult} |
| 18 | +import scala.collection.Stepper.EfficientSplit |
| 19 | +import scala.math.Ordering |
| 20 | +import language.experimental.captureChecking |
| 21 | + |
| 22 | +/** Base trait for indexed sequences that have efficient `apply` and `length` */ |
| 23 | +trait IndexedSeq[+A] extends Seq[A] |
| 24 | + with IndexedSeqOps[A, IndexedSeq, IndexedSeq[A]] |
| 25 | + with IterableFactoryDefaults[A, IndexedSeq] { |
| 26 | + @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") |
| 27 | + override protected[this] def stringPrefix: String = "IndexedSeq" |
| 28 | + |
| 29 | + override def iterableFactory: SeqFactory[IndexedSeq] = IndexedSeq |
| 30 | +} |
| 31 | + |
| 32 | +@SerialVersionUID(3L) |
| 33 | +object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](immutable.IndexedSeq) |
| 34 | + |
| 35 | +/** Base trait for indexed Seq operations */ |
| 36 | +trait IndexedSeqOps[+A, +CC[_], +C] extends AnyRef with SeqOps[A, CC, C] { self => |
| 37 | + |
| 38 | + def iterator: Iterator[A] = view.iterator |
| 39 | + |
| 40 | + override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = { |
| 41 | + import convert.impl._ |
| 42 | + val s = shape.shape match { |
| 43 | + case StepperShape.IntShape => new IntIndexedSeqStepper (this.asInstanceOf[IndexedSeqOps[Int, AnyConstr, _]], 0, length) |
| 44 | + case StepperShape.LongShape => new LongIndexedSeqStepper (this.asInstanceOf[IndexedSeqOps[Long, AnyConstr, _]], 0, length) |
| 45 | + case StepperShape.DoubleShape => new DoubleIndexedSeqStepper(this.asInstanceOf[IndexedSeqOps[Double, AnyConstr, _]], 0, length) |
| 46 | + case _ => shape.parUnbox(new AnyIndexedSeqStepper[A](this, 0, length)) |
| 47 | + } |
| 48 | + s.asInstanceOf[S with EfficientSplit] |
| 49 | + } |
| 50 | + |
| 51 | + override def reverseIterator: Iterator[A] = view.reverseIterator |
| 52 | + |
| 53 | + /* TODO 2.14+ uncomment and delete related code in IterableOnce |
| 54 | + @tailrec private def foldl[B](start: Int, end: Int, z: B, op: (B, A) => B): B = |
| 55 | + if (start == end) z |
| 56 | + else foldl(start + 1, end, op(z, apply(start)), op) |
| 57 | + */ |
| 58 | + |
| 59 | + @tailrec private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B = |
| 60 | + if (start == end) z |
| 61 | + else foldr(start, end - 1, op(apply(end - 1), z), op) |
| 62 | + |
| 63 | + //override def foldLeft[B](z: B)(op: (B, A) => B): B = foldl(0, length, z, op) |
| 64 | + |
| 65 | + override def foldRight[B](z: B)(op: (A, B) => B): B = foldr(0, length, z, op) |
| 66 | + |
| 67 | + //override def reduceLeft[B >: A](op: (B, A) => B): B = if (length > 0) foldl(1, length, apply(0), op) else super.reduceLeft(op) |
| 68 | + |
| 69 | + //override def reduceRight[B >: A](op: (A, B) => B): B = if (length > 0) foldr(0, length - 1, apply(length - 1), op) else super.reduceRight(op) |
| 70 | + |
| 71 | + override def view: IndexedSeqView[A] = new IndexedSeqView.Id[A](this) |
| 72 | + |
| 73 | + @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0") |
| 74 | + override def view(from: Int, until: Int): IndexedSeqView[A] = view.slice(from, until) |
| 75 | + |
| 76 | + override protected def reversed: Iterable[A] = new IndexedSeqView.Reverse(this) |
| 77 | + |
| 78 | + // Override transformation operations to use more efficient views than the default ones |
| 79 | + override def prepended[B >: A](elem: B): CC[B] = iterableFactory.from(new IndexedSeqView.Prepended(elem, this)) |
| 80 | + |
| 81 | + override def take(n: Int): C = fromSpecific(new IndexedSeqView.Take(this, n)) |
| 82 | + |
| 83 | + override def takeRight(n: Int): C = fromSpecific(new IndexedSeqView.TakeRight(this, n)) |
| 84 | + |
| 85 | + override def drop(n: Int): C = fromSpecific(new IndexedSeqView.Drop(this, n)) |
| 86 | + |
| 87 | + override def dropRight(n: Int): C = fromSpecific(new IndexedSeqView.DropRight(this, n)) |
| 88 | + |
| 89 | + override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f)) |
| 90 | + |
| 91 | + override def reverse: C = fromSpecific(new IndexedSeqView.Reverse(this)) |
| 92 | + |
| 93 | + override def slice(from: Int, until: Int): C = fromSpecific(new IndexedSeqView.Slice(this, from, until)) |
| 94 | + |
| 95 | + override def head: A = apply(0) |
| 96 | + |
| 97 | + override def headOption: Option[A] = if (isEmpty) None else Some(head) |
| 98 | + |
| 99 | + override def last: A = apply(length - 1) |
| 100 | + |
| 101 | + // We already inherit an efficient `lastOption = if (isEmpty) None else Some(last)` |
| 102 | + |
| 103 | + override final def lengthCompare(len: Int): Int = Integer.compare(length, len) |
| 104 | + |
| 105 | + override def knownSize: Int = length |
| 106 | + |
| 107 | + override final def lengthCompare(that: Iterable[_]^): Int = { |
| 108 | + val res = that.sizeCompare(length) |
| 109 | + // can't just invert the result, because `-Int.MinValue == Int.MinValue` |
| 110 | + if (res == Int.MinValue) 1 else -res |
| 111 | + } |
| 112 | + |
| 113 | + override def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult = |
| 114 | + binarySearch(elem, 0, length)(ord) |
| 115 | + |
| 116 | + override def search[B >: A](elem: B, from: Int, to: Int)(implicit ord: Ordering[B]): SearchResult = |
| 117 | + binarySearch(elem, from, to)(ord) |
| 118 | + |
| 119 | + @tailrec |
| 120 | + private[this] def binarySearch[B >: A](elem: B, from: Int, to: Int) |
| 121 | + (implicit ord: Ordering[B]): SearchResult = { |
| 122 | + if (from < 0) binarySearch(elem, 0, to) |
| 123 | + else if (to > length) binarySearch(elem, from, length) |
| 124 | + else if (to <= from) InsertionPoint(from) |
| 125 | + else { |
| 126 | + val idx = from + (to - from - 1) / 2 |
| 127 | + math.signum(ord.compare(elem, apply(idx))) match { |
| 128 | + case -1 => binarySearch(elem, from, idx)(ord) |
| 129 | + case 1 => binarySearch(elem, idx + 1, to)(ord) |
| 130 | + case _ => Found(idx) |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | +} |
0 commit comments