diff src/clojure/lang/PersistentVector.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojure/lang/PersistentVector.java	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,748 @@
     1.4 +/**
     1.5 + *   Copyright (c) Rich Hickey. All rights reserved.
     1.6 + *   The use and distribution terms for this software are covered by the
     1.7 + *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
     1.8 + *   which can be found in the file epl-v10.html at the root of this distribution.
     1.9 + *   By using this software in any fashion, you are agreeing to be bound by
    1.10 + * 	 the terms of this license.
    1.11 + *   You must not remove this notice, or any other, from this software.
    1.12 + **/
    1.13 +
    1.14 +/* rich Jul 5, 2007 */
    1.15 +
    1.16 +package clojure.lang;
    1.17 +
    1.18 +import java.io.Serializable;
    1.19 +import java.util.List;
    1.20 +import java.util.concurrent.atomic.AtomicReference;
    1.21 +
    1.22 +public class PersistentVector extends APersistentVector implements IObj, IEditableCollection{
    1.23 +
    1.24 +static class Node implements Serializable {
    1.25 +	transient final AtomicReference<Thread> edit;
    1.26 +	final Object[] array;
    1.27 +
    1.28 +	Node(AtomicReference<Thread> edit, Object[] array){
    1.29 +		this.edit = edit;
    1.30 +		this.array = array;
    1.31 +	}
    1.32 +
    1.33 +	Node(AtomicReference<Thread> edit){
    1.34 +		this.edit = edit;
    1.35 +		this.array = new Object[32];
    1.36 +	}
    1.37 +}
    1.38 +
    1.39 +final static AtomicReference<Thread> NOEDIT = new AtomicReference<Thread>(null);
    1.40 +final static Node EMPTY_NODE = new Node(NOEDIT, new Object[32]);
    1.41 +
    1.42 +final int cnt;
    1.43 +final int shift;
    1.44 +final Node root;
    1.45 +final Object[] tail;
    1.46 +final IPersistentMap _meta;
    1.47 +
    1.48 +
    1.49 +public final static PersistentVector EMPTY = new PersistentVector(0, 5, EMPTY_NODE, new Object[]{});
    1.50 +
    1.51 +static public PersistentVector create(ISeq items){
    1.52 +	TransientVector ret = EMPTY.asTransient();
    1.53 +	for(; items != null; items = items.next())
    1.54 +		ret = ret.conj(items.first());
    1.55 +	return ret.persistent();
    1.56 +}
    1.57 +
    1.58 +static public PersistentVector create(List items){
    1.59 +	TransientVector ret = EMPTY.asTransient();
    1.60 +	for(Object item : items)
    1.61 +		ret = ret.conj(item);
    1.62 +	return ret.persistent();
    1.63 +}
    1.64 +
    1.65 +static public PersistentVector create(Object... items){
    1.66 +	TransientVector ret = EMPTY.asTransient();
    1.67 +	for(Object item : items)
    1.68 +		ret = ret.conj(item);
    1.69 +	return ret.persistent();
    1.70 +}
    1.71 +
    1.72 +PersistentVector(int cnt, int shift, Node root, Object[] tail){
    1.73 +	this._meta = null;
    1.74 +	this.cnt = cnt;
    1.75 +	this.shift = shift;
    1.76 +	this.root = root;
    1.77 +	this.tail = tail;
    1.78 +}
    1.79 +
    1.80 +
    1.81 +PersistentVector(IPersistentMap meta, int cnt, int shift, Node root, Object[] tail){
    1.82 +	this._meta = meta;
    1.83 +	this.cnt = cnt;
    1.84 +	this.shift = shift;
    1.85 +	this.root = root;
    1.86 +	this.tail = tail;
    1.87 +}
    1.88 +
    1.89 +public TransientVector asTransient(){
    1.90 +	return new TransientVector(this);
    1.91 +}
    1.92 +
    1.93 +final int tailoff(){
    1.94 +	if(cnt < 32)
    1.95 +		return 0;
    1.96 +	return ((cnt - 1) >>> 5) << 5;
    1.97 +}
    1.98 +
    1.99 +public Object[] arrayFor(int i){
   1.100 +	if(i >= 0 && i < cnt)
   1.101 +		{
   1.102 +		if(i >= tailoff())
   1.103 +			return tail;
   1.104 +		Node node = root;
   1.105 +		for(int level = shift; level > 0; level -= 5)
   1.106 +			node = (Node) node.array[(i >>> level) & 0x01f];
   1.107 +		return node.array;
   1.108 +		}
   1.109 +	throw new IndexOutOfBoundsException();
   1.110 +}
   1.111 +
   1.112 +public Object nth(int i){
   1.113 +	Object[] node = arrayFor(i);
   1.114 +	return node[i & 0x01f];
   1.115 +}
   1.116 +
   1.117 +public Object nth(int i, Object notFound){
   1.118 +	if(i >= 0 && i < cnt)
   1.119 +		return nth(i);
   1.120 +	return notFound;
   1.121 +}
   1.122 +
   1.123 +public PersistentVector assocN(int i, Object val){
   1.124 +	if(i >= 0 && i < cnt)
   1.125 +		{
   1.126 +		if(i >= tailoff())
   1.127 +			{
   1.128 +			Object[] newTail = new Object[tail.length];
   1.129 +			System.arraycopy(tail, 0, newTail, 0, tail.length);
   1.130 +			newTail[i & 0x01f] = val;
   1.131 +
   1.132 +			return new PersistentVector(meta(), cnt, shift, root, newTail);
   1.133 +			}
   1.134 +
   1.135 +		return new PersistentVector(meta(), cnt, shift, doAssoc(shift, root, i, val), tail);
   1.136 +		}
   1.137 +	if(i == cnt)
   1.138 +		return cons(val);
   1.139 +	throw new IndexOutOfBoundsException();
   1.140 +}
   1.141 +
   1.142 +private static Node doAssoc(int level, Node node, int i, Object val){
   1.143 +	Node ret = new Node(node.edit,node.array.clone());
   1.144 +	if(level == 0)
   1.145 +		{
   1.146 +		ret.array[i & 0x01f] = val;
   1.147 +		}
   1.148 +	else
   1.149 +		{
   1.150 +		int subidx = (i >>> level) & 0x01f;
   1.151 +		ret.array[subidx] = doAssoc(level - 5, (Node) node.array[subidx], i, val);
   1.152 +		}
   1.153 +	return ret;
   1.154 +}
   1.155 +
   1.156 +public int count(){
   1.157 +	return cnt;
   1.158 +}
   1.159 +
   1.160 +public PersistentVector withMeta(IPersistentMap meta){
   1.161 +	return new PersistentVector(meta, cnt, shift, root, tail);
   1.162 +}
   1.163 +
   1.164 +public IPersistentMap meta(){
   1.165 +	return _meta;
   1.166 +}
   1.167 +
   1.168 +
   1.169 +public PersistentVector cons(Object val){
   1.170 +	int i = cnt;
   1.171 +	//room in tail?
   1.172 +//	if(tail.length < 32)
   1.173 +	if(cnt - tailoff() < 32)
   1.174 +		{
   1.175 +		Object[] newTail = new Object[tail.length + 1];
   1.176 +		System.arraycopy(tail, 0, newTail, 0, tail.length);
   1.177 +		newTail[tail.length] = val;
   1.178 +		return new PersistentVector(meta(), cnt + 1, shift, root, newTail);
   1.179 +		}
   1.180 +	//full tail, push into tree
   1.181 +	Node newroot;
   1.182 +	Node tailnode = new Node(root.edit,tail);
   1.183 +	int newshift = shift;
   1.184 +	//overflow root?
   1.185 +	if((cnt >>> 5) > (1 << shift))
   1.186 +		{
   1.187 +		newroot = new Node(root.edit);
   1.188 +		newroot.array[0] = root;
   1.189 +		newroot.array[1] = newPath(root.edit,shift, tailnode);
   1.190 +		newshift += 5;
   1.191 +		}
   1.192 +	else
   1.193 +		newroot = pushTail(shift, root, tailnode);
   1.194 +	return new PersistentVector(meta(), cnt + 1, newshift, newroot, new Object[]{val});
   1.195 +}
   1.196 +
   1.197 +private Node pushTail(int level, Node parent, Node tailnode){
   1.198 +	//if parent is leaf, insert node,
   1.199 +	// else does it map to an existing child? -> nodeToInsert = pushNode one more level
   1.200 +	// else alloc new path
   1.201 +	//return  nodeToInsert placed in copy of parent
   1.202 +	int subidx = ((cnt - 1) >>> level) & 0x01f;
   1.203 +	Node ret = new Node(parent.edit, parent.array.clone());
   1.204 +	Node nodeToInsert;
   1.205 +	if(level == 5)
   1.206 +		{
   1.207 +		nodeToInsert = tailnode;
   1.208 +		}
   1.209 +	else
   1.210 +		{
   1.211 +		Node child = (Node) parent.array[subidx];
   1.212 +		nodeToInsert = (child != null)?
   1.213 +		                pushTail(level-5,child, tailnode)
   1.214 +		                :newPath(root.edit,level-5, tailnode);
   1.215 +		}
   1.216 +	ret.array[subidx] = nodeToInsert;
   1.217 +	return ret;
   1.218 +}
   1.219 +
   1.220 +private static Node newPath(AtomicReference<Thread> edit,int level, Node node){
   1.221 +	if(level == 0)
   1.222 +		return node;
   1.223 +	Node ret = new Node(edit);
   1.224 +	ret.array[0] = newPath(edit, level - 5, node);
   1.225 +	return ret;
   1.226 +}
   1.227 +
   1.228 +public IChunkedSeq chunkedSeq(){
   1.229 +	if(count() == 0)
   1.230 +		return null;
   1.231 +	return new ChunkedSeq(this,0,0);
   1.232 +}
   1.233 +
   1.234 +public ISeq seq(){
   1.235 +	return chunkedSeq();
   1.236 +}
   1.237 +
   1.238 +static public final class ChunkedSeq extends ASeq implements IChunkedSeq{
   1.239 +
   1.240 +	public final PersistentVector vec;
   1.241 +	final Object[] node;
   1.242 +	final int i;
   1.243 +	public final int offset;
   1.244 +
   1.245 +	public ChunkedSeq(PersistentVector vec, int i, int offset){
   1.246 +		this.vec = vec;
   1.247 +		this.i = i;
   1.248 +		this.offset = offset;
   1.249 +		this.node = vec.arrayFor(i);
   1.250 +	}
   1.251 +
   1.252 +	ChunkedSeq(IPersistentMap meta, PersistentVector vec, Object[] node, int i, int offset){
   1.253 +		super(meta);
   1.254 +		this.vec = vec;
   1.255 +		this.node = node;
   1.256 +		this.i = i;
   1.257 +		this.offset = offset;
   1.258 +	}
   1.259 +
   1.260 +	ChunkedSeq(PersistentVector vec, Object[] node, int i, int offset){
   1.261 +		this.vec = vec;
   1.262 +		this.node = node;
   1.263 +		this.i = i;
   1.264 +		this.offset = offset;
   1.265 +	}
   1.266 +
   1.267 +	public IChunk chunkedFirst() throws Exception{
   1.268 +		return new ArrayChunk(node, offset);
   1.269 +		}
   1.270 +
   1.271 +	public ISeq chunkedNext(){
   1.272 +		if(i + node.length < vec.cnt)
   1.273 +			return new ChunkedSeq(vec,i+ node.length,0);
   1.274 +		return null;
   1.275 +		}
   1.276 +
   1.277 +	public ISeq chunkedMore(){
   1.278 +		ISeq s = chunkedNext();
   1.279 +		if(s == null)
   1.280 +			return PersistentList.EMPTY;
   1.281 +		return s;
   1.282 +	}
   1.283 +
   1.284 +	public Obj withMeta(IPersistentMap meta){
   1.285 +		if(meta == this._meta)
   1.286 +			return this;
   1.287 +		return new ChunkedSeq(meta, vec, node, i, offset);
   1.288 +	}
   1.289 +
   1.290 +	public Object first(){
   1.291 +		return node[offset];
   1.292 +	}
   1.293 +
   1.294 +	public ISeq next(){
   1.295 +		if(offset + 1 < node.length)
   1.296 +			return new ChunkedSeq(vec, node, i, offset + 1);
   1.297 +		return chunkedNext();
   1.298 +	}
   1.299 +}
   1.300 +
   1.301 +public IPersistentCollection empty(){
   1.302 +	return EMPTY.withMeta(meta());
   1.303 +}
   1.304 +
   1.305 +//private Node pushTail(int level, Node node, Object[] tailNode, Box expansion){
   1.306 +//	Object newchild;
   1.307 +//	if(level == 0)
   1.308 +//		{
   1.309 +//		newchild = tailNode;
   1.310 +//		}
   1.311 +//	else
   1.312 +//		{
   1.313 +//		newchild = pushTail(level - 5, (Object[]) arr[arr.length - 1], tailNode, expansion);
   1.314 +//		if(expansion.val == null)
   1.315 +//			{
   1.316 +//			Object[] ret = arr.clone();
   1.317 +//			ret[arr.length - 1] = newchild;
   1.318 +//			return ret;
   1.319 +//			}
   1.320 +//		else
   1.321 +//			newchild = expansion.val;
   1.322 +//		}
   1.323 +//	//expansion
   1.324 +//	if(arr.length == 32)
   1.325 +//		{
   1.326 +//		expansion.val = new Object[]{newchild};
   1.327 +//		return arr;
   1.328 +//		}
   1.329 +//	Object[] ret = new Object[arr.length + 1];
   1.330 +//	System.arraycopy(arr, 0, ret, 0, arr.length);
   1.331 +//	ret[arr.length] = newchild;
   1.332 +//	expansion.val = null;
   1.333 +//	return ret;
   1.334 +//}
   1.335 +
   1.336 +public PersistentVector pop(){
   1.337 +	if(cnt == 0)
   1.338 +		throw new IllegalStateException("Can't pop empty vector");
   1.339 +	if(cnt == 1)
   1.340 +		return EMPTY.withMeta(meta());
   1.341 +	//if(tail.length > 1)
   1.342 +	if(cnt-tailoff() > 1)
   1.343 +		{
   1.344 +		Object[] newTail = new Object[tail.length - 1];
   1.345 +		System.arraycopy(tail, 0, newTail, 0, newTail.length);
   1.346 +		return new PersistentVector(meta(), cnt - 1, shift, root, newTail);
   1.347 +		}
   1.348 +	Object[] newtail = arrayFor(cnt - 2);
   1.349 +
   1.350 +	Node newroot = popTail(shift, root);
   1.351 +	int newshift = shift;
   1.352 +	if(newroot == null)
   1.353 +		{
   1.354 +		newroot = EMPTY_NODE;
   1.355 +		}
   1.356 +	if(shift > 5 && newroot.array[1] == null)
   1.357 +		{
   1.358 +		newroot = (Node) newroot.array[0];
   1.359 +		newshift -= 5;
   1.360 +		}
   1.361 +	return new PersistentVector(meta(), cnt - 1, newshift, newroot, newtail);
   1.362 +}
   1.363 +
   1.364 +private Node popTail(int level, Node node){
   1.365 +	int subidx = ((cnt-2) >>> level) & 0x01f;
   1.366 +	if(level > 5)
   1.367 +		{
   1.368 +		Node newchild = popTail(level - 5, (Node) node.array[subidx]);
   1.369 +		if(newchild == null && subidx == 0)
   1.370 +			return null;
   1.371 +		else
   1.372 +			{
   1.373 +			Node ret = new Node(root.edit, node.array.clone());
   1.374 +			ret.array[subidx] = newchild;
   1.375 +			return ret;
   1.376 +			}
   1.377 +		}
   1.378 +	else if(subidx == 0)
   1.379 +		return null;
   1.380 +	else
   1.381 +		{
   1.382 +		Node ret = new Node(root.edit, node.array.clone());
   1.383 +		ret.array[subidx] = null;
   1.384 +		return ret;
   1.385 +		}
   1.386 +}
   1.387 +
   1.388 +static final class TransientVector extends AFn implements ITransientVector, Counted{
   1.389 +	int cnt;
   1.390 +	int shift;
   1.391 +	Node root;
   1.392 +	Object[] tail;
   1.393 +
   1.394 +	TransientVector(int cnt, int shift, Node root, Object[] tail){
   1.395 +		this.cnt = cnt;
   1.396 +		this.shift = shift;
   1.397 +		this.root = root;
   1.398 +		this.tail = tail;
   1.399 +	}
   1.400 +
   1.401 +	TransientVector(PersistentVector v){
   1.402 +		this(v.cnt, v.shift, editableRoot(v.root), editableTail(v.tail));
   1.403 +	}
   1.404 +
   1.405 +	public int count(){
   1.406 +		ensureEditable();
   1.407 +		return cnt;
   1.408 +	}
   1.409 +	
   1.410 +	Node ensureEditable(Node node){
   1.411 +		if(node.edit == root.edit)
   1.412 +			return node;
   1.413 +		return new Node(root.edit, node.array.clone());
   1.414 +	}
   1.415 +
   1.416 +	void ensureEditable(){
   1.417 +		Thread owner = root.edit.get();
   1.418 +		if(owner == Thread.currentThread())
   1.419 +			return;
   1.420 +		if(owner != null)
   1.421 +			throw new IllegalAccessError("Transient used by non-owner thread");
   1.422 +		throw new IllegalAccessError("Transient used after persistent! call");
   1.423 +
   1.424 +//		root = editableRoot(root);
   1.425 +//		tail = editableTail(tail);
   1.426 +	}
   1.427 +
   1.428 +	static Node editableRoot(Node node){
   1.429 +		return new Node(new AtomicReference<Thread>(Thread.currentThread()), node.array.clone());
   1.430 +	}
   1.431 +
   1.432 +	public PersistentVector persistent(){
   1.433 +		ensureEditable();
   1.434 +//		Thread owner = root.edit.get();
   1.435 +//		if(owner != null && owner != Thread.currentThread())
   1.436 +//			{
   1.437 +//			throw new IllegalAccessError("Mutation release by non-owner thread");
   1.438 +//			}
   1.439 +		root.edit.set(null);
   1.440 +		Object[] trimmedTail = new Object[cnt-tailoff()];
   1.441 +		System.arraycopy(tail,0,trimmedTail,0,trimmedTail.length);
   1.442 +		return new PersistentVector(cnt, shift, root, trimmedTail);
   1.443 +	}
   1.444 +
   1.445 +	static Object[] editableTail(Object[] tl){
   1.446 +		Object[] ret = new Object[32];
   1.447 +		System.arraycopy(tl,0,ret,0,tl.length);
   1.448 +		return ret;
   1.449 +	}
   1.450 +
   1.451 +	public TransientVector conj(Object val){
   1.452 +		ensureEditable();
   1.453 +		int i = cnt;
   1.454 +		//room in tail?
   1.455 +		if(i - tailoff() < 32)
   1.456 +			{
   1.457 +			tail[i & 0x01f] = val;
   1.458 +			++cnt;
   1.459 +			return this;
   1.460 +			}
   1.461 +		//full tail, push into tree
   1.462 +		Node newroot;
   1.463 +		Node tailnode = new Node(root.edit, tail);
   1.464 +		tail = new Object[32];
   1.465 +		tail[0] = val;
   1.466 +		int newshift = shift;
   1.467 +		//overflow root?
   1.468 +		if((cnt >>> 5) > (1 << shift))
   1.469 +			{
   1.470 +			newroot = new Node(root.edit);
   1.471 +			newroot.array[0] = root;
   1.472 +			newroot.array[1] = newPath(root.edit,shift, tailnode);
   1.473 +			newshift += 5;
   1.474 +			}
   1.475 +		else
   1.476 +			newroot = pushTail(shift, root, tailnode);
   1.477 +		root = newroot;
   1.478 +		shift = newshift;
   1.479 +		++cnt;
   1.480 +		return this;
   1.481 +	}
   1.482 +
   1.483 +	private Node pushTail(int level, Node parent, Node tailnode){
   1.484 +		//if parent is leaf, insert node,
   1.485 +		// else does it map to an existing child? -> nodeToInsert = pushNode one more level
   1.486 +		// else alloc new path
   1.487 +		//return  nodeToInsert placed in parent
   1.488 +		parent = ensureEditable(parent);
   1.489 +		int subidx = ((cnt - 1) >>> level) & 0x01f;
   1.490 +		Node ret = parent;
   1.491 +		Node nodeToInsert;
   1.492 +		if(level == 5)
   1.493 +			{
   1.494 +			nodeToInsert = tailnode;
   1.495 +			}
   1.496 +		else
   1.497 +			{
   1.498 +			Node child = (Node) parent.array[subidx];
   1.499 +			nodeToInsert = (child != null) ?
   1.500 +			               pushTail(level - 5, child, tailnode)
   1.501 +			                               : newPath(root.edit, level - 5, tailnode);
   1.502 +			}
   1.503 +		ret.array[subidx] = nodeToInsert;
   1.504 +		return ret;
   1.505 +	}
   1.506 +
   1.507 +	final private int tailoff(){
   1.508 +		if(cnt < 32)
   1.509 +			return 0;
   1.510 +		return ((cnt-1) >>> 5) << 5;
   1.511 +	}
   1.512 +
   1.513 +	private Object[] arrayFor(int i){
   1.514 +		if(i >= 0 && i < cnt)
   1.515 +			{
   1.516 +			if(i >= tailoff())
   1.517 +				return tail;
   1.518 +			Node node = root;
   1.519 +			for(int level = shift; level > 0; level -= 5)
   1.520 +				node = (Node) node.array[(i >>> level) & 0x01f];
   1.521 +			return node.array;
   1.522 +			}
   1.523 +		throw new IndexOutOfBoundsException();
   1.524 +	}
   1.525 +
   1.526 +	public Object valAt(Object key){
   1.527 +		//note - relies on ensureEditable in 2-arg valAt
   1.528 +		return valAt(key, null);
   1.529 +	}
   1.530 +
   1.531 +	public Object valAt(Object key, Object notFound){
   1.532 +		ensureEditable();
   1.533 +		if(Util.isInteger(key))
   1.534 +			{
   1.535 +			int i = ((Number) key).intValue();
   1.536 +			if(i >= 0 && i < cnt)
   1.537 +				return nth(i);
   1.538 +			}
   1.539 +		return notFound;
   1.540 +	}
   1.541 +
   1.542 +	public Object invoke(Object arg1) throws Exception{
   1.543 +		//note - relies on ensureEditable in nth
   1.544 +		if(Util.isInteger(arg1))
   1.545 +			return nth(((Number) arg1).intValue());
   1.546 +		throw new IllegalArgumentException("Key must be integer");
   1.547 +	}
   1.548 +
   1.549 +	public Object nth(int i){
   1.550 +		ensureEditable();
   1.551 +		Object[] node = arrayFor(i);
   1.552 +		return node[i & 0x01f];
   1.553 +	}
   1.554 +
   1.555 +	public Object nth(int i, Object notFound){
   1.556 +		if(i >= 0 && i < count())
   1.557 +			return nth(i);
   1.558 +		return notFound;
   1.559 +	}
   1.560 +
   1.561 +	public TransientVector assocN(int i, Object val){
   1.562 +		ensureEditable();
   1.563 +		if(i >= 0 && i < cnt)
   1.564 +			{
   1.565 +			if(i >= tailoff())
   1.566 +				{
   1.567 +				tail[i & 0x01f] = val;
   1.568 +				return this;
   1.569 +				}
   1.570 +
   1.571 +			root = doAssoc(shift, root, i, val);
   1.572 +			return this;
   1.573 +			}
   1.574 +		if(i == cnt)
   1.575 +			return conj(val);
   1.576 +		throw new IndexOutOfBoundsException();
   1.577 +	}
   1.578 +
   1.579 +	public TransientVector assoc(Object key, Object val){
   1.580 +		//note - relies on ensureEditable in assocN
   1.581 +		if(Util.isInteger(key))
   1.582 +			{
   1.583 +			int i = ((Number) key).intValue();
   1.584 +			return assocN(i, val);
   1.585 +			}
   1.586 +		throw new IllegalArgumentException("Key must be integer");
   1.587 +	}
   1.588 +
   1.589 +	private Node doAssoc(int level, Node node, int i, Object val){
   1.590 +		node = ensureEditable(node);
   1.591 +		Node ret = node;
   1.592 +		if(level == 0)
   1.593 +			{
   1.594 +			ret.array[i & 0x01f] = val;
   1.595 +			}
   1.596 +		else
   1.597 +			{
   1.598 +			int subidx = (i >>> level) & 0x01f;
   1.599 +			ret.array[subidx] = doAssoc(level - 5, (Node) node.array[subidx], i, val);
   1.600 +			}
   1.601 +		return ret;
   1.602 +	}
   1.603 +
   1.604 +	public TransientVector pop(){
   1.605 +		ensureEditable();
   1.606 +		if(cnt == 0)
   1.607 +			throw new IllegalStateException("Can't pop empty vector");
   1.608 +		if(cnt == 1)
   1.609 +			{
   1.610 +			cnt = 0;
   1.611 +			return this;
   1.612 +			}
   1.613 +		int i = cnt - 1;
   1.614 +		//pop in tail?
   1.615 +		if((i & 0x01f) > 0)
   1.616 +			{
   1.617 +			--cnt;
   1.618 +			return this;
   1.619 +			}
   1.620 +
   1.621 +		Object[] newtail = arrayFor(cnt - 2);
   1.622 +
   1.623 +		Node newroot = popTail(shift, root);
   1.624 +		int newshift = shift;
   1.625 +		if(newroot == null)
   1.626 +			{
   1.627 +			newroot = new Node(root.edit);
   1.628 +			}
   1.629 +		if(shift > 5 && newroot.array[1] == null)
   1.630 +			{
   1.631 +			newroot = ensureEditable((Node) newroot.array[0]);
   1.632 +			newshift -= 5;
   1.633 +			}
   1.634 +		root = newroot;
   1.635 +		shift = newshift;
   1.636 +		--cnt;
   1.637 +		tail = newtail;
   1.638 +		return this;
   1.639 +	}
   1.640 +
   1.641 +	private Node popTail(int level, Node node){
   1.642 +		node = ensureEditable(node);
   1.643 +		int subidx = ((cnt - 2) >>> level) & 0x01f;
   1.644 +		if(level > 5)
   1.645 +			{
   1.646 +			Node newchild = popTail(level - 5, (Node) node.array[subidx]);
   1.647 +			if(newchild == null && subidx == 0)
   1.648 +				return null;
   1.649 +			else
   1.650 +				{
   1.651 +				Node ret = node;
   1.652 +				ret.array[subidx] = newchild;
   1.653 +				return ret;
   1.654 +				}
   1.655 +			}
   1.656 +		else if(subidx == 0)
   1.657 +			return null;
   1.658 +		else
   1.659 +			{
   1.660 +			Node ret = node;
   1.661 +			ret.array[subidx] = null;
   1.662 +			return ret;
   1.663 +			}
   1.664 +	}
   1.665 +}
   1.666 +/*
   1.667 +static public void main(String[] args){
   1.668 +	if(args.length != 3)
   1.669 +		{
   1.670 +		System.err.println("Usage: PersistentVector size writes reads");
   1.671 +		return;
   1.672 +		}
   1.673 +	int size = Integer.parseInt(args[0]);
   1.674 +	int writes = Integer.parseInt(args[1]);
   1.675 +	int reads = Integer.parseInt(args[2]);
   1.676 +//	Vector v = new Vector(size);
   1.677 +	ArrayList v = new ArrayList(size);
   1.678 +//	v.setSize(size);
   1.679 +	//PersistentArray p = new PersistentArray(size);
   1.680 +	PersistentVector p = PersistentVector.EMPTY;
   1.681 +//	MutableVector mp = p.mutable();
   1.682 +
   1.683 +	for(int i = 0; i < size; i++)
   1.684 +		{
   1.685 +		v.add(i);
   1.686 +//		v.set(i, i);
   1.687 +		//p = p.set(i, 0);
   1.688 +		p = p.cons(i);
   1.689 +//		mp = mp.conj(i);
   1.690 +		}
   1.691 +
   1.692 +	Random rand;
   1.693 +
   1.694 +	rand = new Random(42);
   1.695 +	long tv = 0;
   1.696 +	System.out.println("ArrayList");
   1.697 +	long startTime = System.nanoTime();
   1.698 +	for(int i = 0; i < writes; i++)
   1.699 +		{
   1.700 +		v.set(rand.nextInt(size), i);
   1.701 +		}
   1.702 +	for(int i = 0; i < reads; i++)
   1.703 +		{
   1.704 +		tv += (Integer) v.get(rand.nextInt(size));
   1.705 +		}
   1.706 +	long estimatedTime = System.nanoTime() - startTime;
   1.707 +	System.out.println("time: " + estimatedTime / 1000000);
   1.708 +	System.out.println("PersistentVector");
   1.709 +	rand = new Random(42);
   1.710 +	startTime = System.nanoTime();
   1.711 +	long tp = 0;
   1.712 +
   1.713 +//	PersistentVector oldp = p;
   1.714 +	//Random rand2 = new Random(42);
   1.715 +
   1.716 +	MutableVector mp = p.mutable();
   1.717 +	for(int i = 0; i < writes; i++)
   1.718 +		{
   1.719 +//		p = p.assocN(rand.nextInt(size), i);
   1.720 +		mp = mp.assocN(rand.nextInt(size), i);
   1.721 +//		mp = mp.assoc(rand.nextInt(size), i);
   1.722 +		//dummy set to force perverse branching
   1.723 +		//oldp =	oldp.assocN(rand2.nextInt(size), i);
   1.724 +		}
   1.725 +	for(int i = 0; i < reads; i++)
   1.726 +		{
   1.727 +//		tp += (Integer) p.nth(rand.nextInt(size));
   1.728 +		tp += (Integer) mp.nth(rand.nextInt(size));
   1.729 +		}
   1.730 +//	p = mp.immutable();
   1.731 +	//mp.cons(42);
   1.732 +	estimatedTime = System.nanoTime() - startTime;
   1.733 +	System.out.println("time: " + estimatedTime / 1000000);
   1.734 +	for(int i = 0; i < size / 2; i++)
   1.735 +		{
   1.736 +		mp = mp.pop();
   1.737 +//		p = p.pop();
   1.738 +		v.remove(v.size() - 1);
   1.739 +		}
   1.740 +	p = (PersistentVector) mp.immutable();
   1.741 +	//mp.pop();  //should fail
   1.742 +	for(int i = 0; i < size / 2; i++)
   1.743 +		{
   1.744 +		tp += (Integer) p.nth(i);
   1.745 +		tv += (Integer) v.get(i);
   1.746 +		}
   1.747 +	System.out.println("Done: " + tv + ", " + tp);
   1.748 +
   1.749 +}
   1.750 +//  */
   1.751 +}