1 package org.opendaylight.yangtools.triemap;
3 import java.io.IOException;
4 import java.io.ObjectInputStream;
5 import java.io.ObjectOutputStream;
6 import java.io.Serializable;
7 import java.lang.reflect.Field;
8 import java.util.AbstractMap;
9 import java.util.AbstractMap.SimpleImmutableEntry;
10 import java.util.AbstractSet;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
17 import java.util.NoSuchElementException;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
23 * This is a port of Scala's TrieMap class from the Scala Collections library.
25 * @author Roman Levenstein <romixlev@gmail.com>
30 @SuppressWarnings({"unchecked", "rawtypes", "unused"})
31 public class TrieMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,V>, Serializable {
32 private static final AtomicReferenceFieldUpdater<TrieMap, Object> ROOT_UPDATER = AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root");
33 private static final long serialVersionUID = 1L;
34 private static final Field READONLY_FIELD;
35 private static final TrieMap EMPTY = new TrieMap();
40 f = TrieMap.class.getDeclaredField("readOnly");
41 } catch (NoSuchFieldException e) {
42 throw new ExceptionInInitializerError(e);
43 } catch (SecurityException e) {
44 throw new ExceptionInInitializerError(e);
46 f.setAccessible(true);
53 private transient final EntrySet entrySet = new EntrySet ();
55 public static <K,V> TrieMap<K,V> empty () {
59 // static class MangledHashing<K> extends Hashing<K> {
61 // return util.hashing.byteswap32(k);
65 static class INode<K, V> extends INodeBase<K, V> {
66 static final Object KEY_PRESENT = new Object ();
67 static final Object KEY_ABSENT = new Object ();
69 static <K,V> INode<K,V> newRootNode () {
71 CNode<K, V> cn = new CNode<K, V> (0, new BasicNode[] {}, gen);
72 return new INode<K,V>(cn, gen);
75 public INode (MainNode<K, V> bn, Gen g) {
80 public INode (Gen g) {
84 final void WRITE (final MainNode<K, V> nval) {
85 INodeBase.updater.set (this, nval);
88 final boolean CAS (final MainNode<K, V> old, final MainNode<K, V> n) {
89 return INodeBase.updater.compareAndSet (this, old, n);
92 final MainNode<K, V> gcasRead (final TrieMap<K, V> ct) {
93 return GCAS_READ (ct);
96 final MainNode<K, V> GCAS_READ (TrieMap<K, V> ct) {
97 MainNode<K, V> m = /* READ */mainnode;
98 MainNode<K, V> prevval = /* READ */m.prev;
102 return GCAS_Complete (m, ct);
105 private MainNode<K, V> GCAS_Complete (MainNode<K, V> m, final TrieMap<K, V> ct) {
111 MainNode<K, V> prev = /* READ */m.prev;
112 INode<K, V> ctr = ct.readRoot (true);
117 if (prev instanceof FailedNode) {
118 // try to commit to previous value
119 FailedNode<K, V> fn = (FailedNode<K, V>) prev;
120 if (CAS (m, fn.prev))
124 // return GCAS_Complete (/* READ */mainnode, ct);
125 m = /* READ */mainnode;
128 } else if (prev instanceof MainNode) {
129 // Assume that you've read the root from the generation
131 // Assume that the snapshot algorithm is correct.
132 // ==> you can only reach nodes in generations <= G.
133 // ==> `gen` is <= G.
134 // We know that `ctr.gen` is >= G.
135 // ==> if `ctr.gen` = `gen` then they are both equal to
137 // ==> otherwise, we know that either `ctr.gen` > G,
141 if ((ctr.gen == gen) && ct.nonReadOnly ()) {
143 if (m.CAS_PREV (prev, null))
146 // return GCAS_Complete (m, ct);
152 m.CAS_PREV (prev, new FailedNode<K, V> (prev));
153 return GCAS_Complete (/* READ */mainnode, ct);
157 throw new RuntimeException ("Should not happen");
161 final boolean GCAS (final MainNode<K, V> old, final MainNode<K, V> n, final TrieMap<K, V> ct) {
164 GCAS_Complete (n, ct);
165 return /* READ */n.prev == null;
170 private boolean equal (final K k1, final K k2, final TrieMap<K, V> ct) {
171 return ct.equality ().equiv (k1, k2);
174 private INode<K, V> inode (final MainNode<K, V> cn) {
175 INode<K, V> nin = new INode<K, V> (gen);
180 final INode<K, V> copyToGen (final Gen ngen, final TrieMap<K, V> ct) {
181 INode<K, V> nin = new INode<K, V> (ngen);
182 MainNode<K, V> main = GCAS_READ (ct);
188 * Inserts a key value pair, overwriting the old pair if the keys match.
190 * @return true if successful, false otherwise
192 final boolean rec_insert (final K k, final V v, final int hc, final int lev, final INode<K, V> parent, final Gen startgen, final TrieMap<K, V> ct) {
194 MainNode<K, V> m = GCAS_READ (ct); // use -Yinline!
196 if (m instanceof CNode) {
197 // 1) a multiway node
198 CNode<K, V> cn = (CNode<K, V>) m;
199 int idx = (hc >>> lev) & 0x1f;
203 int pos = Integer.bitCount (bmp & mask);
204 if ((bmp & flag) != 0) {
206 BasicNode cnAtPos = cn.array [pos];
207 if (cnAtPos instanceof INode) {
208 INode<K, V> in = (INode<K, V>) cnAtPos;
209 if (startgen == in.gen)
210 return in.rec_insert (k, v, hc, lev + 5, this, startgen, ct);
212 if (GCAS (cn, cn.renewed (startgen, ct), ct)) {
213 // return rec_insert (k, v, hc, lev, parent,
220 } else if (cnAtPos instanceof SNode) {
221 SNode<K, V> sn = (SNode<K, V>) cnAtPos;
222 if (sn.hc == hc && equal ((K) sn.k, k, ct))
223 return GCAS (cn, cn.updatedAt (pos, new SNode<K, V> (k, v, hc), gen), ct);
225 CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed (gen, ct);
226 MainNode<K, V> nn = rn.updatedAt (pos, inode (CNode.dual (sn, sn.hc, new SNode (k, v, hc), hc, lev + 5, gen)), gen);
227 return GCAS (cn, nn, ct);
231 CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed (gen, ct);
232 MainNode<K, V> ncnode = rn.insertedAt (pos, flag, new SNode<K, V> (k, v, hc), gen);
233 return GCAS (cn, ncnode, ct);
235 } else if (m instanceof TNode) {
236 clean (parent, ct, lev - 5);
238 } else if (m instanceof LNode) {
239 LNode<K, V> ln = (LNode<K, V>) m;
240 MainNode<K, V> nn = ln.inserted (k, v);
241 return GCAS (ln, nn, ct);
244 throw new RuntimeException ("Should not happen");
249 * Inserts a new key value pair, given that a specific condition is met.
252 * null - don't care if the key was there
253 * KEY_ABSENT - key wasn't there
254 * KEY_PRESENT - key was there
255 * other value `v` - key must be bound to `v`
256 * @return null if unsuccessful, Option[V] otherwise (indicating
257 * previous value bound to the key)
259 final Option<V> rec_insertif (final K k, final V v, final int hc, final Object cond, final int lev, final INode<K, V> parent, final Gen startgen, final TrieMap<K, V> ct) {
261 MainNode<K, V> m = GCAS_READ (ct); // use -Yinline!
263 if (m instanceof CNode) {
264 // 1) a multiway node
265 CNode<K, V> cn = (CNode<K, V>) m;
266 int idx = (hc >>> lev) & 0x1f;
270 int pos = Integer.bitCount (bmp & mask);
272 if ((bmp & flag) != 0) {
274 BasicNode cnAtPos = cn.array [pos];
275 if (cnAtPos instanceof INode) {
276 INode<K, V> in = (INode<K, V>) cnAtPos;
277 if (startgen == in.gen)
278 return in.rec_insertif (k, v, hc, cond, lev + 5, this, startgen, ct);
280 if (GCAS (cn, cn.renewed (startgen, ct), ct)) {
281 // return rec_insertif (k, v, hc, cond, lev,
282 // parent, startgen, ct);
288 } else if (cnAtPos instanceof SNode) {
289 SNode<K, V> sn = (SNode<K, V>) cnAtPos;
291 if (sn.hc == hc && equal (sn.k, k, ct)) {
292 if (GCAS (cn, cn.updatedAt (pos, new SNode<K, V> (k, v, hc), gen), ct))
293 return Option.makeOption(sn.v);
297 CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed (gen, ct);
298 MainNode<K, V> nn = rn.updatedAt (pos, inode (CNode.dual (sn, sn.hc, new SNode (k, v, hc), hc, lev + 5, gen)), gen);
299 if (GCAS (cn, nn, ct))
300 return Option.makeOption(); // None;
305 } else if (cond == INode.KEY_ABSENT) {
306 if (sn.hc == hc && equal (sn.k, k, ct))
307 return Option.makeOption(sn.v);
309 CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed (gen, ct);
310 MainNode<K, V> nn = rn.updatedAt (pos, inode (CNode.dual (sn, sn.hc, new SNode (k, v, hc), hc, lev + 5, gen)), gen);
311 if (GCAS (cn, nn, ct))
312 return Option.makeOption (); // None
316 } else if (cond == INode.KEY_PRESENT) {
317 if (sn.hc == hc && equal (sn.k, k, ct)) {
318 if (GCAS (cn, cn.updatedAt (pos, new SNode<K, V> (k, v, hc), gen), ct))
319 return Option.makeOption (sn.v);
324 return Option.makeOption ();// None;
326 if (sn.hc == hc && equal (sn.k, k, ct) && sn.v == cond) {
327 if (GCAS (cn, cn.updatedAt (pos, new SNode<K, V> (k, v, hc), gen), ct))
328 return Option.makeOption (sn.v);
332 return Option.makeOption (); // None
336 } else if (cond == null || cond == INode.KEY_ABSENT) {
337 CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed (gen, ct);
338 CNode<K, V> ncnode = rn.insertedAt (pos, flag, new SNode<K, V> (k, v, hc), gen);
339 if (GCAS (cn, ncnode, ct))
340 return Option.makeOption ();// None
343 } else if (cond == INode.KEY_PRESENT) {
344 return Option.makeOption ();// None;
346 return Option.makeOption (); // None
347 } else if (m instanceof TNode) {
348 clean (parent, ct, lev - 5);
350 } else if (m instanceof LNode) {
352 LNode<K, V> ln = (LNode<K, V>) m;
354 Option<V> optv = ln.get (k);
355 if (insertln (ln, k, v, ct))
359 } else if (cond == INode.KEY_ABSENT) {
360 Option<V> t = ln.get (k);
362 if (insertln (ln, k, v, ct))
363 return Option.makeOption ();// None
368 } else if (cond == INode.KEY_PRESENT) {
369 Option<V> t = ln.get (k);
371 if (insertln (ln, k, v, ct))
378 Option<V> t = ln.get (k);
380 if (((Some<V>) t).get () == cond) {
381 if (insertln (ln, k, v, ct))
382 return new Some<V> ((V) cond);
387 return Option.makeOption ();
392 // throw new RuntimeException ("Should not happen");
396 final boolean insertln (final LNode<K, V> ln, final K k, final V v, final TrieMap<K, V> ct) {
397 LNode<K, V> nn = ln.inserted (k, v);
398 return GCAS (ln, nn, ct);
402 * Looks up the value associated with the key.
404 * @return null if no value has been found, RESTART if the operation
405 * wasn't successful, or any other value otherwise
407 final Object rec_lookup (final K k, final int hc, int lev, INode<K, V> parent, final Gen startgen, final TrieMap<K, V> ct) {
409 MainNode<K, V> m = GCAS_READ (ct); // use -Yinline!
411 if (m instanceof CNode) {
413 final CNode<K, V> cn = (CNode<K, V>) m;
414 int idx = (hc >>> lev) & 0x1f;
417 if ((bmp & flag) == 0)
418 return null; // 1a) bitmap shows no binding
419 else { // 1b) bitmap contains a value - descend
420 int pos = (bmp == 0xffffffff) ? idx : Integer.bitCount (bmp & (flag - 1));
421 final BasicNode sub = cn.array [pos];
422 if (sub instanceof INode) {
423 INode<K, V> in = (INode<K, V>) sub;
424 if (ct.isReadOnly () || (startgen == ((INodeBase<K, V>) sub).gen))
425 return in.rec_lookup (k, hc, lev + 5, this, startgen, ct);
427 if (GCAS (cn, cn.renewed (startgen, ct), ct)) {
428 // return rec_lookup (k, hc, lev, parent,
433 return RESTART; // used to be throw
436 } else if (sub instanceof SNode) {
438 SNode<K, V> sn = (SNode<K, V>) sub;
439 if (((SNode) sub).hc == hc && equal (sn.k, k, ct))
445 } else if (m instanceof TNode) {
447 return cleanReadOnly ((TNode<K, V>) m, lev, parent, ct, k, hc);
448 } else if (m instanceof LNode) {
450 Option<V> tmp = ((LNode<K, V>) m).get (k);
451 return (tmp instanceof Option) ? ((Option<V>) tmp) : null;
454 throw new RuntimeException ("Should not happen");
458 private Object cleanReadOnly (final TNode<K, V> tn, final int lev, final INode<K, V> parent, final TrieMap<K, V> ct, K k, int hc) {
459 if (ct.nonReadOnly ()) {
460 clean (parent, ct, lev - 5);
461 return RESTART; // used to be throw RestartException
463 if (tn.hc == hc && equal(tn.k, k, ct))
471 * Removes the key associated with the given value.
474 * if null, will remove the key irregardless of the value;
475 * otherwise removes only if binding contains that exact key
477 * @return null if not successful, an Option[V] indicating the previous
480 final Option<V> rec_remove (K k, V v, int hc, int lev, final INode<K, V> parent, final Gen startgen, final TrieMap<K, V> ct) {
481 MainNode<K, V> m = GCAS_READ (ct); // use -Yinline!
483 if (m instanceof CNode) {
484 CNode<K, V> cn = (CNode<K, V>) m;
485 int idx = (hc >>> lev) & 0x1f;
488 if ((bmp & flag) == 0)
489 return Option.makeOption ();
491 int pos = Integer.bitCount (bmp & (flag - 1));
492 BasicNode sub = cn.array [pos];
493 Option<V> res = null;
494 if (sub instanceof INode) {
495 INode<K, V> in = (INode<K, V>) sub;
496 if (startgen == in.gen)
497 res = in.rec_remove (k, v, hc, lev + 5, this, startgen, ct);
499 if (GCAS (cn, cn.renewed (startgen, ct), ct))
500 res = rec_remove (k, v, hc, lev, parent, startgen, ct);
505 } else if (sub instanceof SNode) {
506 SNode<K, V> sn = (SNode<K, V>) sub;
507 if (sn.hc == hc && equal (sn.k, k, ct) && (v == null || v.equals(sn.v))) {
508 MainNode<K, V> ncn = cn.removedAt (pos, flag, gen).toContracted (lev);
509 if (GCAS (cn, ncn, ct))
510 res = Option.makeOption (sn.v);
514 res = Option.makeOption ();
517 if (res instanceof None || (res == null))
520 if (parent != null) { // never tomb at root
521 MainNode<K, V> n = GCAS_READ (ct);
522 if (n instanceof TNode)
523 cleanParent (n, parent, ct, hc, lev, startgen);
529 } else if (m instanceof TNode) {
530 clean (parent, ct, lev - 5);
532 } else if (m instanceof LNode) {
533 LNode<K, V> ln = (LNode<K, V>) m;
535 Option<V> optv = ln.get (k);
536 MainNode<K, V> nn = ln.removed (k, ct);
537 if (GCAS (ln, nn, ct))
542 Option<V> tmp = ln.get (k);
543 if (tmp instanceof Some) {
544 Some<V> tmp1 = (Some<V>) tmp;
545 if (tmp1.get () == v) {
546 MainNode<K, V> nn = ln.removed (k, ct);
547 if (GCAS (ln, nn, ct))
555 throw new RuntimeException ("Should not happen");
558 void cleanParent (final Object nonlive, final INode<K, V> parent, final TrieMap<K, V> ct, final int hc, final int lev, final Gen startgen) {
560 MainNode<K, V> pm = parent.GCAS_READ (ct);
561 if (pm instanceof CNode) {
562 CNode<K, V> cn = (CNode<K, V>) pm;
563 int idx = (hc >>> (lev - 5)) & 0x1f;
566 if ((bmp & flag) == 0) {
567 } // somebody already removed this i-node, we're done
569 int pos = Integer.bitCount (bmp & (flag - 1));
570 BasicNode sub = cn.array [pos];
572 if (nonlive instanceof TNode) {
573 TNode<K, V> tn = (TNode<K, V>) nonlive;
574 MainNode<K, V> ncn = cn.updatedAt (pos, tn.copyUntombed (), gen).toContracted (lev - 5);
575 if (!parent.GCAS (cn, ncn, ct))
576 if (ct.readRoot ().gen == startgen) {
577 // cleanParent (nonlive, parent, ct, hc,
586 // parent is no longer a cnode, we're done
592 private void clean (final INode<K, V> nd, final TrieMap<K, V> ct, int lev) {
593 MainNode<K, V> m = nd.GCAS_READ (ct);
594 if (m instanceof CNode) {
595 CNode<K, V> cn = (CNode<K, V>) m;
596 nd.GCAS (cn, cn.toCompressed (ct, lev, gen), ct);
600 final boolean isNullInode (final TrieMap<K, V> ct) {
601 return GCAS_READ (ct) == null;
604 final int cachedSize (final TrieMap<K, V> ct) {
605 MainNode<K, V> m = GCAS_READ (ct);
606 return m.cachedSize (ct);
609 // /* this is a quiescent method! */
610 // def string(lev: Int) = "%sINode -> %s".format(" " * lev, mainnode
612 // case null => "<null>"
613 // case tn: TNode[_, _] => "TNode(%s, %s, %d, !)".format(tn.k, tn.v,
615 // case cn: CNode[_, _] => cn.string(lev)
616 // case ln: LNode[_, _] => ln.string(lev)
617 // case x => "<elem: %s>".format(x)
620 public String string (int lev) {
626 private static final class FailedNode<K, V> extends MainNode<K, V> {
629 FailedNode (final MainNode<K, V> p) {
634 public String string (int lev) {
635 throw new UnsupportedOperationException ();
638 public int cachedSize (Object ct) {
639 throw new UnsupportedOperationException ();
642 public String toString () {
643 return String.format ("FailedNode(%s)", p);
647 private interface KVNode<K, V> {
648 Map.Entry<K, V> kvPair ();
651 private static final class SNode<K, V> extends BasicNode implements KVNode<K, V> {
656 SNode (final K k, final V v, final int hc) {
662 final SNode<K, V> copy() {
663 return new SNode<K, V> (k, v, hc);
666 final TNode<K, V> copyTombed () {
667 return new TNode<K, V> (k, v, hc);
670 final SNode<K, V> copyUntombed () {
671 return new SNode<K, V> (k, v, hc);
674 final public Map.Entry<K, V> kvPair () {
675 return new SimpleImmutableEntry<K, V> (k, v);
678 final public String string (int lev) {
679 // (" " * lev) + "SNode(%s, %s, %x)".format(k, v, hc);
684 private static final class TNode<K, V> extends MainNode<K, V> implements KVNode<K, V> {
689 TNode (final K k, final V v, final int hc) {
695 final TNode<K, V> copy () {
696 return new TNode<K, V> (k, v, hc);
699 final TNode<K, V> copyTombed () {
700 return new TNode<K, V> (k, v, hc);
703 final SNode<K, V> copyUntombed () {
704 return new SNode<K, V> (k, v, hc);
707 final public Map.Entry<K, V> kvPair () {
708 return new SimpleImmutableEntry<K, V> (k, v);
711 final public int cachedSize (Object ct) {
715 final public String string (int lev) {
716 // (" " * lev) + "TNode(%s, %s, %x, !)".format(k, v, hc);
721 private final static class LNode<K, V> extends MainNode<K, V> {
722 final ListMap<K, V> listmap;
724 public LNode (final ListMap<K, V> listmap) {
725 this.listmap = listmap;
728 public LNode(K k, V v) {
729 this (ListMap.map (k, v));
732 public LNode (K k1, V v1, K k2, V v2) {
733 this (ListMap.map (k1, v1, k2, v2));
736 LNode<K, V> inserted (K k, V v) {
737 return new LNode<K, V> (listmap.add (k, v));
740 MainNode<K, V> removed (K k, final TrieMap<K, V> ct) {
741 ListMap<K, V> updmap = listmap.remove (k);
742 if (updmap.size () > 1)
743 return new LNode<K, V> (updmap);
745 Entry<K, V> kv = updmap.iterator ().next ();
746 // create it tombed so that it gets compressed on subsequent
748 return new TNode<K, V> (kv.getKey (), kv.getValue (), ct.computeHash (kv.getKey ()));
752 Option<V> get (K k) {
753 return listmap.get (k);
756 public int cachedSize (Object ct) {
757 return listmap.size ();
760 public String string (int lev) {
761 // (" " * lev) + "LNode(%s)".format(listmap.mkString(", "))
766 private static final class CNode<K, V> extends CNodeBase<K, V> {
769 final BasicNode[] array;
772 CNode (final int bitmap, final BasicNode[] array, final Gen gen) {
773 this.bitmap = bitmap;
778 // this should only be called from within read-only snapshots
779 final public int cachedSize (Object ct) {
780 int currsz = READ_SIZE ();
784 int sz = computeSize ((TrieMap<K, V>) ct);
785 while (READ_SIZE () == -1)
791 // lends itself towards being parallelizable by choosing
792 // a random starting offset in the array
793 // => if there are concurrent size computations, they start
794 // at different positions, so they are more likely to
796 private int computeSize (final TrieMap<K, V> ct) {
799 // final int offset = (array.length > 0) ?
800 // // util.Random.nextInt(array.length) /* <-- benchmarks show that
801 // // this causes observable contention */
802 // scala.concurrent.forkjoin.ThreadLocalRandom.current.nextInt (0,
806 final int offset = 0;
807 while (i < array.length) {
808 int pos = (i + offset) % array.length;
809 BasicNode elem = array [pos];
810 if (elem instanceof SNode)
812 else if (elem instanceof INode)
813 sz += ((INode<K, V>) elem).cachedSize (ct);
819 final CNode<K, V> updatedAt (int pos, final BasicNode nn, final Gen gen) {
820 int len = array.length;
821 BasicNode[] narr = new BasicNode[len];
822 System.arraycopy (array, 0, narr, 0, len);
824 return new CNode<K, V> (bitmap, narr, gen);
827 final CNode<K, V> removedAt (int pos, int flag, final Gen gen) {
828 BasicNode[] arr = array;
829 int len = arr.length;
830 BasicNode[] narr = new BasicNode[len - 1];
831 System.arraycopy (arr, 0, narr, 0, pos);
832 System.arraycopy (arr, pos + 1, narr, pos, len - pos - 1);
833 return new CNode<K, V> (bitmap ^ flag, narr, gen);
836 final CNode<K, V> insertedAt (int pos, int flag, final BasicNode nn, final Gen gen) {
837 int len = array.length;
839 BasicNode[] narr = new BasicNode[len + 1];
840 System.arraycopy (array, 0, narr, 0, pos);
842 System.arraycopy (array, pos, narr, pos + 1, len - pos);
843 return new CNode<K, V> (bmp | flag, narr, gen);
847 * Returns a copy of this cnode such that all the i-nodes below it are
848 * copied to the specified generation `ngen`.
850 final CNode<K, V> renewed (final Gen ngen, final TrieMap<K, V> ct) {
852 BasicNode[] arr = array;
853 int len = arr.length;
854 BasicNode[] narr = new BasicNode[len];
856 BasicNode elem = arr [i];
857 if (elem instanceof INode) {
858 INode<K, V> in = (INode<K, V>) elem;
859 narr [i] = in.copyToGen (ngen, ct);
860 } else if (elem instanceof BasicNode)
864 return new CNode<K, V> (bitmap, narr, ngen);
867 private BasicNode resurrect (final INode<K, V> inode, final Object inodemain) {
868 if (inodemain instanceof TNode) {
869 TNode<K, V> tn = (TNode<K, V>) inodemain;
870 return tn.copyUntombed ();
875 final MainNode<K, V> toContracted (int lev) {
876 if (array.length == 1 && lev > 0) {
877 if (array [0] instanceof SNode) {
878 SNode<K, V> sn = (SNode<K, V>) array [0];
879 return sn.copyTombed ();
887 // - if the branching factor is 1 for this CNode, and the child
888 // is a tombed SNode, returns its tombed version
889 // - otherwise, if there is at least one non-null node below,
890 // returns the version of this node with at least some null-inodes
891 // removed (those existing when the op began)
892 // - if there are only null-i-nodes below, returns null
893 final MainNode<K, V> toCompressed (final TrieMap<K, V> ct, int lev, Gen gen) {
896 BasicNode[] arr = array;
897 BasicNode[] tmparray = new BasicNode[arr.length];
898 while (i < arr.length) { // construct new bitmap
899 BasicNode sub = arr [i];
900 if (sub instanceof INode) {
901 INode<K, V> in = (INode<K, V>) sub;
902 MainNode<K, V> inodemain = in.gcasRead (ct);
903 assert (inodemain != null);
904 tmparray [i] = resurrect (in, inodemain);
905 } else if (sub instanceof SNode) {
911 return new CNode<K, V> (bmp, tmparray, gen).toContracted (lev);
914 public String string (int lev) {
915 // "CNode %x\n%s".format(bitmap, array.map(_.string(lev +
916 // 1)).mkString("\n"));
921 * quiescently consistent - don't call concurrently to anything
924 // protected Seq<K,V> collectElems() {
926 // case sn: SNode[K, V] => Some(sn.kvPair)
927 // case in: INode[K, V] => in.mainnode match {
928 // case tn: TNode[K, V] => Some(tn.kvPair)
929 // case ln: LNode[K, V] => ln.listmap.toList
930 // case cn: CNode[K, V] => cn.collectElems
935 // protected Seq<String> collectLocalElems() {
936 // // array flatMap {
937 // // case sn: SNode[K, V] => Some(sn.kvPair._2.toString)
938 // // case in: INode[K, V] => Some(in.toString.drop(14) + "(" + in.gen +
944 public String toString () {
945 // val elems = collectLocalElems
946 // "CNode(sz: %d; %s)".format(elems.size,
947 // elems.sorted.mkString(", "))
951 static <K, V> MainNode<K,V> dual (final SNode<K, V> x, int xhc, final SNode<K, V> y, int yhc, int lev, Gen gen) {
953 int xidx = (xhc >>> lev) & 0x1f;
954 int yidx = (yhc >>> lev) & 0x1f;
955 int bmp = (1 << xidx) | (1 << yidx);
958 INode<K, V> subinode = new INode<K, V> (gen);// (TrieMap.inodeupdater)
959 subinode.mainnode = dual (x, xhc, y, yhc, lev + 5, gen);
960 return new CNode<K, V> (bmp, new BasicNode[] { subinode }, gen);
963 return new CNode<K, V> (bmp, new BasicNode[] { x, y }, gen);
965 return new CNode<K, V> (bmp, new BasicNode[] { y, x }, gen);
968 return new LNode<K, V> (x.k, x.v, y.k, y.v);
974 private static class RDCSS_Descriptor<K, V> {
976 MainNode<K, V> expectedmain;
978 volatile boolean committed = false;
980 public RDCSS_Descriptor (final INode<K, V> old, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
982 this.expectedmain = expectedmain;
988 private static class Equiv<K> implements Serializable {
989 private static final long serialVersionUID = 1L;
991 public boolean equiv (K k1, K k2) {
992 return k1.equals (k2);
995 static Equiv universal = new Equiv ();
998 private static interface Hashing<K> extends Serializable {
999 public int hash (K k);
1002 static class Default<K> implements Hashing<K> {
1003 private static final long serialVersionUID = 1L;
1005 public int hash (K k) {
1006 int h = k.hashCode ();
1007 // This function ensures that hashCodes that differ only by
1008 // constant multiples at each bit position have a bounded
1009 // number of collisions (approximately 8 at default load factor).
1010 h ^= (h >>> 20) ^ (h >>> 12);
1011 h ^= (h >>> 7) ^ (h >>> 4);
1016 private final Hashing<K> hashingobj;
1017 private final Equiv<K> equalityobj;
1019 Hashing<K> hashing () {
1023 Equiv<K> equality () {
1027 private transient volatile Object root;
1028 private final transient boolean readOnly;
1030 TrieMap (final Hashing<K> hashf, final Equiv<K> ef, final boolean readOnly) {
1031 this.hashingobj = hashf;
1032 this.equalityobj = ef;
1033 this.readOnly = readOnly;
1036 TrieMap (final Object r, final Hashing<K> hashf, final Equiv<K> ef, boolean readOnly) {
1037 this(hashf, ef, readOnly);
1041 public TrieMap (final Hashing<K> hashf, final Equiv<K> ef) {
1042 this(INode.newRootNode(), hashf, ef, false);
1046 this (new Default<K> (), Equiv.universal);
1049 /* internal methods */
1051 // private void writeObject(java.io.ObjectOutputStream out) {
1052 // out.writeObject(hashf);
1053 // out.writeObject(ef);
1055 // Iterator it = iterator();
1056 // while (it.hasNext) {
1057 // val (k, v) = it.next();
1058 // out.writeObject(k);
1059 // out.writeObject(v);
1061 // out.writeObject(TrieMapSerializationEnd);
1064 // private TrieMap readObject(java.io.ObjectInputStream in) {
1065 // root = INode.newRootNode();
1066 // rootupdater = AtomicReferenceFieldUpdater.newUpdater(TrieMap.class,
1067 // Object.class, "root");
1069 // hashingobj = in.readObject();
1070 // equalityobj = in.readObject();
1072 // Object obj = null;
1074 // obj = in.readObject();
1075 // if (obj != TrieMapSerializationEnd) {
1077 // V = (V)in.readObject();
1080 // } while (obj != TrieMapSerializationEnd);
1083 final boolean CAS_ROOT (Object ov, Object nv) {
1085 throw new IllegalStateException("Attempted to modify a read-only snapshot");
1087 return ROOT_UPDATER.compareAndSet (this, ov, nv);
1090 // FIXME: abort = false by default
1091 final INode<K, V> readRoot (boolean abort) {
1092 return RDCSS_READ_ROOT (abort);
1095 final INode<K, V> readRoot () {
1096 return RDCSS_READ_ROOT (false);
1099 final INode<K, V> RDCSS_READ_ROOT () {
1100 return RDCSS_READ_ROOT (false);
1103 final INode<K, V> RDCSS_READ_ROOT (boolean abort) {
1104 Object r = /* READ */root;
1105 if (r instanceof INode)
1106 return (INode<K, V>) r;
1107 else if (r instanceof RDCSS_Descriptor) {
1108 return RDCSS_Complete (abort);
1110 throw new RuntimeException ("Should not happen");
1113 private final INode<K, V> RDCSS_Complete (final boolean abort) {
1115 Object v = /* READ */root;
1116 if (v instanceof INode)
1117 return (INode<K, V>) v;
1118 else if (v instanceof RDCSS_Descriptor) {
1119 RDCSS_Descriptor<K, V> desc = (RDCSS_Descriptor<K, V>) v;
1120 INode<K, V> ov = desc.old;
1121 MainNode<K, V> exp = desc.expectedmain;
1122 INode<K, V> nv = desc.nv;
1125 if (CAS_ROOT (desc, ov))
1128 // return RDCSS_Complete (abort);
1133 MainNode<K, V> oldmain = ov.gcasRead (this);
1134 if (oldmain == exp) {
1135 if (CAS_ROOT (desc, nv)) {
1136 desc.committed = true;
1139 // return RDCSS_Complete (abort);
1144 if (CAS_ROOT (desc, ov))
1147 // return RDCSS_Complete (abort);
1156 throw new RuntimeException ("Should not happen");
1160 private boolean RDCSS_ROOT (final INode<K, V> ov, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
1161 RDCSS_Descriptor<K, V> desc = new RDCSS_Descriptor<K, V> (ov, expectedmain, nv);
1162 if (CAS_ROOT (ov, desc)) {
1163 RDCSS_Complete (false);
1164 return /* READ */desc.committed;
1169 private void inserthc (final K k, final int hc, final V v) {
1171 INode<K, V> r = RDCSS_READ_ROOT ();
1172 if (!r.rec_insert (k, v, hc, 0, null, r.gen, this)) {
1173 // inserthc (k, hc, v);
1181 private Option<V> insertifhc (final K k, final int hc, final V v, final Object cond) {
1183 INode<K, V> r = RDCSS_READ_ROOT ();
1185 Option<V> ret = r.rec_insertif (k, v, hc, cond, 0, null, r.gen, this);
1187 // return insertifhc (k, hc, v, cond);
1195 private Object lookuphc (final K k, final int hc) {
1197 INode<K, V> r = RDCSS_READ_ROOT ();
1198 Object res = r.rec_lookup (k, hc, 0, null, r.gen, this);
1199 if (res == INodeBase.RESTART) {
1200 // return lookuphc (k, hc);
1208 private Option<V> removehc (final K k, final V v, final int hc) {
1210 INode<K, V> r = RDCSS_READ_ROOT ();
1211 Option<V> res = r.rec_remove (k, v, hc, 0, null, r.gen, this);
1215 // return removehc (k, v, hc);
1223 * Ensure this instance is read-write, throw UnsupportedOperationException
1224 * otherwise. Used by Map-type methods for quick check.
1226 private void ensureReadWrite() {
1228 throw new UnsupportedOperationException("Attempted to modify a read-only view");
1232 public String string () {
1233 // RDCSS_READ_ROOT().string(0);
1237 /* public methods */
1239 // public Seq<V> seq() {
1243 // override def par = new ParTrieMap(this)
1245 // static TrieMap empty() {
1246 // return new TrieMap();
1249 final boolean isReadOnly () {
1253 final boolean nonReadOnly () {
1258 * Returns a snapshot of this TrieMap. This operation is lock-free and
1261 * The snapshot is lazily updated - the first time some branch in the
1262 * snapshot or this TrieMap are accessed, they are rewritten. This means
1263 * that the work of rebuilding both the snapshot and this TrieMap is
1264 * distributed across all the threads doing updates or accesses subsequent
1265 * to the snapshot creation.
1268 final public TrieMap<K, V> snapshot () {
1270 INode<K, V> r = RDCSS_READ_ROOT ();
1271 final MainNode<K, V> expmain = r.gcasRead (this);
1272 if (RDCSS_ROOT (r, expmain, r.copyToGen (new Gen (), this)))
1273 return new TrieMap<K, V> (r.copyToGen (new Gen (), this), hashing (), equality (), readOnly);
1275 // return snapshot ();
1283 * Returns a read-only snapshot of this TrieMap. This operation is lock-free
1286 * The snapshot is lazily updated - the first time some branch of this
1287 * TrieMap are accessed, it is rewritten. The work of creating the snapshot
1288 * is thus distributed across subsequent updates and accesses on this
1289 * TrieMap by all threads. Note that the snapshot itself is never rewritten
1290 * unlike when calling the `snapshot` method, but the obtained snapshot
1291 * cannot be modified.
1293 * This method is used by other methods such as `size` and `iterator`.
1295 final public TrieMap<K, V> readOnlySnapshot () {
1296 // Is it a snapshot of a read-only snapshot?
1301 INode<K, V> r = RDCSS_READ_ROOT ();
1302 MainNode<K, V> expmain = r.gcasRead (this);
1303 if (RDCSS_ROOT (r, expmain, r.copyToGen (new Gen (), this)))
1304 return new TrieMap<K, V> (r, hashing (), equality (), true);
1306 // return readOnlySnapshot ();
1312 final public void clear () {
1314 INode<K, V> r = RDCSS_READ_ROOT ();
1315 if (!RDCSS_ROOT (r, r.gcasRead (this), INode.<K, V>newRootNode ())) {
1324 int computeHash (K k) {
1325 return hashingobj.hash (k);
1328 final V lookup (K k) {
1329 int hc = computeHash (k);
1330 // return (V) lookuphc (k, hc);
1331 Object o = lookuphc (k, hc);
1332 if(o instanceof Some) {
1333 return ((Some<V>)o).get ();
1334 } else if(o instanceof None)
1340 final V apply (K k) {
1341 int hc = computeHash (k);
1342 Object res = lookuphc (k, hc);
1344 throw new NoSuchElementException ();
1349 // final public Option<V> get (K k) {
1350 // int hc = computeHash (k);
1351 // return Option.makeOption ((V)lookuphc (k, hc));
1354 final public V get (Object k) {
1355 return lookup((K)k);
1358 final public Option<V> putOpt(Object key, Object value) {
1359 int hc = computeHash ((K)key);
1360 return insertifhc ((K)key, hc, (V)value, null);
1364 final public V put (Object key, Object value) {
1366 int hc = computeHash ((K)key);
1367 Option<V> ov = insertifhc ((K)key, hc, (V)value, null);
1368 if(ov instanceof Some) {
1369 Some<V> sv = (Some<V>)ov;
1375 final public void update (K k, V v) {
1376 int hc = computeHash (k);
1377 inserthc (k, hc, v);
1380 final public TrieMap<K, V> add (K k, V v) {
1385 final Option<V> removeOpt (K k) {
1386 int hc = computeHash (k);
1387 return removehc (k, (V) null, hc);
1391 final public V remove (Object k) {
1393 int hc = computeHash ((K)k);
1394 Option<V> ov = removehc ((K)k, (V) null, hc);
1395 if(ov instanceof Some) {
1396 Some<V> sv = (Some<V>)ov;
1402 // final public TrieMap<K, V> remove (Object k) {
1403 // removeOpt ((K)k);
1407 final public Option<V> putIfAbsentOpt (K k, V v) {
1408 int hc = computeHash (k);
1409 return insertifhc (k, hc, v, INode.KEY_ABSENT);
1413 final public V putIfAbsent (Object k, Object v) {
1415 int hc = computeHash ((K)k);
1416 Option<V> ov = insertifhc ((K)k, hc, (V)v, INode.KEY_ABSENT);
1417 if(ov instanceof Some) {
1418 Some<V> sv = (Some<V>)ov;
1425 public boolean remove (Object k, Object v) {
1427 int hc = computeHash ((K)k);
1428 return removehc ((K)k, (V)v, hc).nonEmpty ();
1432 public boolean replace (K k, V oldvalue, V newvalue) {
1434 int hc = computeHash (k);
1435 return insertifhc (k, hc, newvalue, (Object) oldvalue).nonEmpty ();
1438 public Option<V> replaceOpt (K k, V v) {
1439 int hc = computeHash (k);
1440 return insertifhc (k, hc, v, INode.KEY_PRESENT);
1444 public V replace (Object k, Object v) {
1446 int hc = computeHash ((K)k);
1447 Option<V> ov = insertifhc ((K)k, hc, (V)v, INode.KEY_PRESENT);
1448 if(ov instanceof Some) {
1449 Some<V> sv = (Some<V>)ov;
1456 * Return an iterator over a TrieMap.
1458 * If this is a read-only snapshot, it would return a read-only iterator.
1460 * If it is the original TrieMap or a non-readonly snapshot, it would return
1461 * an iterator that would allow for updates.
1465 public Iterator<Map.Entry<K, V>> iterator () {
1466 if (!nonReadOnly ())
1467 return readOnlySnapshot ().readOnlyIterator ();
1469 return new TrieMapIterator<K, V> (0, this);
1473 * Return an iterator over a TrieMap.
1474 * This is a read-only iterator.
1478 public Iterator<Map.Entry<K, V>> readOnlyIterator () {
1480 return readOnlySnapshot ().readOnlyIterator ();
1482 return new TrieMapReadOnlyIterator<K, V> (0, this);
1485 private int cachedSize () {
1486 INode<K, V> r = RDCSS_READ_ROOT ();
1487 return r.cachedSize (this);
1490 public int size () {
1492 return readOnlySnapshot ().size ();
1494 return cachedSize ();
1497 String stringPrefix () {
1502 * This iterator is a read-only one and does not allow for any update
1503 * operations on the underlying data structure.
1508 private static class TrieMapReadOnlyIterator<K, V> extends TrieMapIterator<K, V> {
1509 TrieMapReadOnlyIterator (int level, final TrieMap<K, V> ct, boolean mustInit) {
1510 super (level, ct, mustInit);
1513 TrieMapReadOnlyIterator (int level, TrieMap<K, V> ct) {
1514 this (level, ct, true);
1516 void initialize () {
1517 assert (ct.isReadOnly ());
1518 super.initialize ();
1521 public void remove () {
1522 throw new UnsupportedOperationException ("Operation not supported for read-only iterators");
1525 Map.Entry<K, V> nextEntry(final Map.Entry<K, V> rr) {
1526 // Return non-updatable entry
1531 private static class TrieMapIterator<K, V> implements java.util.Iterator<Map.Entry<K, V>> {
1533 protected TrieMap<K, V> ct;
1534 private final boolean mustInit;
1535 private BasicNode[][] stack = new BasicNode[7][];
1536 private int[] stackpos = new int[7];
1537 private int depth = -1;
1538 private Iterator<Map.Entry<K, V>> subiter = null;
1539 private KVNode<K, V> current = null;
1540 private Map.Entry<K, V> lastReturned = null;
1542 TrieMapIterator (int level, final TrieMap<K, V> ct, boolean mustInit) {
1545 this.mustInit = mustInit;
1550 TrieMapIterator (int level, TrieMap<K, V> ct) {
1551 this (level, ct, true);
1555 public boolean hasNext () {
1556 return (current != null) || (subiter != null);
1559 public Map.Entry<K, V> next () {
1561 Map.Entry<K, V> r = null;
1562 if (subiter != null) {
1563 r = subiter.next ();
1566 r = current.kvPair ();
1571 if(r instanceof Map.Entry) {
1572 final Map.Entry<K, V> rr = (Map.Entry<K, V>)r;
1573 return nextEntry(rr);
1577 // return Iterator.empty ().next ();
1582 Map.Entry<K, V> nextEntry(final Map.Entry<K, V> rr) {
1583 return new Map.Entry<K, V>() {
1584 private V updated = null;
1587 public K getKey () {
1588 return rr.getKey ();
1592 public V getValue () {
1593 return (updated == null)?rr.getValue (): updated;
1597 public V setValue (V value) {
1599 return ct.replace (getKey (), value);
1604 private void readin (INode<K, V> in) {
1605 MainNode<K, V> m = in.gcasRead (ct);
1606 if (m instanceof CNode) {
1607 CNode<K, V> cn = (CNode<K, V>) m;
1609 stack [depth] = cn.array;
1610 stackpos [depth] = -1;
1612 } else if (m instanceof TNode) {
1613 current = (TNode<K, V>) m;
1614 } else if (m instanceof LNode) {
1615 subiter = ((LNode<K, V>) m).listmap.iterator ();
1617 } else if (m == null) {
1623 private void checkSubiter () {
1624 if (!subiter.hasNext ()) {
1631 void initialize () {
1632 // assert (ct.isReadOnly ());
1633 INode<K, V> r = ct.RDCSS_READ_ROOT ();
1639 int npos = stackpos [depth] + 1;
1640 if (npos < stack [depth].length) {
1641 stackpos [depth] = npos;
1642 BasicNode elem = stack [depth] [npos];
1643 if (elem instanceof SNode) {
1644 current = (SNode<K, V>) elem;
1645 } else if (elem instanceof INode) {
1646 readin ((INode<K, V>) elem);
1656 protected TrieMapIterator<K, V> newIterator (int _lev, TrieMap<K, V> _ct, boolean _mustInit) {
1657 return new TrieMapIterator<K, V> (_lev, _ct, _mustInit);
1660 protected void dupTo (TrieMapIterator<K, V> it) {
1661 it.level = this.level;
1663 it.depth = this.depth;
1664 it.current = this.current;
1666 // these need a deep copy
1667 System.arraycopy (this.stack, 0, it.stack, 0, 7);
1668 System.arraycopy (this.stackpos, 0, it.stackpos, 0, 7);
1670 // this one needs to be evaluated
1671 if (this.subiter == null)
1674 List<Map.Entry<K, V>> lst = toList (this.subiter);
1675 this.subiter = lst.iterator ();
1676 it.subiter = lst.iterator ();
1680 // /** Returns a sequence of iterators over subsets of this iterator.
1681 // * It's used to ease the implementation of splitters for a parallel
1682 // version of the TrieMap.
1684 // protected def subdivide(): Seq[Iterator[(K, V)]] = if (subiter ne
1686 // // the case where an LNode is being iterated
1692 // } else if (depth == -1) {
1697 // while (d <= depth) {
1698 // val rem = stack(d).length - 1 - stackpos(d)
1700 // val (arr1, arr2) = stack(d).drop(stackpos(d) + 1).splitAt(rem / 2)
1703 // val it = newIterator(level + 1, ct, false)
1704 // it.stack(0) = arr2
1705 // it.stackpos(0) = -1
1707 // it.advance() // <-- fix it
1709 // return Seq(this, it)
1717 private List<Entry<K, V>> toList (Iterator<Entry<K, V>> it) {
1718 ArrayList<Entry<K, V>> list = new ArrayList<Map.Entry<K, V>> ();
1719 while (it.hasNext ()) {
1720 list.add (it.next ());
1725 void printDebug () {
1726 System.out.println ("ctrie iterator");
1727 System.out.println (Arrays.toString (stackpos));
1728 System.out.println ("depth: " + depth);
1729 System.out.println ("curr.: " + current);
1730 // System.out.println(stack.mkString("\n"));
1734 public void remove () {
1735 if (lastReturned != null) {
1736 ct.remove (lastReturned.getKey ());
1737 lastReturned = null;
1739 throw new IllegalStateException();
1744 /** Only used for ctrie serialization. */
1745 // @SerialVersionUID(0L - 7237891413820527142L)
1746 private static long TrieMapSerializationEnd = 0L - 7237891413820527142L;
1749 public boolean containsKey (Object key) {
1750 return lookup ((K) key) != null;
1755 public Set<Map.Entry<K, V>> entrySet () {
1760 * Support for EntrySet operations required by the Map interface
1763 final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
1766 public Iterator<Map.Entry<K, V>> iterator () {
1767 return TrieMap.this.iterator ();
1771 public final boolean contains (final Object o) {
1772 if (!(o instanceof Map.Entry)) {
1775 final Map.Entry<K, V> e = (Map.Entry<K, V>) o;
1776 final K k = e.getKey ();
1777 final V v = lookup (k);
1782 public final boolean remove (final Object o) {
1783 if (!(o instanceof Map.Entry)) {
1786 final Map.Entry<K, V> e = (Map.Entry<K, V>) o;
1787 final K k = e.getKey ();
1788 return null != TrieMap.this.remove (k);
1792 public final int size () {
1794 for (final Iterator<?> i = iterator (); i.hasNext (); i.next ()) {
1801 public final void clear () {
1802 TrieMap.this.clear ();
1806 private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
1807 inputStream.defaultReadObject();
1808 this.root = INode.newRootNode();
1810 final boolean ro = inputStream.readBoolean();
1811 final int size = inputStream.readInt();
1812 for (int i = 0; i < size; ++i) {
1813 final K key = (K)inputStream.readObject();
1814 final V value = (V)inputStream.readObject();
1818 // Propagate the read-only bit
1820 READONLY_FIELD.setBoolean(this, ro);
1821 } catch (IllegalAccessException e) {
1822 throw new IOException("Failed to set read-only flag", e);
1826 private void writeObject(ObjectOutputStream outputStream) throws IOException {
1827 outputStream.defaultWriteObject();
1829 final Map<K, V> ro = readOnlySnapshot();
1830 outputStream.writeBoolean(isReadOnly());
1831 outputStream.writeInt(ro.size());
1833 for (Entry<K, V> e : ro.entrySet()) {
1834 outputStream.writeObject(e.getKey());
1835 outputStream.writeObject(e.getValue());