|
| 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.collection |
| 14 | +package mutable |
| 15 | + |
| 16 | +import scala.annotation.nowarn |
| 17 | + |
| 18 | + |
| 19 | +/** A `Buffer` is a growable and shrinkable `Seq`. */ |
| 20 | +trait Buffer[A] |
| 21 | + extends Seq[A] |
| 22 | + with SeqOps[A, Buffer, Buffer[A]] |
| 23 | + with Growable[A] |
| 24 | + with Shrinkable[A] |
| 25 | + with IterableFactoryDefaults[A, Buffer] { |
| 26 | + |
| 27 | + override def iterableFactory: SeqFactory[Buffer] = Buffer |
| 28 | + |
| 29 | + override def knownSize: Int = super[Seq].knownSize |
| 30 | + |
| 31 | + //TODO Prepend is a logical choice for a readable name of `+=:` but it conflicts with the renaming of `append` to `add` |
| 32 | + /** Prepends a single element at the front of this $coll. |
| 33 | + * |
| 34 | + * @param elem the element to $add. |
| 35 | + * @return the $coll itself |
| 36 | + */ |
| 37 | + def prepend(elem: A): this.type |
| 38 | + |
| 39 | + /** Appends the given elements to this buffer. |
| 40 | + * |
| 41 | + * @param elem the element to append. |
| 42 | + */ |
| 43 | + @`inline` final def append(elem: A): this.type = addOne(elem) |
| 44 | + |
| 45 | + @deprecated("Use appendAll instead", "2.13.0") |
| 46 | + @`inline` final def append(elems: A*): this.type = addAll(elems) |
| 47 | + |
| 48 | + /** Appends the elements contained in a iterable object to this buffer. |
| 49 | + * @param xs the iterable object containing the elements to append. |
| 50 | + */ |
| 51 | + @`inline` final def appendAll(xs: IterableOnce[A]): this.type = addAll(xs) |
| 52 | + |
| 53 | + |
| 54 | + /** Alias for `prepend` */ |
| 55 | + @`inline` final def +=: (elem: A): this.type = prepend(elem) |
| 56 | + |
| 57 | + def prependAll(elems: IterableOnce[A]): this.type = { insertAll(0, elems); this } |
| 58 | + |
| 59 | + @deprecated("Use prependAll instead", "2.13.0") |
| 60 | + @`inline` final def prepend(elems: A*): this.type = prependAll(elems) |
| 61 | + |
| 62 | + /** Alias for `prependAll` */ |
| 63 | + @inline final def ++=:(elems: IterableOnce[A]): this.type = prependAll(elems) |
| 64 | + |
| 65 | + /** Inserts a new element at a given index into this buffer. |
| 66 | + * |
| 67 | + * @param idx the index where the new elements is inserted. |
| 68 | + * @param elem the element to insert. |
| 69 | + * @throws IndexOutOfBoundsException if the index `idx` is not in the valid range |
| 70 | + * `0 <= idx <= length`. |
| 71 | + */ |
| 72 | + @throws[IndexOutOfBoundsException] |
| 73 | + def insert(idx: Int, elem: A): Unit |
| 74 | + |
| 75 | + /** Inserts new elements at the index `idx`. Opposed to method |
| 76 | + * `update`, this method will not replace an element with a new |
| 77 | + * one. Instead, it will insert a new element at index `idx`. |
| 78 | + * |
| 79 | + * @param idx the index where a new element will be inserted. |
| 80 | + * @param elems the iterable object providing all elements to insert. |
| 81 | + * @throws IndexOutOfBoundsException if `idx` is out of bounds. |
| 82 | + */ |
| 83 | + @throws[IndexOutOfBoundsException] |
| 84 | + def insertAll(idx: Int, elems: IterableOnce[A]): Unit |
| 85 | + |
| 86 | + /** Removes the element at a given index position. |
| 87 | + * |
| 88 | + * @param idx the index which refers to the element to delete. |
| 89 | + * @return the element that was formerly at index `idx`. |
| 90 | + */ |
| 91 | + @throws[IndexOutOfBoundsException] |
| 92 | + def remove(idx: Int): A |
| 93 | + |
| 94 | + /** Removes the element on a given index position. It takes time linear in |
| 95 | + * the buffer size. |
| 96 | + * |
| 97 | + * @param idx the index which refers to the first element to remove. |
| 98 | + * @param count the number of elements to remove. |
| 99 | + * @throws IndexOutOfBoundsException if the index `idx` is not in the valid range |
| 100 | + * `0 <= idx <= length - count` (with `count > 0`). |
| 101 | + * @throws IllegalArgumentException if `count < 0`. |
| 102 | + */ |
| 103 | + @throws[IndexOutOfBoundsException] |
| 104 | + @throws[IllegalArgumentException] |
| 105 | + def remove(idx: Int, count: Int): Unit |
| 106 | + |
| 107 | + /** Removes a single element from this buffer, at its first occurrence. |
| 108 | + * If the buffer does not contain that element, it is unchanged. |
| 109 | + * |
| 110 | + * @param x the element to remove. |
| 111 | + * @return the buffer itself |
| 112 | + */ |
| 113 | + def subtractOne (x: A): this.type = { |
| 114 | + val i = indexOf(x) |
| 115 | + if (i != -1) remove(i) |
| 116 | + this |
| 117 | + } |
| 118 | + |
| 119 | + /** Removes the first ''n'' elements of this buffer. |
| 120 | + * |
| 121 | + * @param n the number of elements to remove from the beginning |
| 122 | + * of this buffer. |
| 123 | + */ |
| 124 | + @deprecated("use dropInPlace instead", since = "2.13.4") |
| 125 | + def trimStart(n: Int): Unit = dropInPlace(n) |
| 126 | + |
| 127 | + /** Removes the last ''n'' elements of this buffer. |
| 128 | + * |
| 129 | + * @param n the number of elements to remove from the end |
| 130 | + * of this buffer. |
| 131 | + */ |
| 132 | + @deprecated("use dropRightInPlace instead", since = "2.13.4") |
| 133 | + def trimEnd(n: Int): Unit = dropRightInPlace(n) |
| 134 | + |
| 135 | + def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type |
| 136 | + |
| 137 | + // +=, ++=, clear inherited from Growable |
| 138 | + // Per remark of @ichoran, we should preferably not have these: |
| 139 | + // |
| 140 | + // def +=:(elem: A): this.type = { insert(0, elem); this } |
| 141 | + // def +=:(elem1: A, elem2: A, elems: A*): this.type = elem1 +=: elem2 +=: elems ++=: this |
| 142 | + // def ++=:(elems: IterableOnce[A]): this.type = { insertAll(0, elems); this } |
| 143 | + |
| 144 | + def dropInPlace(n: Int): this.type = { remove(0, normalized(n)); this } |
| 145 | + def dropRightInPlace(n: Int): this.type = { |
| 146 | + val norm = normalized(n) |
| 147 | + remove(length - norm, norm) |
| 148 | + this |
| 149 | + } |
| 150 | + def takeInPlace(n: Int): this.type = { |
| 151 | + val norm = normalized(n) |
| 152 | + remove(norm, length - norm) |
| 153 | + this |
| 154 | + } |
| 155 | + def takeRightInPlace(n: Int): this.type = { remove(0, length - normalized(n)); this } |
| 156 | + def sliceInPlace(start: Int, end: Int): this.type = takeInPlace(end).dropInPlace(start) |
| 157 | + private def normalized(n: Int): Int = math.min(math.max(n, 0), length) |
| 158 | + |
| 159 | + def dropWhileInPlace(p: A => Boolean): this.type = { |
| 160 | + val idx = indexWhere(!p(_)) |
| 161 | + if (idx < 0) { clear(); this } else dropInPlace(idx) |
| 162 | + } |
| 163 | + def takeWhileInPlace(p: A => Boolean): this.type = { |
| 164 | + val idx = indexWhere(!p(_)) |
| 165 | + if (idx < 0) this else takeInPlace(idx) |
| 166 | + } |
| 167 | + def padToInPlace(len: Int, elem: A): this.type = { |
| 168 | + while (length < len) +=(elem) |
| 169 | + this |
| 170 | + } |
| 171 | + |
| 172 | + @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") |
| 173 | + override protected[this] def stringPrefix = "Buffer" |
| 174 | +} |
| 175 | + |
| 176 | +trait IndexedBuffer[A] extends IndexedSeq[A] |
| 177 | + with IndexedSeqOps[A, IndexedBuffer, IndexedBuffer[A]] |
| 178 | + with Buffer[A] |
| 179 | + with IterableFactoryDefaults[A, IndexedBuffer] { |
| 180 | + |
| 181 | + override def iterableFactory: SeqFactory[IndexedBuffer] = IndexedBuffer |
| 182 | + |
| 183 | + def flatMapInPlace(f: A => IterableOnce[A]): this.type = { |
| 184 | + // There's scope for a better implementation which copies elements in place. |
| 185 | + var i = 0 |
| 186 | + val s = size |
| 187 | + val newElems = new Array[IterableOnce[A]](s) |
| 188 | + while (i < s) { newElems(i) = f(this(i)); i += 1 } |
| 189 | + clear() |
| 190 | + i = 0 |
| 191 | + while (i < s) { ++=(newElems(i)); i += 1 } |
| 192 | + this |
| 193 | + } |
| 194 | + |
| 195 | + def filterInPlace(p: A => Boolean): this.type = { |
| 196 | + var i, j = 0 |
| 197 | + while (i < size) { |
| 198 | + if (p(apply(i))) { |
| 199 | + if (i != j) { |
| 200 | + this(j) = this(i) |
| 201 | + } |
| 202 | + j += 1 |
| 203 | + } |
| 204 | + i += 1 |
| 205 | + } |
| 206 | + |
| 207 | + if (i == j) this else takeInPlace(j) |
| 208 | + } |
| 209 | + |
| 210 | + def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type = { |
| 211 | + val replaced0 = math.min(math.max(replaced, 0), length) |
| 212 | + val i = math.min(math.max(from, 0), length) |
| 213 | + var j = 0 |
| 214 | + val iter = patch.iterator |
| 215 | + while (iter.hasNext && j < replaced0 && i + j < length) { |
| 216 | + update(i + j, iter.next()) |
| 217 | + j += 1 |
| 218 | + } |
| 219 | + if (iter.hasNext) insertAll(i + j, iter) |
| 220 | + else if (j < replaced0) remove(i + j, math.min(replaced0 - j, length - i - j)) |
| 221 | + this |
| 222 | + } |
| 223 | +} |
| 224 | + |
| 225 | +@SerialVersionUID(3L) |
| 226 | +object Buffer extends SeqFactory.Delegate[Buffer](ArrayBuffer) |
| 227 | + |
| 228 | +@SerialVersionUID(3L) |
| 229 | +object IndexedBuffer extends SeqFactory.Delegate[IndexedBuffer](ArrayBuffer) |
| 230 | + |
| 231 | +/** Explicit instantiation of the `Buffer` trait to reduce class file size in subclasses. */ |
| 232 | +abstract class AbstractBuffer[A] extends AbstractSeq[A] with Buffer[A] |
0 commit comments