summaryrefslogtreecommitdiff
path: root/src/library/scalax/collection/generic/IterableView.scala
blob: 45a0a50be2e9756259b9f4e5f151c8ea9ce10758 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2009, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id: Iterable.scala 15188 2008-05-24 15:01:02Z stepancheg $

package scalax.collection.generic

/** A non-strict projection of an iterable.
 * @author Sean McDirmid
 * @author Martin Odersky
 * @note this should really be a virtual class of SequenceFactory
 */
trait IterableView[+UC[/*+*/B] <: Iterable[B], /*+*/A] extends Iterable[A] { self =>

  val origin: Iterable[_]
  def elements: Iterator[A]

  val underlying: Iterable[_] = origin match {
    case v: IterableView[t, _] => v.underlying
    case _ => origin
  }

  private def isDelay = elements eq underlying.elements

  private[this] var forced: UC[A] = _
  private[this] var wasForced = false

  def force: UC[A] = {
    if (!wasForced) {
      forced = {
        val b = underlying.newBuilder[A]
        for (x <- elements)
          b += x
        b.result
      }.asInstanceOf[UC[A]]
      wasForced = true
    }
    forced
  }

  def newBuilder[A] = underlying.newBuilder[A]

  /** Builds a new view object. This method needs to be overridden in subclasses
   *  which refine in IterableView type
   */
  protected def newView[B](elems: Iterator[B]) = new IterableView[UC, B] {
    val origin = if (self.isDelay) self.origin else self
    val elements = elems
  }

  /** Non-strict variant of @see IterableLike.++ */
  override def ++[B >: A](that: Iterator[B]): IterableView[UC, B] = newView(elements ++ that)

  /** Non-strict variant of @see IterableLike.++ */
  override def ++[B >: A](that: Iterable[B]): IterableView[UC, B] = newView(elements ++ that.elements)

  /** Non-strict variant of @see IterableLike.map */
  override def map[B](f: A => B): IterableView[UC, B] = newView(elements map f)

  /** Non-strict variant of @see IterableLike.flatMap */
  override def flatMap[B](f: A => Iterable[B]): IterableView[UC, B] = newView(elements flatMap (f(_).elements))

  /** Non-strict variant of @see IterableLike.filter */
  override def filter(p: A => Boolean): IterableView[UC, A] = newView(elements filter p)

  /** Non-strict variant of @see IterableLike.partition */
  override def partition(p: A => Boolean): (IterableView[UC, A], IterableView[UC, A]) = {
    val (li, ri) = elements partition p
    (newView(li), newView(ri))
  }

  /** Non-strict variant of @see IterableLike.zip */
  override def zip[B](other: Iterable[B]): IterableView[UC, (A, B)] = newView(elements zip other.elements)

  /** Non-strict variant of @see IterableLike.zipWithIndex */
  override def zipWithIndex: IterableView[UC, (A, Int)] = newView(elements.zipWithIndex)

  /* Non-strict variant of @see IterableLike.zipAll
   *  This is not enabled because it can't be specialized in VectorView:
   *  VectorView is not covariant, yet must maintain updatability. Impossible to do this
   *  with this type signature.
  override def zipAll[B, A1 >: A, B1 >: B](that: Iterable[B], thisElem: A1, thatElem: B1): IterableView[UC, (A1, B1)] =
    newView(elements zipAll (that.elements, thisElem, thatElem))
   */

  /** Non-strict variant of @see Iterable.take */
  override def take(n: Int): IterableView[UC, A] = newView(elements take n)

  /** Non-strict variant of @see Iterable.drop */
  override def drop(n: Int): IterableView[UC, A] = newView(elements drop n)

  /** Non-strict variant of @see Iterable.splitAt */
  override def splitAt(n: Int): (IterableView[UC, A], IterableView[UC, A]) = (take(n), drop(n))

  /** Non-strict variant of @see Iterable.slice */
  override def slice(from: Int, until: Int): IterableView[UC, A] = newView(elements slice (from, until))

  /** Non-strict variant of @see Iterable.takeWhile */
  override def takeWhile(p: A => Boolean): IterableView[UC, A] = newView(elements takeWhile p)

  /** Non-strict variant of @see Iterable.dropWhile */
  override def dropWhile(p: A => Boolean): IterableView[UC, A] = newView(elements dropWhile p)

  /** Non-strict variant of @see Iterable.span */
  override def span(p: A => Boolean): (IterableView[UC, A], IterableView[UC, A]) = (takeWhile(p), dropWhile(p))

  /** The projection resulting from the concatenation of this projection with the <code>rest</code> projection.
   *  @param rest   The projection that gets appended to this projection
   *  @deprecated   Use ++ instead
   */
  @deprecated def append[B >: A](rest : => Iterable[B]): IterableView[UC, B] = this ++ rest.elements

  override def stringPrefix = origin.stringPrefix+"V"


}