|
25 | 25 | Any errors are my own
|
26 | 26 | */
|
27 | 27 |
|
28 |
| -public class PersistentHashMap extends APersistentMap implements IEditableCollection, IObj { |
| 28 | +public class PersistentHashMap extends APersistentMap implements IEditableCollection, IObj, IMapIterable { |
29 | 29 |
|
30 | 30 | final int count;
|
31 | 31 | final INode root;
|
@@ -173,8 +173,59 @@ public IPersistentMap without(Object key){
|
173 | 173 | return new PersistentHashMap(meta(), count - 1, newroot, hasNull, nullValue);
|
174 | 174 | }
|
175 | 175 |
|
| 176 | +static final Iterator EMPTY_ITER = new Iterator(){ |
| 177 | + public boolean hasNext(){ |
| 178 | + return false; |
| 179 | + } |
| 180 | + |
| 181 | + public Object next(){ |
| 182 | + throw new NoSuchElementException(); |
| 183 | + } |
| 184 | + |
| 185 | + public void remove(){ |
| 186 | + throw new UnsupportedOperationException(); |
| 187 | + } |
| 188 | +}; |
| 189 | + |
| 190 | +private Iterator iterator(final IFn f){ |
| 191 | + final Iterator rootIter = (root == null) ? EMPTY_ITER : root.iterator(f); |
| 192 | + if(hasNull) { |
| 193 | + return new Iterator() { |
| 194 | + private boolean seen = false; |
| 195 | + public boolean hasNext() { |
| 196 | + if (!seen) |
| 197 | + return true; |
| 198 | + else |
| 199 | + return rootIter.hasNext(); |
| 200 | + } |
| 201 | + |
| 202 | + public Object next(){ |
| 203 | + if (!seen) { |
| 204 | + seen = true; |
| 205 | + return f.invoke(null, nullValue); |
| 206 | + } else |
| 207 | + return rootIter.next(); |
| 208 | + } |
| 209 | + |
| 210 | + public void remove(){ |
| 211 | + throw new UnsupportedOperationException(); |
| 212 | + } |
| 213 | + }; |
| 214 | + } |
| 215 | + else |
| 216 | + return rootIter; |
| 217 | +} |
| 218 | + |
176 | 219 | public Iterator iterator(){
|
177 |
| - return new SeqIterator(this); |
| 220 | + return iterator(APersistentMap.MAKE_ENTRY); |
| 221 | +} |
| 222 | + |
| 223 | +public Iterator keyIterator(){ |
| 224 | + return iterator(APersistentMap.MAKE_KEY); |
| 225 | +} |
| 226 | + |
| 227 | +public Iterator valIterator(){ |
| 228 | + return iterator(APersistentMap.MAKE_VAL); |
178 | 229 | }
|
179 | 230 |
|
180 | 231 | public Object kvreduce(IFn f, Object init){
|
@@ -340,6 +391,9 @@ static interface INode extends Serializable {
|
340 | 391 | public Object kvreduce(IFn f, Object init);
|
341 | 392 |
|
342 | 393 | Object fold(IFn combinef, IFn reducef, IFn fjtask, IFn fjfork, IFn fjjoin);
|
| 394 | + |
| 395 | + // returns the result of (f [k v]) for each iterated element |
| 396 | + Iterator iterator(IFn f); |
343 | 397 | }
|
344 | 398 |
|
345 | 399 | final static class ArrayNode implements INode{
|
@@ -400,6 +454,10 @@ public ISeq nodeSeq(){
|
400 | 454 | return Seq.create(array);
|
401 | 455 | }
|
402 | 456 |
|
| 457 | + public Iterator iterator(IFn f){ |
| 458 | + return new Iter(array, f); |
| 459 | + } |
| 460 | + |
403 | 461 | public Object kvreduce(IFn f, Object init){
|
404 | 462 | for(INode node : array){
|
405 | 463 | if(node != null){
|
@@ -563,6 +621,49 @@ public ISeq next() {
|
563 | 621 | }
|
564 | 622 |
|
565 | 623 | }
|
| 624 | + |
| 625 | + static class Iter implements Iterator { |
| 626 | + private final INode[] array; |
| 627 | + private final IFn f; |
| 628 | + private int i = 0; |
| 629 | + private Iterator nestedIter; |
| 630 | + |
| 631 | + private Iter(INode[] array, IFn f){ |
| 632 | + this.array = array; |
| 633 | + this.f = f; |
| 634 | + } |
| 635 | + |
| 636 | + public boolean hasNext(){ |
| 637 | + while(true) |
| 638 | + { |
| 639 | + if(nestedIter != null) |
| 640 | + if(nestedIter.hasNext()) |
| 641 | + return true; |
| 642 | + else |
| 643 | + nestedIter = null; |
| 644 | + |
| 645 | + if(i < array.length) |
| 646 | + { |
| 647 | + INode node = array[i++]; |
| 648 | + if (node != null) |
| 649 | + nestedIter = node.iterator(f); |
| 650 | + } |
| 651 | + else |
| 652 | + return false; |
| 653 | + } |
| 654 | + } |
| 655 | + |
| 656 | + public Object next(){ |
| 657 | + if(hasNext()) |
| 658 | + return nestedIter.next(); |
| 659 | + else |
| 660 | + throw new NoSuchElementException(); |
| 661 | + } |
| 662 | + |
| 663 | + public void remove(){ |
| 664 | + throw new UnsupportedOperationException(); |
| 665 | + } |
| 666 | + } |
566 | 667 | }
|
567 | 668 |
|
568 | 669 | final static class BitmapIndexedNode implements INode{
|
@@ -687,6 +788,10 @@ public ISeq nodeSeq(){
|
687 | 788 | return NodeSeq.create(array);
|
688 | 789 | }
|
689 | 790 |
|
| 791 | + public Iterator iterator(IFn f){ |
| 792 | + return new NodeIter(array, f); |
| 793 | + } |
| 794 | + |
690 | 795 | public Object kvreduce(IFn f, Object init){
|
691 | 796 | return NodeSeq.kvreduce(array,f,init);
|
692 | 797 | }
|
@@ -879,6 +984,10 @@ public ISeq nodeSeq(){
|
879 | 984 | return NodeSeq.create(array);
|
880 | 985 | }
|
881 | 986 |
|
| 987 | + public Iterator iterator(IFn f){ |
| 988 | + return new NodeIter(array, f); |
| 989 | + } |
| 990 | + |
882 | 991 | public Object kvreduce(IFn f, Object init){
|
883 | 992 | return NodeSeq.kvreduce(array,f,init);
|
884 | 993 | }
|
@@ -1107,6 +1216,73 @@ private static int bitpos(int hash, int shift){
|
1107 | 1216 | return 1 << mask(hash, shift);
|
1108 | 1217 | }
|
1109 | 1218 |
|
| 1219 | +static final class NodeIter implements Iterator { |
| 1220 | + private static final Object NULL = new Object(); |
| 1221 | + final Object[] array; |
| 1222 | + final IFn f; |
| 1223 | + private int i = 0; |
| 1224 | + private Object nextEntry = NULL; |
| 1225 | + private Iterator nextIter; |
| 1226 | + |
| 1227 | + NodeIter(Object[] array, IFn f){ |
| 1228 | + this.array = array; |
| 1229 | + this.f = f; |
| 1230 | + } |
| 1231 | + |
| 1232 | + private boolean advance(){ |
| 1233 | + while (i<array.length) |
| 1234 | + { |
| 1235 | + Object key = array[i]; |
| 1236 | + Object nodeOrVal = array[i+1]; |
| 1237 | + i += 2; |
| 1238 | + if (key != null) |
| 1239 | + { |
| 1240 | + nextEntry = f.invoke(key, nodeOrVal); |
| 1241 | + return true; |
| 1242 | + } |
| 1243 | + else if(nodeOrVal != null) |
| 1244 | + { |
| 1245 | + Iterator iter = ((INode) nodeOrVal).iterator(f); |
| 1246 | + if(iter != null && iter.hasNext()) |
| 1247 | + { |
| 1248 | + nextIter = iter; |
| 1249 | + return true; |
| 1250 | + } |
| 1251 | + } |
| 1252 | + } |
| 1253 | + return false; |
| 1254 | + } |
| 1255 | + |
| 1256 | + public boolean hasNext(){ |
| 1257 | + if (nextEntry != NULL || nextIter != null) |
| 1258 | + return true; |
| 1259 | + return advance(); |
| 1260 | + } |
| 1261 | + |
| 1262 | + public Object next(){ |
| 1263 | + Object ret = nextEntry; |
| 1264 | + if(ret != NULL) |
| 1265 | + { |
| 1266 | + nextEntry = NULL; |
| 1267 | + return ret; |
| 1268 | + } |
| 1269 | + else if(nextIter != null) |
| 1270 | + { |
| 1271 | + ret = nextIter.next(); |
| 1272 | + if(! nextIter.hasNext()) |
| 1273 | + nextIter = null; |
| 1274 | + return ret; |
| 1275 | + } |
| 1276 | + else if(advance()) |
| 1277 | + return next(); |
| 1278 | + throw new NoSuchElementException(); |
| 1279 | + } |
| 1280 | + |
| 1281 | + public void remove(){ |
| 1282 | + throw new UnsupportedOperationException(); |
| 1283 | + } |
| 1284 | +} |
| 1285 | + |
1110 | 1286 | static final class NodeSeq extends ASeq {
|
1111 | 1287 | final Object[] array;
|
1112 | 1288 | final int i;
|
|
0 commit comments