summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/jcl/Buffer.scala
blob: 15033867e99999cb625a3c2532803ba6c677f4bf (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2006-2007, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id$

package scala.collection.jcl;

/** A mutable sequence that supports element insertion and update.
 *
 *  @author Sean McDirmid
 */
trait Buffer[A] extends MutableSeq[A] with Collection[A] with Ranged[Int,A] {
  final protected type SortedSelf = Buffer[A];

  trait MutableSeqProjection extends super[MutableSeq].Projection;
  trait Projection extends MutableSeqProjection with super[Collection].Projection {
    override def filter(p : A => Boolean) = super[MutableSeqProjection].filter(p);
  }
  override def projection = new Projection {}

  override def elements : BufferIterator[Int,A];
  /** The first index of a buffer is 0. */
  override def first = 0;
  /** The last index of a buffer is its size - 1. */
  override def last = size - 1;
  /** Indices are compared through subtraction. */
  final def compare(k0 : Int, k1 : Int) = k0 - k1;
  /** Removes the element at index "idx" */
  def remove(idx : Int) = {
    val i = elements;
    val ret = i.seek(idx); i.remove; ret;
  }

  /** Replaces the element at index "idx" with "a."
    * @returns the element replaced.
    */
  def set(idx : Int, a : A) : A = {
    val i = elements;
    val ret = i.seek(idx); i.set(a); ret;
  }

  /** Equivalent to set except the replaced element is not returned. */
  def update(idx : Int, a : A) : Unit = set(idx, a);

  /** @returns always true. */
  def add(a : A) : Boolean = {
    val i = elements;
    while (i.hasNext) i.next;
    i.add(a);
    true;
  }

  /** Inserts "a" into this buffer just before the element at index "idx." */
  def add(idx: Int, a: A): Unit = {
    val i = elements; i.seek(idx);
    i.add(a);
  }

  /** Inserts all elements of <code>that</code> into this buffer just before
   *  the element at index <code>idx</code>.
   *
   *  @param idx  ..
   *  @param that ..
   */
  def addAll(idx: Int, that: Iterable[A]): Unit = {
    val i = elements; i.seek(idx);
    for (val that <- that) {
      i.add(that); i.next;
    }
  }

  override def transform(f: A => A): Boolean = {
    var changed = false;
    val i = elements;
    while (i.hasNext) {
      val a0 = i.next;
      val a1 = f(a0);
      if (a0 != a1) {
        i.set(a1); changed = true;
      }
    }
    changed;
  }
  override def +(a : A) : this.type = super[Collection].+(a);
  override def -=(a : A) = super[Collection].-=(a);
  override def isEmpty = super[MutableSeq].isEmpty;
  override def rangeImpl(from : Option[Int], until : Option[Int]) : Buffer[A] = new Range(from, until);


  protected class Range(var from : Option[Int], var until : Option[Int]) extends Buffer[A] {
    if (from == None && until == None) throw new IllegalArgumentException;
    if (from != None && until != None && !(from.get < until.get)) throw new IllegalArgumentException;
    override def add(a : A) =
      if (until == None) Buffer.this.add(a);
      else {
        Buffer.this.add(until.get, a);
        true;
      }
    private def translate(idx : Int) = {
      if (until != None && idx > until.get) throw new IllegalArgumentException;
      else if (from != None) from.get + idx;
      else idx;
    }
    override def apply(idx : Int) : A = Buffer.this.apply(translate(idx));
    override def set(idx : Int, a : A) = Buffer.this.set(translate(idx), a);
    override def add(idx : Int, a : A) = Buffer.this.add(translate(idx), a);
    override def remove(idx : Int) = Buffer.this.remove(translate(idx));
    override def length = {
      if (until != None) {
        if (from != None) until.get - from.get;
        else until.get;
      } else super.length;
    }
    def elements : BufferIterator[Int,A] = new RangeIterator;
    class RangeIterator extends BufferIterator[Int,A] {
      val underlying = Buffer.this.elements;
      if (from != None) underlying.seek(from.get);
      def hasNext = underlying.hasNext &&
        (until == None || underlying.nextIndex < until.get);
      def hasPrevious = underlying.hasPrevious &&
        (from == None || underlying.previousIndex >= from.get);
      def next = {
        if (until != None && underlying.nextIndex >= until.get) throw new NoSuchElementException;
        underlying.next;
      }
      def previous = {
        if (from != None && underlying.previousIndex < from.get) throw new NoSuchElementException;
        underlying.previous;
      }
      def add(a : A) = {
        if (until != None && underlying.nextIndex > until.get) throw new NoSuchElementException;
        if (from != None && underlying.previousIndex < from.get) throw new NoSuchElementException;
        underlying.add(a);
        if (until != None) until = Some(until.get + 1);
      }
      def set(a : A) = {
        if (until != None && underlying.nextIndex > until.get) throw new NoSuchElementException;
        if (from != None && underlying.previousIndex < from.get) throw new NoSuchElementException;
        underlying.set(a);
      }
      def remove = {
        if (until != None && underlying.nextIndex > until.get) throw new NoSuchElementException;
        if (from != None && underlying.previousIndex < from.get) throw new NoSuchElementException;
        underlying.remove;
      }
      def nextIndex = {
        val ret = underlying.nextIndex;
        if (until != None && ret >= until.get) throw new NoSuchElementException;
        if (from != None) ret - from.get;
        else ret;
      }
      def previousIndex = {
        val ret = underlying.previousIndex;
        if (from != None && ret < from.get) throw new NoSuchElementException;
        if (from != None) ret - from.get;
        else ret;
      }
    }
  }
}