view 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 source
1 /**
2 * Copyright (c) Rich Hickey. All rights reserved.
3 * The use and distribution terms for this software are covered by the
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
5 * which can be found in the file epl-v10.html at the root of this distribution.
6 * By using this software in any fashion, you are agreeing to be bound by
7 * the terms of this license.
8 * You must not remove this notice, or any other, from this software.
9 **/
11 /* rich Jul 5, 2007 */
13 package clojure.lang;
15 import java.io.Serializable;
16 import java.util.List;
17 import java.util.concurrent.atomic.AtomicReference;
19 public class PersistentVector extends APersistentVector implements IObj, IEditableCollection{
21 static class Node implements Serializable {
22 transient final AtomicReference<Thread> edit;
23 final Object[] array;
25 Node(AtomicReference<Thread> edit, Object[] array){
26 this.edit = edit;
27 this.array = array;
28 }
30 Node(AtomicReference<Thread> edit){
31 this.edit = edit;
32 this.array = new Object[32];
33 }
34 }
36 final static AtomicReference<Thread> NOEDIT = new AtomicReference<Thread>(null);
37 final static Node EMPTY_NODE = new Node(NOEDIT, new Object[32]);
39 final int cnt;
40 final int shift;
41 final Node root;
42 final Object[] tail;
43 final IPersistentMap _meta;
46 public final static PersistentVector EMPTY = new PersistentVector(0, 5, EMPTY_NODE, new Object[]{});
48 static public PersistentVector create(ISeq items){
49 TransientVector ret = EMPTY.asTransient();
50 for(; items != null; items = items.next())
51 ret = ret.conj(items.first());
52 return ret.persistent();
53 }
55 static public PersistentVector create(List items){
56 TransientVector ret = EMPTY.asTransient();
57 for(Object item : items)
58 ret = ret.conj(item);
59 return ret.persistent();
60 }
62 static public PersistentVector create(Object... items){
63 TransientVector ret = EMPTY.asTransient();
64 for(Object item : items)
65 ret = ret.conj(item);
66 return ret.persistent();
67 }
69 PersistentVector(int cnt, int shift, Node root, Object[] tail){
70 this._meta = null;
71 this.cnt = cnt;
72 this.shift = shift;
73 this.root = root;
74 this.tail = tail;
75 }
78 PersistentVector(IPersistentMap meta, int cnt, int shift, Node root, Object[] tail){
79 this._meta = meta;
80 this.cnt = cnt;
81 this.shift = shift;
82 this.root = root;
83 this.tail = tail;
84 }
86 public TransientVector asTransient(){
87 return new TransientVector(this);
88 }
90 final int tailoff(){
91 if(cnt < 32)
92 return 0;
93 return ((cnt - 1) >>> 5) << 5;
94 }
96 public Object[] arrayFor(int i){
97 if(i >= 0 && i < cnt)
98 {
99 if(i >= tailoff())
100 return tail;
101 Node node = root;
102 for(int level = shift; level > 0; level -= 5)
103 node = (Node) node.array[(i >>> level) & 0x01f];
104 return node.array;
105 }
106 throw new IndexOutOfBoundsException();
107 }
109 public Object nth(int i){
110 Object[] node = arrayFor(i);
111 return node[i & 0x01f];
112 }
114 public Object nth(int i, Object notFound){
115 if(i >= 0 && i < cnt)
116 return nth(i);
117 return notFound;
118 }
120 public PersistentVector assocN(int i, Object val){
121 if(i >= 0 && i < cnt)
122 {
123 if(i >= tailoff())
124 {
125 Object[] newTail = new Object[tail.length];
126 System.arraycopy(tail, 0, newTail, 0, tail.length);
127 newTail[i & 0x01f] = val;
129 return new PersistentVector(meta(), cnt, shift, root, newTail);
130 }
132 return new PersistentVector(meta(), cnt, shift, doAssoc(shift, root, i, val), tail);
133 }
134 if(i == cnt)
135 return cons(val);
136 throw new IndexOutOfBoundsException();
137 }
139 private static Node doAssoc(int level, Node node, int i, Object val){
140 Node ret = new Node(node.edit,node.array.clone());
141 if(level == 0)
142 {
143 ret.array[i & 0x01f] = val;
144 }
145 else
146 {
147 int subidx = (i >>> level) & 0x01f;
148 ret.array[subidx] = doAssoc(level - 5, (Node) node.array[subidx], i, val);
149 }
150 return ret;
151 }
153 public int count(){
154 return cnt;
155 }
157 public PersistentVector withMeta(IPersistentMap meta){
158 return new PersistentVector(meta, cnt, shift, root, tail);
159 }
161 public IPersistentMap meta(){
162 return _meta;
163 }
166 public PersistentVector cons(Object val){
167 int i = cnt;
168 //room in tail?
169 // if(tail.length < 32)
170 if(cnt - tailoff() < 32)
171 {
172 Object[] newTail = new Object[tail.length + 1];
173 System.arraycopy(tail, 0, newTail, 0, tail.length);
174 newTail[tail.length] = val;
175 return new PersistentVector(meta(), cnt + 1, shift, root, newTail);
176 }
177 //full tail, push into tree
178 Node newroot;
179 Node tailnode = new Node(root.edit,tail);
180 int newshift = shift;
181 //overflow root?
182 if((cnt >>> 5) > (1 << shift))
183 {
184 newroot = new Node(root.edit);
185 newroot.array[0] = root;
186 newroot.array[1] = newPath(root.edit,shift, tailnode);
187 newshift += 5;
188 }
189 else
190 newroot = pushTail(shift, root, tailnode);
191 return new PersistentVector(meta(), cnt + 1, newshift, newroot, new Object[]{val});
192 }
194 private Node pushTail(int level, Node parent, Node tailnode){
195 //if parent is leaf, insert node,
196 // else does it map to an existing child? -> nodeToInsert = pushNode one more level
197 // else alloc new path
198 //return nodeToInsert placed in copy of parent
199 int subidx = ((cnt - 1) >>> level) & 0x01f;
200 Node ret = new Node(parent.edit, parent.array.clone());
201 Node nodeToInsert;
202 if(level == 5)
203 {
204 nodeToInsert = tailnode;
205 }
206 else
207 {
208 Node child = (Node) parent.array[subidx];
209 nodeToInsert = (child != null)?
210 pushTail(level-5,child, tailnode)
211 :newPath(root.edit,level-5, tailnode);
212 }
213 ret.array[subidx] = nodeToInsert;
214 return ret;
215 }
217 private static Node newPath(AtomicReference<Thread> edit,int level, Node node){
218 if(level == 0)
219 return node;
220 Node ret = new Node(edit);
221 ret.array[0] = newPath(edit, level - 5, node);
222 return ret;
223 }
225 public IChunkedSeq chunkedSeq(){
226 if(count() == 0)
227 return null;
228 return new ChunkedSeq(this,0,0);
229 }
231 public ISeq seq(){
232 return chunkedSeq();
233 }
235 static public final class ChunkedSeq extends ASeq implements IChunkedSeq{
237 public final PersistentVector vec;
238 final Object[] node;
239 final int i;
240 public final int offset;
242 public ChunkedSeq(PersistentVector vec, int i, int offset){
243 this.vec = vec;
244 this.i = i;
245 this.offset = offset;
246 this.node = vec.arrayFor(i);
247 }
249 ChunkedSeq(IPersistentMap meta, PersistentVector vec, Object[] node, int i, int offset){
250 super(meta);
251 this.vec = vec;
252 this.node = node;
253 this.i = i;
254 this.offset = offset;
255 }
257 ChunkedSeq(PersistentVector vec, Object[] node, int i, int offset){
258 this.vec = vec;
259 this.node = node;
260 this.i = i;
261 this.offset = offset;
262 }
264 public IChunk chunkedFirst() throws Exception{
265 return new ArrayChunk(node, offset);
266 }
268 public ISeq chunkedNext(){
269 if(i + node.length < vec.cnt)
270 return new ChunkedSeq(vec,i+ node.length,0);
271 return null;
272 }
274 public ISeq chunkedMore(){
275 ISeq s = chunkedNext();
276 if(s == null)
277 return PersistentList.EMPTY;
278 return s;
279 }
281 public Obj withMeta(IPersistentMap meta){
282 if(meta == this._meta)
283 return this;
284 return new ChunkedSeq(meta, vec, node, i, offset);
285 }
287 public Object first(){
288 return node[offset];
289 }
291 public ISeq next(){
292 if(offset + 1 < node.length)
293 return new ChunkedSeq(vec, node, i, offset + 1);
294 return chunkedNext();
295 }
296 }
298 public IPersistentCollection empty(){
299 return EMPTY.withMeta(meta());
300 }
302 //private Node pushTail(int level, Node node, Object[] tailNode, Box expansion){
303 // Object newchild;
304 // if(level == 0)
305 // {
306 // newchild = tailNode;
307 // }
308 // else
309 // {
310 // newchild = pushTail(level - 5, (Object[]) arr[arr.length - 1], tailNode, expansion);
311 // if(expansion.val == null)
312 // {
313 // Object[] ret = arr.clone();
314 // ret[arr.length - 1] = newchild;
315 // return ret;
316 // }
317 // else
318 // newchild = expansion.val;
319 // }
320 // //expansion
321 // if(arr.length == 32)
322 // {
323 // expansion.val = new Object[]{newchild};
324 // return arr;
325 // }
326 // Object[] ret = new Object[arr.length + 1];
327 // System.arraycopy(arr, 0, ret, 0, arr.length);
328 // ret[arr.length] = newchild;
329 // expansion.val = null;
330 // return ret;
331 //}
333 public PersistentVector pop(){
334 if(cnt == 0)
335 throw new IllegalStateException("Can't pop empty vector");
336 if(cnt == 1)
337 return EMPTY.withMeta(meta());
338 //if(tail.length > 1)
339 if(cnt-tailoff() > 1)
340 {
341 Object[] newTail = new Object[tail.length - 1];
342 System.arraycopy(tail, 0, newTail, 0, newTail.length);
343 return new PersistentVector(meta(), cnt - 1, shift, root, newTail);
344 }
345 Object[] newtail = arrayFor(cnt - 2);
347 Node newroot = popTail(shift, root);
348 int newshift = shift;
349 if(newroot == null)
350 {
351 newroot = EMPTY_NODE;
352 }
353 if(shift > 5 && newroot.array[1] == null)
354 {
355 newroot = (Node) newroot.array[0];
356 newshift -= 5;
357 }
358 return new PersistentVector(meta(), cnt - 1, newshift, newroot, newtail);
359 }
361 private Node popTail(int level, Node node){
362 int subidx = ((cnt-2) >>> level) & 0x01f;
363 if(level > 5)
364 {
365 Node newchild = popTail(level - 5, (Node) node.array[subidx]);
366 if(newchild == null && subidx == 0)
367 return null;
368 else
369 {
370 Node ret = new Node(root.edit, node.array.clone());
371 ret.array[subidx] = newchild;
372 return ret;
373 }
374 }
375 else if(subidx == 0)
376 return null;
377 else
378 {
379 Node ret = new Node(root.edit, node.array.clone());
380 ret.array[subidx] = null;
381 return ret;
382 }
383 }
385 static final class TransientVector extends AFn implements ITransientVector, Counted{
386 int cnt;
387 int shift;
388 Node root;
389 Object[] tail;
391 TransientVector(int cnt, int shift, Node root, Object[] tail){
392 this.cnt = cnt;
393 this.shift = shift;
394 this.root = root;
395 this.tail = tail;
396 }
398 TransientVector(PersistentVector v){
399 this(v.cnt, v.shift, editableRoot(v.root), editableTail(v.tail));
400 }
402 public int count(){
403 ensureEditable();
404 return cnt;
405 }
407 Node ensureEditable(Node node){
408 if(node.edit == root.edit)
409 return node;
410 return new Node(root.edit, node.array.clone());
411 }
413 void ensureEditable(){
414 Thread owner = root.edit.get();
415 if(owner == Thread.currentThread())
416 return;
417 if(owner != null)
418 throw new IllegalAccessError("Transient used by non-owner thread");
419 throw new IllegalAccessError("Transient used after persistent! call");
421 // root = editableRoot(root);
422 // tail = editableTail(tail);
423 }
425 static Node editableRoot(Node node){
426 return new Node(new AtomicReference<Thread>(Thread.currentThread()), node.array.clone());
427 }
429 public PersistentVector persistent(){
430 ensureEditable();
431 // Thread owner = root.edit.get();
432 // if(owner != null && owner != Thread.currentThread())
433 // {
434 // throw new IllegalAccessError("Mutation release by non-owner thread");
435 // }
436 root.edit.set(null);
437 Object[] trimmedTail = new Object[cnt-tailoff()];
438 System.arraycopy(tail,0,trimmedTail,0,trimmedTail.length);
439 return new PersistentVector(cnt, shift, root, trimmedTail);
440 }
442 static Object[] editableTail(Object[] tl){
443 Object[] ret = new Object[32];
444 System.arraycopy(tl,0,ret,0,tl.length);
445 return ret;
446 }
448 public TransientVector conj(Object val){
449 ensureEditable();
450 int i = cnt;
451 //room in tail?
452 if(i - tailoff() < 32)
453 {
454 tail[i & 0x01f] = val;
455 ++cnt;
456 return this;
457 }
458 //full tail, push into tree
459 Node newroot;
460 Node tailnode = new Node(root.edit, tail);
461 tail = new Object[32];
462 tail[0] = val;
463 int newshift = shift;
464 //overflow root?
465 if((cnt >>> 5) > (1 << shift))
466 {
467 newroot = new Node(root.edit);
468 newroot.array[0] = root;
469 newroot.array[1] = newPath(root.edit,shift, tailnode);
470 newshift += 5;
471 }
472 else
473 newroot = pushTail(shift, root, tailnode);
474 root = newroot;
475 shift = newshift;
476 ++cnt;
477 return this;
478 }
480 private Node pushTail(int level, Node parent, Node tailnode){
481 //if parent is leaf, insert node,
482 // else does it map to an existing child? -> nodeToInsert = pushNode one more level
483 // else alloc new path
484 //return nodeToInsert placed in parent
485 parent = ensureEditable(parent);
486 int subidx = ((cnt - 1) >>> level) & 0x01f;
487 Node ret = parent;
488 Node nodeToInsert;
489 if(level == 5)
490 {
491 nodeToInsert = tailnode;
492 }
493 else
494 {
495 Node child = (Node) parent.array[subidx];
496 nodeToInsert = (child != null) ?
497 pushTail(level - 5, child, tailnode)
498 : newPath(root.edit, level - 5, tailnode);
499 }
500 ret.array[subidx] = nodeToInsert;
501 return ret;
502 }
504 final private int tailoff(){
505 if(cnt < 32)
506 return 0;
507 return ((cnt-1) >>> 5) << 5;
508 }
510 private Object[] arrayFor(int i){
511 if(i >= 0 && i < cnt)
512 {
513 if(i >= tailoff())
514 return tail;
515 Node node = root;
516 for(int level = shift; level > 0; level -= 5)
517 node = (Node) node.array[(i >>> level) & 0x01f];
518 return node.array;
519 }
520 throw new IndexOutOfBoundsException();
521 }
523 public Object valAt(Object key){
524 //note - relies on ensureEditable in 2-arg valAt
525 return valAt(key, null);
526 }
528 public Object valAt(Object key, Object notFound){
529 ensureEditable();
530 if(Util.isInteger(key))
531 {
532 int i = ((Number) key).intValue();
533 if(i >= 0 && i < cnt)
534 return nth(i);
535 }
536 return notFound;
537 }
539 public Object invoke(Object arg1) throws Exception{
540 //note - relies on ensureEditable in nth
541 if(Util.isInteger(arg1))
542 return nth(((Number) arg1).intValue());
543 throw new IllegalArgumentException("Key must be integer");
544 }
546 public Object nth(int i){
547 ensureEditable();
548 Object[] node = arrayFor(i);
549 return node[i & 0x01f];
550 }
552 public Object nth(int i, Object notFound){
553 if(i >= 0 && i < count())
554 return nth(i);
555 return notFound;
556 }
558 public TransientVector assocN(int i, Object val){
559 ensureEditable();
560 if(i >= 0 && i < cnt)
561 {
562 if(i >= tailoff())
563 {
564 tail[i & 0x01f] = val;
565 return this;
566 }
568 root = doAssoc(shift, root, i, val);
569 return this;
570 }
571 if(i == cnt)
572 return conj(val);
573 throw new IndexOutOfBoundsException();
574 }
576 public TransientVector assoc(Object key, Object val){
577 //note - relies on ensureEditable in assocN
578 if(Util.isInteger(key))
579 {
580 int i = ((Number) key).intValue();
581 return assocN(i, val);
582 }
583 throw new IllegalArgumentException("Key must be integer");
584 }
586 private Node doAssoc(int level, Node node, int i, Object val){
587 node = ensureEditable(node);
588 Node ret = node;
589 if(level == 0)
590 {
591 ret.array[i & 0x01f] = val;
592 }
593 else
594 {
595 int subidx = (i >>> level) & 0x01f;
596 ret.array[subidx] = doAssoc(level - 5, (Node) node.array[subidx], i, val);
597 }
598 return ret;
599 }
601 public TransientVector pop(){
602 ensureEditable();
603 if(cnt == 0)
604 throw new IllegalStateException("Can't pop empty vector");
605 if(cnt == 1)
606 {
607 cnt = 0;
608 return this;
609 }
610 int i = cnt - 1;
611 //pop in tail?
612 if((i & 0x01f) > 0)
613 {
614 --cnt;
615 return this;
616 }
618 Object[] newtail = arrayFor(cnt - 2);
620 Node newroot = popTail(shift, root);
621 int newshift = shift;
622 if(newroot == null)
623 {
624 newroot = new Node(root.edit);
625 }
626 if(shift > 5 && newroot.array[1] == null)
627 {
628 newroot = ensureEditable((Node) newroot.array[0]);
629 newshift -= 5;
630 }
631 root = newroot;
632 shift = newshift;
633 --cnt;
634 tail = newtail;
635 return this;
636 }
638 private Node popTail(int level, Node node){
639 node = ensureEditable(node);
640 int subidx = ((cnt - 2) >>> level) & 0x01f;
641 if(level > 5)
642 {
643 Node newchild = popTail(level - 5, (Node) node.array[subidx]);
644 if(newchild == null && subidx == 0)
645 return null;
646 else
647 {
648 Node ret = node;
649 ret.array[subidx] = newchild;
650 return ret;
651 }
652 }
653 else if(subidx == 0)
654 return null;
655 else
656 {
657 Node ret = node;
658 ret.array[subidx] = null;
659 return ret;
660 }
661 }
662 }
663 /*
664 static public void main(String[] args){
665 if(args.length != 3)
666 {
667 System.err.println("Usage: PersistentVector size writes reads");
668 return;
669 }
670 int size = Integer.parseInt(args[0]);
671 int writes = Integer.parseInt(args[1]);
672 int reads = Integer.parseInt(args[2]);
673 // Vector v = new Vector(size);
674 ArrayList v = new ArrayList(size);
675 // v.setSize(size);
676 //PersistentArray p = new PersistentArray(size);
677 PersistentVector p = PersistentVector.EMPTY;
678 // MutableVector mp = p.mutable();
680 for(int i = 0; i < size; i++)
681 {
682 v.add(i);
683 // v.set(i, i);
684 //p = p.set(i, 0);
685 p = p.cons(i);
686 // mp = mp.conj(i);
687 }
689 Random rand;
691 rand = new Random(42);
692 long tv = 0;
693 System.out.println("ArrayList");
694 long startTime = System.nanoTime();
695 for(int i = 0; i < writes; i++)
696 {
697 v.set(rand.nextInt(size), i);
698 }
699 for(int i = 0; i < reads; i++)
700 {
701 tv += (Integer) v.get(rand.nextInt(size));
702 }
703 long estimatedTime = System.nanoTime() - startTime;
704 System.out.println("time: " + estimatedTime / 1000000);
705 System.out.println("PersistentVector");
706 rand = new Random(42);
707 startTime = System.nanoTime();
708 long tp = 0;
710 // PersistentVector oldp = p;
711 //Random rand2 = new Random(42);
713 MutableVector mp = p.mutable();
714 for(int i = 0; i < writes; i++)
715 {
716 // p = p.assocN(rand.nextInt(size), i);
717 mp = mp.assocN(rand.nextInt(size), i);
718 // mp = mp.assoc(rand.nextInt(size), i);
719 //dummy set to force perverse branching
720 //oldp = oldp.assocN(rand2.nextInt(size), i);
721 }
722 for(int i = 0; i < reads; i++)
723 {
724 // tp += (Integer) p.nth(rand.nextInt(size));
725 tp += (Integer) mp.nth(rand.nextInt(size));
726 }
727 // p = mp.immutable();
728 //mp.cons(42);
729 estimatedTime = System.nanoTime() - startTime;
730 System.out.println("time: " + estimatedTime / 1000000);
731 for(int i = 0; i < size / 2; i++)
732 {
733 mp = mp.pop();
734 // p = p.pop();
735 v.remove(v.size() - 1);
736 }
737 p = (PersistentVector) mp.immutable();
738 //mp.pop(); //should fail
739 for(int i = 0; i < size / 2; i++)
740 {
741 tp += (Integer) p.nth(i);
742 tv += (Integer) v.get(i);
743 }
744 System.out.println("Done: " + tv + ", " + tp);
746 }
747 // */
748 }