djspiewak / scala-collections
- Source
- Commits
- Network (0)
- Issues (0)
- Downloads (1)
- Wiki (1)
- Graphs
-
Branch:
master
Daniel Spiewak (author)
Fri Feb 27 09:55:00 -0800 2009
commit 883d4606378fa879ed83120bdde7fa01d608f094
tree 5779872b1a6c549ad3fdd3b302b785d68ff9b33c
parent f60315249528fd84fc3f1e365636def2210a684b
tree 5779872b1a6c549ad3fdd3b302b785d68ff9b33c
parent f60315249528fd84fc3f1e365636def2210a684b
| ca63f092 » | djspiewak | 2008-11-13 | 1 | /** | |
| 2 | Copyright (c) 2007-2008, Rich Hickey | ||||
| 3 | All rights reserved. | ||||
| 4 | |||||
| 5 | Redistribution and use in source and binary forms, with or without | ||||
| 6 | modification, are permitted provided that the following conditions | ||||
| 7 | are met: | ||||
| 8 | |||||
| 9 | * Redistributions of source code must retain the above copyright | ||||
| 10 | notice, this list of conditions and the following disclaimer. | ||||
| 11 | |||||
| 12 | * Redistributions in binary form must reproduce the above | ||||
| 13 | copyright notice, this list of conditions and the following | ||||
| 14 | disclaimer in the documentation and/or other materials provided | ||||
| 15 | with the distribution. | ||||
| 16 | |||||
| 17 | * Neither the name of Clojure nor the names of its contributors | ||||
| 18 | may be used to endorse or promote products derived from this | ||||
| 19 | software without specific prior written permission. | ||||
| 20 | |||||
| 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||||
| 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||||
| 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
| 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||||
| 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||||
| 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| 32 | POSSIBILITY OF SUCH DAMAGE. | ||||
| 33 | **/ | ||||
| a802e4bd » | djspiewak | 2008-10-26 | 34 | ||
| 35 | package com.codecommit.collection | ||||
| 36 | |||||
| 37 | import Vector._ | ||||
| 38 | |||||
| 39 | /** | ||||
| 40 | * A straight port of Clojure's <code>PersistentVector</code> class. | ||||
| 41 | * | ||||
| 42 | * @author Daniel Spiewak | ||||
| 43 | * @author Rich Hickey | ||||
| 44 | */ | ||||
| 45 | class Vector[+T] private (val length: Int, shift: Int, root: Array[AnyRef], tail: Array[AnyRef]) extends RandomAccessSeq[T] { outer => | ||||
| 46 | private val tailOff = length - tail.length | ||||
| 47 | |||||
| 48 | /* | ||||
| 49 | * The design of this data structure inherantly requires heterogenous arrays. | ||||
| 50 | * It is *possible* to design around this, but the result is comparatively | ||||
| 51 | * quite inefficient. With respect to this fact, I have left the original | ||||
| 52 | * (somewhat dynamically-typed) implementation in place. | ||||
| 53 | */ | ||||
| 54 | |||||
| 55 | private[collection] def this() = this(0, 5, EmptyArray, EmptyArray) | ||||
| 56 | |||||
| 57 | def apply(i: Int): T = { | ||||
| 58 | if (i >= 0 && i < length) { | ||||
| 59 | if (i >= tailOff) { | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 60 | tail(i & 0x01f).asInstanceOf[T] | |
| a802e4bd » | djspiewak | 2008-10-26 | 61 | } else { | |
| 62 | var arr = root | ||||
| 63 | var level = shift | ||||
| 64 | |||||
| 65 | while (level > 0) { | ||||
| 66 | arr = arr((i >>> level) & 0x01f).asInstanceOf[Array[AnyRef]] | ||||
| 67 | level -= 5 | ||||
| 68 | } | ||||
| 69 | |||||
| 70 | arr(i & 0x01f).asInstanceOf[T] | ||||
| 71 | } | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 72 | } else throw new IndexOutOfBoundsException(i.toString) | |
| a802e4bd » | djspiewak | 2008-10-26 | 73 | } | |
| 74 | |||||
| 75 | def update[A >: T](i: Int, obj: A): Vector[A] = { | ||||
| 76 | if (i >= 0 && i < length) { | ||||
| 77 | if (i >= tailOff) { | ||||
| 78 | val newTail = new Array[AnyRef](tail.length) | ||||
| 79 | Array.copy(tail, 0, newTail, 0, tail.length) | ||||
| 80 | newTail(i & 0x01f) = obj.asInstanceOf[AnyRef] | ||||
| 81 | |||||
| 82 | new Vector[A](length, shift, root, newTail) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 83 | } else { | |
| a802e4bd » | djspiewak | 2008-10-26 | 84 | new Vector[A](length, shift, doAssoc(shift, root, i, obj), tail) | |
| 85 | } | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 86 | } else if (i == length) { | |
| 87 | this + obj | ||||
| a802e4bd » | djspiewak | 2008-10-26 | 88 | } else throw new IndexOutOfBoundsException(i.toString) | |
| 89 | } | ||||
| 90 | |||||
| 91 | private def doAssoc[A >: T](level: Int, arr: Array[AnyRef], i: Int, obj: A): Array[AnyRef] = { | ||||
| 92 | val ret = new Array[AnyRef](arr.length) | ||||
| 93 | Array.copy(arr, 0, ret, 0, arr.length) | ||||
| 94 | |||||
| 95 | if (level == 0) { | ||||
| 96 | ret(i & 0x01f) = obj.asInstanceOf[AnyRef] | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 97 | } else { | |
| a802e4bd » | djspiewak | 2008-10-26 | 98 | val subidx = (i >>> level) & 0x01f | |
| 99 | ret(subidx) = doAssoc(level - 5, arr(subidx).asInstanceOf[Array[AnyRef]], i, obj) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 100 | } | |
| a802e4bd » | djspiewak | 2008-10-26 | 101 | ||
| 102 | ret | ||||
| 103 | } | ||||
| 104 | |||||
| 105 | override def ++[A >: T](other: Iterable[A]) = other.foldLeft(this:Vector[A]) { _ + _ } | ||||
| 106 | |||||
| 107 | def +[A >: T](obj: A): Vector[A] = { | ||||
| 108 | if (tail.length < 32) { | ||||
| 109 | val newTail = new Array[AnyRef](tail.length + 1) | ||||
| 110 | Array.copy(tail, 0, newTail, 0, tail.length) | ||||
| 111 | newTail(tail.length) = obj.asInstanceOf[AnyRef] | ||||
| 112 | |||||
| 113 | new Vector[A](length + 1, shift, root, newTail) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 114 | } else { | |
| a802e4bd » | djspiewak | 2008-10-26 | 115 | var (newRoot, expansion) = pushTail(shift - 5, root, tail, null) | |
| 116 | var newShift = shift | ||||
| 117 | |||||
| 118 | if (expansion != null) { | ||||
| 119 | newRoot = array(newRoot, expansion) | ||||
| 120 | newShift += 5 | ||||
| 121 | } | ||||
| 122 | |||||
| 123 | new Vector[A](length + 1, newShift, newRoot, array(obj.asInstanceOf[AnyRef])) | ||||
| 124 | } | ||||
| 125 | } | ||||
| 126 | |||||
| 127 | private def pushTail(level: Int, arr: Array[AnyRef], tailNode: Array[AnyRef], expansion: AnyRef): (Array[AnyRef], AnyRef) = { | ||||
| 128 | val newChild = if (level == 0) tailNode else { | ||||
| 129 | val (newChild, subExpansion) = pushTail(level - 5, arr(arr.length - 1).asInstanceOf[Array[AnyRef]], tailNode, expansion) | ||||
| 130 | |||||
| 131 | if (subExpansion == null) { | ||||
| 132 | val ret = new Array[AnyRef](arr.length) | ||||
| 133 | Array.copy(arr, 0, ret, 0, arr.length) | ||||
| 134 | |||||
| 135 | ret(arr.length - 1) = newChild | ||||
| 136 | |||||
| 137 | return (ret, null) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 138 | } else subExpansion | |
| 139 | } | ||||
| a802e4bd » | djspiewak | 2008-10-26 | 140 | ||
| 141 | // expansion | ||||
| 142 | if (arr.length == 32) { | ||||
| 143 | (arr, array(newChild)) | ||||
| 144 | } else { | ||||
| 145 | val ret = new Array[AnyRef](arr.length + 1) | ||||
| 146 | Array.copy(arr, 0, ret, 0, arr.length) | ||||
| 147 | ret(arr.length) = newChild | ||||
| 148 | |||||
| 149 | (ret, null) | ||||
| 150 | } | ||||
| 151 | } | ||||
| 152 | |||||
| 153 | /** | ||||
| 154 | * Removes the <i>tail</i> element of this vector. | ||||
| 155 | */ | ||||
| 156 | def pop: Vector[T] = { | ||||
| 157 | if (length == 0) { | ||||
| 158 | throw new IllegalStateException("Can't pop empty vector") | ||||
| 159 | } else if (length == 1) { | ||||
| 160 | EmptyVector | ||||
| 161 | } else if (tail.length > 1) { | ||||
| 162 | val newTail = new Array[AnyRef](tail.length - 1) | ||||
| 163 | Array.copy(tail, 0, newTail, 0, newTail.length) | ||||
| 164 | |||||
| 165 | new Vector[T](length - 1, shift, root, newTail) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 166 | } else { | |
| a802e4bd » | djspiewak | 2008-10-26 | 167 | var (newRoot, pTail) = popTail(shift - 5, root, null) | |
| 168 | var newShift = shift | ||||
| 169 | |||||
| 170 | if (newRoot == null) { | ||||
| 171 | newRoot = EmptyArray | ||||
| 172 | } | ||||
| 173 | |||||
| 174 | if (shift > 5 && newRoot.length == 1) { | ||||
| 175 | newRoot = newRoot(0).asInstanceOf[Array[AnyRef]] | ||||
| 176 | newShift -= 5 | ||||
| 177 | } | ||||
| 178 | |||||
| 179 | new Vector[T](length - 1, newShift, newRoot, pTail.asInstanceOf[Array[AnyRef]]) | ||||
| 180 | } | ||||
| 181 | } | ||||
| 182 | |||||
| 183 | private def popTail(shift: Int, arr: Array[AnyRef], pTail: AnyRef): (Array[AnyRef], AnyRef) = { | ||||
| 184 | val newPTail = if (shift > 0) { | ||||
| 185 | val (newChild, subPTail) = popTail(shift - 5, arr(arr.length - 1).asInstanceOf[Array[AnyRef]], pTail) | ||||
| 186 | |||||
| 187 | if (newChild != null) { | ||||
| 188 | val ret = new Array[AnyRef](arr.length) | ||||
| 189 | Array.copy(arr, 0, ret, 0, arr.length) | ||||
| 190 | |||||
| 191 | ret(arr.length - 1) = newChild | ||||
| 192 | |||||
| 193 | return (ret, subPTail) | ||||
| cd9a39bf » | djspiewak | 2008-11-13 | 194 | } | |
| a802e4bd » | djspiewak | 2008-10-26 | 195 | subPTail | |
| cd9a39bf » | djspiewak | 2008-11-13 | 196 | } else if (shift == 0) { | |
| a802e4bd » | djspiewak | 2008-10-26 | 197 | arr(arr.length - 1) | |
| 198 | } else pTail | ||||
| 199 | |||||
| 200 | // contraction | ||||
| 201 | if (arr.length == 1) { | ||||
| 202 | (null, newPTail) | ||||
| 203 | } else { | ||||
| 204 | val ret = new Array[AnyRef](arr.length - 1) | ||||
| 205 | Array.copy(arr, 0, ret, 0, ret.length) | ||||
| 206 | |||||
| 207 | (ret, newPTail) | ||||
| 208 | } | ||||
| 209 | } | ||||
| 210 | |||||
| 211 | override def filter(p: (T)=>Boolean) = { | ||||
| 212 | var back = new Vector[T] | ||||
| 213 | var i = 0 | ||||
| 214 | |||||
| 215 | while (i < length) { | ||||
| 216 | val e = apply(i) | ||||
| 217 | if (p(e)) back += e | ||||
| 218 | |||||
| 219 | i += 1 | ||||
| 220 | } | ||||
| 221 | |||||
| 222 | back | ||||
| 223 | } | ||||
| 224 | |||||
| 225 | override def flatMap[A](f: (T)=>Iterable[A]) = { | ||||
| 226 | var back = new Vector[A] | ||||
| 227 | var i = 0 | ||||
| 228 | |||||
| 229 | while (i < length) { | ||||
| 230 | f(apply(i)) foreach { back += _ } | ||||
| 231 | i += 1 | ||||
| 232 | } | ||||
| 233 | |||||
| 234 | back | ||||
| 235 | } | ||||
| 236 | |||||
| 237 | override def map[A](f: (T)=>A) = { | ||||
| 238 | var back = new Vector[A] | ||||
| 239 | var i = 0 | ||||
| 240 | |||||
| 241 | while (i < length) { | ||||
| 242 | back += f(apply(i)) | ||||
| 243 | i += 1 | ||||
| 244 | } | ||||
| 245 | |||||
| 246 | back | ||||
| 247 | } | ||||
| 248 | |||||
| 249 | override def reverse: Vector[T] = new VectorProjection[T] { | ||||
| 250 | override val length = outer.length | ||||
| 251 | |||||
| 252 | override def apply(i: Int) = outer.apply(length - i - 1) | ||||
| 253 | } | ||||
| 254 | |||||
| 255 | override def subseq(from: Int, end: Int) = subVector(from, end) | ||||
| 256 | |||||
| 257 | def subVector(from: Int, end: Int): Vector[T] = { | ||||
| 258 | if (from < 0) { | ||||
| 259 | throw new IndexOutOfBoundsException(from.toString) | ||||
| 260 | } else if (end >= length) { | ||||
| 261 | throw new IndexOutOfBoundsException(end.toString) | ||||
| 262 | } else if (end <= from) { | ||||
| 263 | throw new IllegalArgumentException("Invalid range: " + from + ".." + end) | ||||
| 264 | } else { | ||||
| 265 | new VectorProjection[T] { | ||||
| 266 | override val length = end - from | ||||
| 267 | |||||
| 268 | override def apply(i: Int) = outer.apply(i + from) | ||||
| 269 | } | ||||
| 270 | } | ||||
| 271 | } | ||||
| 272 | |||||
| 273 | def zip[A](that: Vector[A]) = { | ||||
| 274 | var back = new Vector[(T, A)] | ||||
| 275 | var i = 0 | ||||
| 276 | |||||
| 277 | val limit = Math.min(length, that.length) | ||||
| 278 | while (i < limit) { | ||||
| 279 | back += (apply(i), that(i)) | ||||
| 280 | i += 1 | ||||
| 281 | } | ||||
| 282 | |||||
| 283 | back | ||||
| 284 | } | ||||
| 285 | |||||
| 286 | def zipWithIndex = { | ||||
| 287 | var back = new Vector[(T, Int)] | ||||
| 288 | var i = 0 | ||||
| 289 | |||||
| 290 | while (i < length) { | ||||
| 291 | back += (apply(i), i) | ||||
| 292 | i += 1 | ||||
| 293 | } | ||||
| 294 | |||||
| 295 | back | ||||
| 296 | } | ||||
| 297 | |||||
| 298 | override def equals(other: Any) = other match { | ||||
| 299 | case vec:Vector[T] => { | ||||
| 300 | var back = length == vec.length | ||||
| 301 | var i = 0 | ||||
| 302 | |||||
| 303 | while (i < length) { | ||||
| 304 | back &&= apply(i) == vec.apply(i) | ||||
| 305 | i += 1 | ||||
| 306 | } | ||||
| 307 | |||||
| 308 | back | ||||
| 309 | } | ||||
| 310 | |||||
| 311 | case _ => false | ||||
| 312 | } | ||||
| 313 | |||||
| 314 | override def hashCode = foldLeft(0) { _ ^ _.hashCode } | ||||
| 315 | } | ||||
| 316 | |||||
| 317 | object Vector { | ||||
| 318 | private[collection] val EmptyArray = new Array[AnyRef](0) | ||||
| 319 | |||||
| 320 | def apply[T](elems: T*) = elems.foldLeft(EmptyVector:Vector[T]) { _ + _ } | ||||
| 321 | |||||
| 322 | def unapplySeq[T](vec: Vector[T]): Option[Seq[T]] = Some(vec) | ||||
| 323 | |||||
| 324 | @inline | ||||
| 325 | private[collection] def array(elems: AnyRef*) = { | ||||
| 326 | val back = new Array[AnyRef](elems.length) | ||||
| 327 | Array.copy(elems, 0, back, 0, back.length) | ||||
| 328 | |||||
| 329 | back | ||||
| 330 | } | ||||
| 331 | } | ||||
| 332 | |||||
| 333 | object EmptyVector extends Vector[Nothing] | ||||
| 334 | |||||
| 335 | private[collection] abstract class VectorProjection[+T] extends Vector[T] { | ||||
| 336 | override val length: Int | ||||
| 337 | override def apply(i: Int): T | ||||
| 338 | |||||
| 339 | override def +[A >: T](e: A) = innerCopy + e | ||||
| 340 | |||||
| 341 | override def update[A >: T](i: Int, e: A) = { | ||||
| 342 | if (i < 0) { | ||||
| 343 | throw new IndexOutOfBoundsException(i.toString) | ||||
| 344 | } else if (i > length) { | ||||
| 345 | throw new IndexOutOfBoundsException(i.toString) | ||||
| 346 | } else innerCopy(i) = e | ||||
| 347 | } | ||||
| 348 | |||||
| 349 | private lazy val innerCopy = foldLeft(EmptyVector:Vector[T]) { _ + _ } | ||||
| 350 | } | ||||
| 351 | |||||
