X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=third-party%2Ftriemap%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Ftriemap%2FTrieMap.java;h=b5db32c4957ead56fc48d64ba08512a9f8240a30;hb=7dc59ccbdd4fea87fe9719f8095547b8321079f8;hp=f92b7d0a38f957d10d63b36c9b6f4aa018b1b4fa;hpb=a977b02cb1bf3a485601c4a3d239b82674c3041a;p=yangtools.git diff --git a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java index f92b7d0a38..b5db32c495 100644 --- a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java +++ b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java @@ -15,698 +15,192 @@ */ package org.opendaylight.yangtools.triemap; -import com.google.common.base.Preconditions; -import java.io.ObjectStreamException; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ForwardingObject; import java.io.Serializable; -import java.util.AbstractMap; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.Collection; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.function.BiFunction; +import java.util.function.Function; -/*** +/** * This is a port of Scala's TrieMap class from the Scala Collections library. This implementation does not support * null keys nor null values. * - * @author Roman Levenstein <romixlev@gmail.com> + * @author Aleksandar Prokopec (original Scala implementation) + * @author Roman Levenstein (original Java 6 port) + * @author Robert Varga * - * @param - * @param + * @param the type of keys maintained by this map + * @param the type of mapped values + * @deprecated use {@link tech.pantheon.triemap.TrieMap} instead. */ -@SuppressWarnings({"unchecked", "rawtypes", "unused"}) -public final class TrieMap extends AbstractMap implements ConcurrentMap, Serializable { - private static final AtomicReferenceFieldUpdater ROOT_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root"); +@Deprecated +public abstract class TrieMap extends ForwardingObject implements ConcurrentMap, Serializable { private static final long serialVersionUID = 1L; - /** - * EntrySet - */ - private final EntrySet entrySet = new EntrySet(); - private final Equivalence equiv; - private final boolean readOnly; - - private volatile Object root; - - private TrieMap(final INode r, final Equivalence equiv, final boolean readOnly) { - this.root = r; - this.equiv = equiv; - this.readOnly = readOnly; - } - - TrieMap(final Equivalence equiv) { - this(newRootNode(), equiv, false); - } - - public TrieMap() { - this(Equivalence.equals()); - } - - /* internal methods */ - - final Equivalence equiv() { - return equiv; - } - - private static INode newRootNode() { - final Gen gen = new Gen(); - return new INode<>(gen, new CNode<>(gen)); - } + private final tech.pantheon.triemap.TrieMap delegate; - final boolean CAS_ROOT(final Object ov, final Object nv) { - Preconditions.checkState(!readOnly, "Attempted to modify a read-only snapshot"); - return ROOT_UPDATER.compareAndSet (this, ov, nv); + TrieMap(final tech.pantheon.triemap.TrieMap delegate) { + this.delegate = requireNonNull(delegate); } - // FIXME: abort = false by default - final INode readRoot(final boolean abort) { - return RDCSS_READ_ROOT(abort); + public static MutableTrieMap create() { + return new MutableTrieMap<>(tech.pantheon.triemap.TrieMap.create()); } - final INode readRoot() { - return RDCSS_READ_ROOT(false); - } - - final INode RDCSS_READ_ROOT() { - return RDCSS_READ_ROOT(false); - } - - final INode RDCSS_READ_ROOT(final boolean abort) { - final Object r = /* READ */root; - if (r instanceof INode) { - return (INode) r; - } else if (r instanceof RDCSS_Descriptor) { - return RDCSS_Complete (abort); - } else { - throw new IllegalStateException("Unhandled root " + r); - } - } - - private INode RDCSS_Complete(final boolean abort) { - while (true) { - final Object v = /* READ */root; - if (v instanceof INode) { - return (INode) v; - } - - if (v instanceof RDCSS_Descriptor) { - final RDCSS_Descriptor desc = (RDCSS_Descriptor) v; - final INode ov = desc.old; - final MainNode exp = desc.expectedmain; - final INode nv = desc.nv; - - if (abort) { - if (CAS_ROOT(desc, ov)) { - return ov; - } - - // Tail recursion: return RDCSS_Complete(abort); - continue; - } - - final MainNode oldmain = ov.gcasRead(this); - if (oldmain == exp) { - if (CAS_ROOT(desc, nv)) { - desc.committed = true; - return nv; - } - - // Tail recursion: return RDCSS_Complete(abort); - continue; - } - - if (CAS_ROOT(desc, ov)) { - return ov; - } - - // Tail recursion: return RDCSS_Complete(abort); - continue; - } - - throw new IllegalStateException("Unexpected root " + v); - } - } - - private boolean RDCSS_ROOT(final INode ov, final MainNode expectedmain, final INode nv) { - final RDCSS_Descriptor desc = new RDCSS_Descriptor<> (ov, expectedmain, nv); - if (CAS_ROOT(ov, desc)) { - RDCSS_Complete(false); - return /* READ */desc.committed; - } - - return false; - } - - private void inserthc(final K k, final int hc, final V v) { - while (true) { - final INode r = RDCSS_READ_ROOT(); - if (r.rec_insert(k, v, hc, 0, null, r.gen, this)) { - // Successful, we are done - return; - } - - // Tail recursion: inserthc(k, hc, v); - } - } - - private Optional insertifhc(final K k, final int hc, final V v, final Object cond) { - while (true) { - final INode r = RDCSS_READ_ROOT(); - final Optional ret = r.rec_insertif(k, v, hc, cond, 0, null, r.gen, this); - if (ret != null) { - return ret; - } - - // Tail recursion: return insertifhc(k, hc, v, cond); - } - } - - private Object lookuphc(final K k, final int hc) { - while (true) { - final INode r = RDCSS_READ_ROOT (); - final Object res = r.rec_lookup(k, hc, 0, null, r.gen, this); - if (!INode.RESTART.equals(res)) { - return res; - } - - // Tail recursion: lookuphc(k, hc) - } - } - - private Optional removehc(final K k, final V v, final int hc) { - while (true) { - final INode r = RDCSS_READ_ROOT(); - final Optional res = r.rec_remove(k, v, hc, 0, null, r.gen, this); - if (res != null) { - return res; - } - - // Tail recursion: return removehc(k, v, hc); - } - } - - /** - * Ensure this instance is read-write, throw UnsupportedOperationException - * otherwise. Used by Map-type methods for quick check. - */ - private void ensureReadWrite() { - if (readOnly) { - throw new UnsupportedOperationException("Attempted to modify a read-only view"); - } - } - - boolean isReadOnly() { - return readOnly; - } - - /* public methods */ - /** * Returns a snapshot of this TrieMap. This operation is lock-free and - * linearizable. + * linearizable. Modification operations on this Map and the returned one + * are isolated from each other. * + *

* The snapshot is lazily updated - the first time some branch in the * snapshot or this TrieMap are accessed, they are rewritten. This means * that the work of rebuilding both the snapshot and this TrieMap is * distributed across all the threads doing updates or accesses subsequent * to the snapshot creation. + * + * @return A read-write TrieMap containing the contents of this map. */ - public TrieMap snapshot() { - while (true) { - final INode r = RDCSS_READ_ROOT(); - final MainNode expmain = r.gcasRead(this); - if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen(), this))) { - return new TrieMap<> (r.copyToGen(new Gen(), this), equiv, readOnly); - } - - // Tail recursion: return snapshot(); - } - } + public abstract TrieMap mutableSnapshot(); /** * Returns a read-only snapshot of this TrieMap. This operation is lock-free * and linearizable. * + *

* The snapshot is lazily updated - the first time some branch of this * TrieMap are accessed, it is rewritten. The work of creating the snapshot * is thus distributed across subsequent updates and accesses on this * TrieMap by all threads. Note that the snapshot itself is never rewritten - * unlike when calling the `snapshot` method, but the obtained snapshot + * unlike when calling {@link #mutableSnapshot()}, but the obtained snapshot * cannot be modified. * + *

* This method is used by other methods such as `size` and `iterator`. + * + * @return A read-only TrieMap containing the contents of this map. */ - public TrieMap readOnlySnapshot() { - // Is it a snapshot of a read-only snapshot? - if (readOnly) { - return this; - } - - while (true) { - final INode r = RDCSS_READ_ROOT(); - final MainNode expmain = r.gcasRead(this); - if (RDCSS_ROOT(r, expmain, r.copyToGen (new Gen(), this))) { - return new TrieMap<>(r, equiv, true); - } - - // Tail recursion: return readOnlySnapshot(); - } - } + public abstract ImmutableTrieMap immutableSnapshot(); @Override - public void clear() { - while (true) { - final INode r = RDCSS_READ_ROOT(); - if (RDCSS_ROOT(r, r.gcasRead(this), newRootNode())) { - return; - } - } + public final boolean containsKey(final Object key) { + return delegate.containsKey(key); } - int computeHash(final K k) { - return equiv.hash(k); + @Override + public final boolean containsValue(final Object value) { + return delegate.containsValue(value); } - boolean equal(final K k1, final K k2) { - return equiv.equivalent(k1, k2); + @Override + public final Set> entrySet() { + return delegate.entrySet(); } - V lookup(final K k) { - return (V) lookuphc(k, computeHash(k)); + @Override + public final Set keySet() { + return delegate.keySet(); } @Override - public V get(final Object k) { - return lookup((K)k); + public final V get(final Object key) { + return delegate.get(key); } @Override - public V put(final K key, final V value) { - ensureReadWrite(); - final int hc = computeHash(key); - return insertifhc (key, hc, value, null).orElse(null); + public final void clear() { + delegate.clear(); } - void add(final K k, final V v) { - inserthc(k, computeHash(k), v); + @Override + public final V put(final K key, final V value) { + return delegate.put(key, value); } @Override - public V remove(final Object k) { - ensureReadWrite(); - final int hc = computeHash ((K)k); - return removehc ((K)k, (V) null, hc).orElse(null); + public final V putIfAbsent(final K key, final V value) { + return delegate.putIfAbsent(key, value); } @Override - public V putIfAbsent(final K k, final V v) { - ensureReadWrite(); - final int hc = computeHash (k); - return insertifhc (k, hc, v, INode.KEY_ABSENT).orElse(null); + public final V remove(final Object key) { + return delegate.remove(key); } @Override - public boolean remove(final Object k, final Object v) { - ensureReadWrite(); - final int hc = computeHash ((K)k); - return removehc((K)k, (V)v, hc).isPresent(); + public final boolean remove(final Object key, final Object value) { + return delegate.remove(key, value); } @Override - public boolean replace(final K k, final V oldvalue, final V newvalue) { - ensureReadWrite(); - final int hc = computeHash (k); - return insertifhc (k, hc, newvalue, oldvalue).isPresent(); + public final boolean replace(final K key, final V oldValue, final V newValue) { + return delegate.replace(key, oldValue, newValue); } @Override - public V replace(final K k, final V v) { - ensureReadWrite(); - final int hc = computeHash (k); - return insertifhc (k, hc, v, INode.KEY_PRESENT).orElse(null); + public final V replace(final K key, final V value) { + return delegate.replace(key, value); } - /*** - * Return an iterator over a TrieMap. - * - * If this is a read-only snapshot, it would return a read-only iterator. - * - * If it is the original TrieMap or a non-readonly snapshot, it would return - * an iterator that would allow for updates. - * - * @return - */ - Iterator> iterator() { - return readOnly ? new TrieMapReadOnlyIterator<>(0, this) : new TrieMapIterator<>(0, this); + @Override + public final int size() { + return delegate.size(); } - /*** - * Return an iterator over a TrieMap. - * This is a read-only iterator. - * - * @return - */ - Iterator> readOnlyIterator() { - return new TrieMapReadOnlyIterator<>(0, readOnly ? this : readOnlySnapshot()); + @Override + public final boolean isEmpty() { + return delegate.isEmpty(); } - private int cachedSize() { - INode r = RDCSS_READ_ROOT (); - return r.cachedSize (this); + @Override + public final void putAll(final Map m) { + delegate.putAll(m); } @Override - public int size() { - return readOnly ? cachedSize() : readOnlySnapshot().size(); + public final Collection values() { + return delegate.values(); } @Override - public boolean containsKey(final Object key) { - return lookup((K) key) != null; + public final V compute(final K key, final BiFunction remappingFunction) { + return delegate.compute(key, remappingFunction); } @Override - public Set> entrySet() { - return entrySet; + public final V computeIfAbsent(final K key, final Function mappingFunction) { + return delegate.computeIfAbsent(key, mappingFunction); } - private Object writeReplace() throws ObjectStreamException { - return new ExternalForm(this); + @Override + public final V computeIfPresent(final K key, + final BiFunction remappingFunction) { + return delegate.computeIfPresent(key, remappingFunction); } - private static final class RDCSS_Descriptor { - INode old; - MainNode expectedmain; - INode nv; - volatile boolean committed = false; - - RDCSS_Descriptor (final INode old, final MainNode expectedmain, final INode nv) { - this.old = old; - this.expectedmain = expectedmain; - this.nv = nv; - } + @Override + public final V merge(final K key, final V value, + final BiFunction remappingFunction) { + return delegate.merge(key, value, remappingFunction); } - /*** - * This iterator is a read-only one and does not allow for any update - * operations on the underlying data structure. - * - * @param - * @param - */ - private static final class TrieMapReadOnlyIterator extends TrieMapIterator { - TrieMapReadOnlyIterator (final int level, final TrieMap ct, final boolean mustInit) { - super (level, ct, mustInit); - } - - TrieMapReadOnlyIterator (final int level, final TrieMap ct) { - this (level, ct, true); - } - @Override - void initialize () { - assert (ct.isReadOnly ()); - super.initialize (); - } - - @Override - public void remove () { - throw new UnsupportedOperationException ("Operation not supported for read-only iterators"); - } - - @Override - Entry nextEntry(final Entry rr) { - // Return non-updatable entry - return rr; - } + @Override + public final int hashCode() { + return delegate.hashCode(); } - private static class TrieMapIterator implements Iterator> { - private int level; - protected TrieMap ct; - private final boolean mustInit; - private final BasicNode[][] stack = new BasicNode[7][]; - private final int[] stackpos = new int[7]; - private int depth = -1; - private Iterator> subiter = null; - private KVNode current = null; - private Entry lastReturned = null; - - TrieMapIterator (final int level, final TrieMap ct, final boolean mustInit) { - this.level = level; - this.ct = ct; - this.mustInit = mustInit; - if (this.mustInit) { - initialize (); - } - } - - TrieMapIterator (final int level, final TrieMap ct) { - this (level, ct, true); - } - - - @Override - public boolean hasNext () { - return (current != null) || (subiter != null); - } - - @Override - public Entry next () { - if (hasNext ()) { - Entry r = null; - if (subiter != null) { - r = subiter.next (); - checkSubiter (); - } else { - r = current.kvPair (); - advance (); - } - - lastReturned = r; - if (r != null) { - final Entry rr = r; - return nextEntry(rr); - } - return r; - } else { - // return Iterator.empty ().next (); - return null; - } - } - - Entry nextEntry(final Entry rr) { - return new Entry() { - private V updated = null; - - @Override - public K getKey () { - return rr.getKey (); - } - - @Override - public V getValue () { - return (updated == null)?rr.getValue (): updated; - } - - @Override - public V setValue (final V value) { - updated = value; - return ct.replace (getKey (), value); - } - }; - } - - private void readin (final INode in) { - MainNode m = in.gcasRead (ct); - if (m instanceof CNode) { - CNode cn = (CNode) m; - depth += 1; - stack [depth] = cn.array; - stackpos [depth] = -1; - advance (); - } else if (m instanceof TNode) { - current = (TNode) m; - } else if (m instanceof LNode) { - subiter = ((LNode) m).iterator(); - checkSubiter (); - } else if (m == null) { - current = null; - } - } - - // @inline - private void checkSubiter () { - if (!subiter.hasNext ()) { - subiter = null; - advance (); - } - } - - // @inline - void initialize () { -// assert (ct.isReadOnly ()); - INode r = ct.RDCSS_READ_ROOT (); - readin (r); - } - - void advance () { - if (depth >= 0) { - int npos = stackpos [depth] + 1; - if (npos < stack [depth].length) { - stackpos [depth] = npos; - BasicNode elem = stack [depth] [npos]; - if (elem instanceof SNode) { - current = (SNode) elem; - } else if (elem instanceof INode) { - readin ((INode) elem); - } - } else { - depth -= 1; - advance (); - } - } else { - current = null; - } - } - - protected TrieMapIterator newIterator (final int _lev, final TrieMap _ct, final boolean _mustInit) { - return new TrieMapIterator<> (_lev, _ct, _mustInit); - } - - protected void dupTo (final TrieMapIterator it) { - it.level = this.level; - it.ct = this.ct; - it.depth = this.depth; - it.current = this.current; - - // these need a deep copy - System.arraycopy (this.stack, 0, it.stack, 0, 7); - System.arraycopy (this.stackpos, 0, it.stackpos, 0, 7); - - // this one needs to be evaluated - if (this.subiter == null) { - it.subiter = null; - } else { - List> lst = toList (this.subiter); - this.subiter = lst.iterator (); - it.subiter = lst.iterator (); - } - } - - // /** Returns a sequence of iterators over subsets of this iterator. - // * It's used to ease the implementation of splitters for a parallel - // version of the TrieMap. - // */ - // protected def subdivide(): Seq[Iterator[(K, V)]] = if (subiter ne - // null) { - // // the case where an LNode is being iterated - // val it = subiter - // subiter = null - // advance() - // this.level += 1 - // Seq(it, this) - // } else if (depth == -1) { - // this.level += 1 - // Seq(this) - // } else { - // var d = 0 - // while (d <= depth) { - // val rem = stack(d).length - 1 - stackpos(d) - // if (rem > 0) { - // val (arr1, arr2) = stack(d).drop(stackpos(d) + 1).splitAt(rem / 2) - // stack(d) = arr1 - // stackpos(d) = -1 - // val it = newIterator(level + 1, ct, false) - // it.stack(0) = arr2 - // it.stackpos(0) = -1 - // it.depth = 0 - // it.advance() // <-- fix it - // this.level += 1 - // return Seq(this, it) - // } - // d += 1 - // } - // this.level += 1 - // Seq(this) - // } - - private List> toList (final Iterator> it) { - ArrayList> list = new ArrayList<> (); - while (it.hasNext ()) { - list.add (it.next ()); - } - return list; - } - - void printDebug () { - System.out.println ("ctrie iterator"); - System.out.println (Arrays.toString (stackpos)); - System.out.println ("depth: " + depth); - System.out.println ("curr.: " + current); - // System.out.println(stack.mkString("\n")); - } - - @Override - public void remove () { - if (lastReturned != null) { - ct.remove (lastReturned.getKey ()); - lastReturned = null; - } else { - throw new IllegalStateException(); - } - } - + @Override + public final boolean equals(final Object o) { + return delegate.equals(o); } - /*** - * Support for EntrySet operations required by the Map interface - */ - private final class EntrySet extends AbstractSet> { - - @Override - public Iterator> iterator () { - return TrieMap.this.iterator (); - } - - @Override - public final boolean contains (final Object o) { - if (!(o instanceof Entry)) { - return false; - } - final Entry e = (Entry) o; - final K k = e.getKey (); - final V v = lookup (k); - return v != null; - } - - @Override - public final boolean remove (final Object o) { - if (!(o instanceof Entry)) { - return false; - } - final Entry e = (Entry) o; - final K k = e.getKey(); - return null != TrieMap.this.remove(k); - } - - @Override - public final int size () { - int size = 0; - for (final Iterator i = iterator (); i.hasNext (); i.next ()) { - size++; - } - return size; - } - - @Override - public final void clear () { - TrieMap.this.clear (); - } + @Override + protected final tech.pantheon.triemap.TrieMap delegate() { + return delegate; } - }