2 * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.opendaylight.yangtools.triemap;
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectOutputStream;
21 import java.io.Serializable;
22 import java.lang.reflect.Field;
23 import java.util.AbstractMap;
24 import java.util.AbstractSet;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Iterator;
28 import java.util.List;
31 import java.util.concurrent.ConcurrentMap;
32 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
35 * This is a port of Scala's TrieMap class from the Scala Collections library. This implementation does not support
36 * null keys nor null values.
38 * @author Roman Levenstein <romixlev@gmail.com>
43 @SuppressWarnings({"unchecked", "rawtypes", "unused"})
44 public final class TrieMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,V>, Serializable {
45 private static final AtomicReferenceFieldUpdater<TrieMap, Object> ROOT_UPDATER =
46 AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root");
47 private static final long serialVersionUID = 1L;
48 private static final Field READONLY_FIELD;
53 f = TrieMap.class.getDeclaredField("readOnly");
54 } catch (NoSuchFieldException e) {
55 throw new ExceptionInInitializerError(e);
56 } catch (SecurityException e) {
57 throw new ExceptionInInitializerError(e);
59 f.setAccessible(true);
66 private transient final EntrySet entrySet = new EntrySet ();
68 private final Equivalence<? super K> equiv;
70 private transient volatile Object root;
71 private final transient boolean readOnly;
73 TrieMap(final INode<K, V> r, final Equivalence<? super K> equiv, final boolean readOnly) {
76 this.readOnly = readOnly;
80 this(newRootNode(), Equivalence.equals(), false);
83 /* internal methods */
85 private static <K,V> INode<K, V> newRootNode() {
86 final Gen gen = new Gen();
87 return new INode<>(gen, new CNode<>(gen));
90 final boolean CAS_ROOT (final Object ov, final Object nv) {
92 throw new IllegalStateException("Attempted to modify a read-only snapshot");
94 return ROOT_UPDATER.compareAndSet (this, ov, nv);
97 // FIXME: abort = false by default
98 final INode<K, V> readRoot(final boolean abort) {
99 return RDCSS_READ_ROOT(abort);
102 final INode<K, V> readRoot() {
103 return RDCSS_READ_ROOT(false);
106 final INode<K, V> RDCSS_READ_ROOT() {
107 return RDCSS_READ_ROOT(false);
110 final INode<K, V> RDCSS_READ_ROOT(final boolean abort) {
111 final Object r = /* READ */root;
112 if (r instanceof INode) {
113 return (INode<K, V>) r;
114 } else if (r instanceof RDCSS_Descriptor) {
115 return RDCSS_Complete (abort);
117 throw new IllegalStateException("Unhandled root " + r);
121 private INode<K, V> RDCSS_Complete(final boolean abort) {
123 final Object v = /* READ */root;
124 if (v instanceof INode) {
125 return (INode<K, V>) v;
128 if (v instanceof RDCSS_Descriptor) {
129 final RDCSS_Descriptor<K, V> desc = (RDCSS_Descriptor<K, V>) v;
130 final INode<K, V> ov = desc.old;
131 final MainNode<K, V> exp = desc.expectedmain;
132 final INode<K, V> nv = desc.nv;
135 if (CAS_ROOT(desc, ov)) {
139 // Tail recursion: return RDCSS_Complete(abort);
143 final MainNode<K, V> oldmain = ov.gcasRead(this);
144 if (oldmain == exp) {
145 if (CAS_ROOT(desc, nv)) {
146 desc.committed = true;
150 // Tail recursion: return RDCSS_Complete(abort);
154 if (CAS_ROOT(desc, ov)) {
158 // Tail recursion: return RDCSS_Complete(abort);
162 throw new IllegalStateException("Unexpected root " + v);
166 private boolean RDCSS_ROOT(final INode<K, V> ov, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
167 final RDCSS_Descriptor<K, V> desc = new RDCSS_Descriptor<> (ov, expectedmain, nv);
168 if (CAS_ROOT(ov, desc)) {
169 RDCSS_Complete(false);
170 return /* READ */desc.committed;
176 private void inserthc(final K k, final int hc, final V v) {
178 final INode<K, V> r = RDCSS_READ_ROOT();
179 if (r.rec_insert(k, v, hc, 0, null, r.gen, this)) {
180 // Successful, we are done
184 // Tail recursion: inserthc(k, hc, v);
188 private Option<V> insertifhc(final K k, final int hc, final V v, final Object cond) {
190 final INode<K, V> r = RDCSS_READ_ROOT();
191 final Option<V> ret = r.rec_insertif(k, v, hc, cond, 0, null, r.gen, this);
196 // Tail recursion: return insertifhc(k, hc, v, cond);
200 private Object lookuphc(final K k, final int hc) {
202 final INode<K, V> r = RDCSS_READ_ROOT ();
203 final Object res = r.rec_lookup(k, hc, 0, null, r.gen, this);
204 if (!INode.RESTART.equals(res)) {
208 // Tail recursion: lookuphc(k, hc)
212 private Option<V> removehc(final K k, final V v, final int hc) {
214 final INode<K, V> r = RDCSS_READ_ROOT();
215 final Option<V> res = r.rec_remove(k, v, hc, 0, null, r.gen, this);
220 // Tail recursion: return removehc(k, v, hc);
225 * Ensure this instance is read-write, throw UnsupportedOperationException
226 * otherwise. Used by Map-type methods for quick check.
228 private void ensureReadWrite() {
230 throw new UnsupportedOperationException("Attempted to modify a read-only view");
234 boolean isReadOnly() {
238 boolean nonReadOnly() {
245 * Returns a snapshot of this TrieMap. This operation is lock-free and
248 * The snapshot is lazily updated - the first time some branch in the
249 * snapshot or this TrieMap are accessed, they are rewritten. This means
250 * that the work of rebuilding both the snapshot and this TrieMap is
251 * distributed across all the threads doing updates or accesses subsequent
252 * to the snapshot creation.
254 public TrieMap<K, V> snapshot() {
256 final INode<K, V> r = RDCSS_READ_ROOT();
257 final MainNode<K, V> expmain = r.gcasRead(this);
258 if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen(), this))) {
259 return new TrieMap<> (r.copyToGen(new Gen(), this), equiv, readOnly);
262 // Tail recursion: return snapshot();
267 * Returns a read-only snapshot of this TrieMap. This operation is lock-free
270 * The snapshot is lazily updated - the first time some branch of this
271 * TrieMap are accessed, it is rewritten. The work of creating the snapshot
272 * is thus distributed across subsequent updates and accesses on this
273 * TrieMap by all threads. Note that the snapshot itself is never rewritten
274 * unlike when calling the `snapshot` method, but the obtained snapshot
275 * cannot be modified.
277 * This method is used by other methods such as `size` and `iterator`.
279 public TrieMap<K, V> readOnlySnapshot() {
280 // Is it a snapshot of a read-only snapshot?
286 final INode<K, V> r = RDCSS_READ_ROOT();
287 final MainNode<K, V> expmain = r.gcasRead(this);
288 if (RDCSS_ROOT(r, expmain, r.copyToGen (new Gen(), this))) {
289 return new TrieMap<>(r, equiv, true);
292 // Tail recursion: return readOnlySnapshot();
297 public void clear() {
299 final INode<K, V> r = RDCSS_READ_ROOT();
300 if (RDCSS_ROOT(r, r.gcasRead(this), newRootNode())) {
306 int computeHash(final K k) {
307 return equiv.hash(k);
310 boolean equal(final K k1, final K k2) {
311 return equiv.equivalent(k1, k2);
314 V lookup(final K k) {
315 final int hc = computeHash (k);
316 // return (V) lookuphc (k, hc);
317 final Object o = lookuphc (k, hc);
318 if (o instanceof Some) {
319 return ((Some<V>)o).get ();
320 } else if (o instanceof None) {
328 public V get(final Object k) {
333 public V put(final K key, final V value) {
335 final int hc = computeHash(key);
336 final Option<V> ov = insertifhc (key, hc, value, null);
337 if (ov instanceof Some) {
338 Some<V> sv = (Some<V>)ov;
345 TrieMap<K, V> add(final K k, final V v) {
346 final int hc = computeHash (k);
352 public V remove(final Object k) {
354 final int hc = computeHash ((K)k);
355 final Option<V> ov = removehc ((K)k, (V) null, hc);
356 if (ov instanceof Some) {
357 Some<V> sv = (Some<V>)ov;
365 public V putIfAbsent(final K k, final V v) {
367 final int hc = computeHash (k);
368 final Option<V> ov = insertifhc (k, hc, v, INode.KEY_ABSENT);
369 if (ov instanceof Some) {
370 Some<V> sv = (Some<V>)ov;
378 public boolean remove(final Object k, final Object v) {
380 final int hc = computeHash ((K)k);
381 return removehc((K)k, (V)v, hc).nonEmpty();
385 public boolean replace(final K k, final V oldvalue, final V newvalue) {
387 final int hc = computeHash (k);
388 return insertifhc (k, hc, newvalue, oldvalue).nonEmpty();
392 public V replace(final K k, final V v) {
394 final int hc = computeHash (k);
395 final Option<V> ov = insertifhc (k, hc, v, INode.KEY_PRESENT);
396 if (ov instanceof Some) {
397 Some<V> sv = (Some<V>)ov;
405 * Return an iterator over a TrieMap.
407 * If this is a read-only snapshot, it would return a read-only iterator.
409 * If it is the original TrieMap or a non-readonly snapshot, it would return
410 * an iterator that would allow for updates.
414 Iterator<Entry<K, V>> iterator () {
415 if (!nonReadOnly()) {
416 return readOnlySnapshot().readOnlyIterator();
419 return new TrieMapIterator<> (0, this);
423 * Return an iterator over a TrieMap.
424 * This is a read-only iterator.
428 Iterator<Entry<K, V>> readOnlyIterator () {
430 return readOnlySnapshot().readOnlyIterator();
433 return new TrieMapReadOnlyIterator<>(0, this);
436 private int cachedSize() {
437 INode<K, V> r = RDCSS_READ_ROOT ();
438 return r.cachedSize (this);
444 return readOnlySnapshot().size ();
451 public boolean containsKey(final Object key) {
452 return lookup((K) key) != null;
456 public Set<Entry<K, V>> entrySet() {
460 private static final class RDCSS_Descriptor<K, V> {
462 MainNode<K, V> expectedmain;
464 volatile boolean committed = false;
466 RDCSS_Descriptor (final INode<K, V> old, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
468 this.expectedmain = expectedmain;
474 * This iterator is a read-only one and does not allow for any update
475 * operations on the underlying data structure.
480 private static final class TrieMapReadOnlyIterator<K, V> extends TrieMapIterator<K, V> {
481 TrieMapReadOnlyIterator (final int level, final TrieMap<K, V> ct, final boolean mustInit) {
482 super (level, ct, mustInit);
485 TrieMapReadOnlyIterator (final int level, final TrieMap<K, V> ct) {
486 this (level, ct, true);
490 assert (ct.isReadOnly ());
495 public void remove () {
496 throw new UnsupportedOperationException ("Operation not supported for read-only iterators");
500 Entry<K, V> nextEntry(final Entry<K, V> rr) {
501 // Return non-updatable entry
506 private static class TrieMapIterator<K, V> implements Iterator<Entry<K, V>> {
508 protected TrieMap<K, V> ct;
509 private final boolean mustInit;
510 private final BasicNode[][] stack = new BasicNode[7][];
511 private final int[] stackpos = new int[7];
512 private int depth = -1;
513 private Iterator<Entry<K, V>> subiter = null;
514 private KVNode<K, V> current = null;
515 private Entry<K, V> lastReturned = null;
517 TrieMapIterator (final int level, final TrieMap<K, V> ct, final boolean mustInit) {
520 this.mustInit = mustInit;
526 TrieMapIterator (final int level, final TrieMap<K, V> ct) {
527 this (level, ct, true);
532 public boolean hasNext () {
533 return (current != null) || (subiter != null);
537 public Entry<K, V> next () {
539 Entry<K, V> r = null;
540 if (subiter != null) {
544 r = current.kvPair ();
550 final Entry<K, V> rr = r;
551 return nextEntry(rr);
555 // return Iterator.empty ().next ();
560 Entry<K, V> nextEntry(final Entry<K, V> rr) {
561 return new Entry<K, V>() {
562 private V updated = null;
570 public V getValue () {
571 return (updated == null)?rr.getValue (): updated;
575 public V setValue (final V value) {
577 return ct.replace (getKey (), value);
582 private void readin (final INode<K, V> in) {
583 MainNode<K, V> m = in.gcasRead (ct);
584 if (m instanceof CNode) {
585 CNode<K, V> cn = (CNode<K, V>) m;
587 stack [depth] = cn.array;
588 stackpos [depth] = -1;
590 } else if (m instanceof TNode) {
591 current = (TNode<K, V>) m;
592 } else if (m instanceof LNode) {
593 subiter = ((LNode<K, V>) m).iterator();
595 } else if (m == null) {
601 private void checkSubiter () {
602 if (!subiter.hasNext ()) {
610 // assert (ct.isReadOnly ());
611 INode<K, V> r = ct.RDCSS_READ_ROOT ();
617 int npos = stackpos [depth] + 1;
618 if (npos < stack [depth].length) {
619 stackpos [depth] = npos;
620 BasicNode elem = stack [depth] [npos];
621 if (elem instanceof SNode) {
622 current = (SNode<K, V>) elem;
623 } else if (elem instanceof INode) {
624 readin ((INode<K, V>) elem);
635 protected TrieMapIterator<K, V> newIterator (final int _lev, final TrieMap<K, V> _ct, final boolean _mustInit) {
636 return new TrieMapIterator<> (_lev, _ct, _mustInit);
639 protected void dupTo (final TrieMapIterator<K, V> it) {
640 it.level = this.level;
642 it.depth = this.depth;
643 it.current = this.current;
645 // these need a deep copy
646 System.arraycopy (this.stack, 0, it.stack, 0, 7);
647 System.arraycopy (this.stackpos, 0, it.stackpos, 0, 7);
649 // this one needs to be evaluated
650 if (this.subiter == null) {
653 List<Entry<K, V>> lst = toList (this.subiter);
654 this.subiter = lst.iterator ();
655 it.subiter = lst.iterator ();
659 // /** Returns a sequence of iterators over subsets of this iterator.
660 // * It's used to ease the implementation of splitters for a parallel
661 // version of the TrieMap.
663 // protected def subdivide(): Seq[Iterator[(K, V)]] = if (subiter ne
665 // // the case where an LNode is being iterated
671 // } else if (depth == -1) {
676 // while (d <= depth) {
677 // val rem = stack(d).length - 1 - stackpos(d)
679 // val (arr1, arr2) = stack(d).drop(stackpos(d) + 1).splitAt(rem / 2)
682 // val it = newIterator(level + 1, ct, false)
683 // it.stack(0) = arr2
684 // it.stackpos(0) = -1
686 // it.advance() // <-- fix it
688 // return Seq(this, it)
696 private List<Entry<K, V>> toList (final Iterator<Entry<K, V>> it) {
697 ArrayList<Entry<K, V>> list = new ArrayList<> ();
698 while (it.hasNext ()) {
699 list.add (it.next ());
705 System.out.println ("ctrie iterator");
706 System.out.println (Arrays.toString (stackpos));
707 System.out.println ("depth: " + depth);
708 System.out.println ("curr.: " + current);
709 // System.out.println(stack.mkString("\n"));
713 public void remove () {
714 if (lastReturned != null) {
715 ct.remove (lastReturned.getKey ());
718 throw new IllegalStateException();
725 * Support for EntrySet operations required by the Map interface
727 private final class EntrySet extends AbstractSet<Entry<K, V>> {
730 public Iterator<Entry<K, V>> iterator () {
731 return TrieMap.this.iterator ();
735 public final boolean contains (final Object o) {
736 if (!(o instanceof Entry)) {
739 final Entry<K, V> e = (Entry<K, V>) o;
740 final K k = e.getKey ();
741 final V v = lookup (k);
746 public final boolean remove (final Object o) {
747 if (!(o instanceof Entry)) {
750 final Entry<K, V> e = (Entry<K, V>) o;
751 final K k = e.getKey();
752 return null != TrieMap.this.remove(k);
756 public final int size () {
758 for (final Iterator<?> i = iterator (); i.hasNext (); i.next ()) {
765 public final void clear () {
766 TrieMap.this.clear ();
770 private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
771 inputStream.defaultReadObject();
772 this.root = newRootNode();
774 final boolean ro = inputStream.readBoolean();
775 final int size = inputStream.readInt();
776 for (int i = 0; i < size; ++i) {
777 final K key = (K)inputStream.readObject();
778 final V value = (V)inputStream.readObject();
782 // Propagate the read-only bit
784 READONLY_FIELD.setBoolean(this, ro);
785 } catch (IllegalAccessException e) {
786 throw new IOException("Failed to set read-only flag", e);
790 private void writeObject(final ObjectOutputStream outputStream) throws IOException {
791 outputStream.defaultWriteObject();
793 final Map<K, V> ro = readOnlySnapshot();
794 outputStream.writeBoolean(isReadOnly());
795 outputStream.writeInt(ro.size());
797 for (Entry<K, V> e : ro.entrySet()) {
798 outputStream.writeObject(e.getKey());
799 outputStream.writeObject(e.getValue());