BUG-7464: remove uneeded casts and similar warnings
[yangtools.git] / third-party / triemap / src / main / java / org / opendaylight / yangtools / triemap / TrieMap.java
1 /*
2  * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.opendaylight.yangtools.triemap;
17
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.base.Preconditions.checkState;
20 import static org.opendaylight.yangtools.triemap.LookupResult.RESTART;
21 import static org.opendaylight.yangtools.triemap.PresencePredicate.ABSENT;
22 import static org.opendaylight.yangtools.triemap.PresencePredicate.PRESENT;
23
24 import com.google.common.base.Verify;
25 import com.google.common.collect.Iterators;
26 import java.io.ObjectStreamException;
27 import java.io.Serializable;
28 import java.util.AbstractMap;
29 import java.util.AbstractSet;
30 import java.util.ArrayList;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.NoSuchElementException;
34 import java.util.Optional;
35 import java.util.Set;
36 import java.util.concurrent.ConcurrentMap;
37 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
38
39 /***
40  * This is a port of Scala's TrieMap class from the Scala Collections library. This implementation does not support
41  * null keys nor null values.
42  *
43  * @author Roman Levenstein <romixlev@gmail.com>
44  *
45  * @param <K> the type of keys maintained by this map
46  * @param <V> the type of mapped values
47  */
48 public final class TrieMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,V>, Serializable {
49     @SuppressWarnings("rawtypes")
50     private static final AtomicReferenceFieldUpdater<TrieMap, Object> ROOT_UPDATER =
51             AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root");
52     private static final long serialVersionUID = 1L;
53
54     /**
55      * EntrySet
56      */
57     private final EntrySet entrySet = new EntrySet();
58     private final Equivalence<? super K> equiv;
59     private final boolean readOnly;
60
61     private volatile Object root;
62
63     private TrieMap(final INode<K, V> r, final Equivalence<? super K> equiv, final boolean readOnly) {
64         this.root = r;
65         this.equiv = equiv;
66         this.readOnly = readOnly;
67     }
68
69     TrieMap(final Equivalence<? super K> equiv) {
70         this(newRootNode(), equiv, false);
71     }
72
73     public TrieMap() {
74         this(Equivalence.equals());
75     }
76
77     /* internal methods */
78
79     final Equivalence<? super K> equiv() {
80         return equiv;
81     }
82
83     private static <K,V> INode<K, V> newRootNode() {
84         final Gen gen = new Gen();
85         return new INode<>(gen, new CNode<>(gen));
86     }
87
88     private boolean CAS_ROOT(final Object ov, final Object nv) {
89         checkState(!readOnly, "Attempted to modify a read-only snapshot");
90         return ROOT_UPDATER.compareAndSet(this, ov, nv);
91     }
92
93     final INode<K, V> readRoot() {
94         return RDCSS_READ_ROOT(false);
95     }
96
97     // FIXME: abort = false by default
98     final INode<K, V> readRoot(final boolean abort) {
99         return RDCSS_READ_ROOT(abort);
100     }
101
102     private final INode<K, V> RDCSS_READ_ROOT() {
103         return RDCSS_READ_ROOT(false);
104     }
105
106     private final INode<K, V> RDCSS_READ_ROOT(final boolean abort) {
107         final Object r = /* READ */ root;
108         if (r instanceof INode) {
109             return (INode<K, V>) r;
110         }
111
112         checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r);
113         return RDCSS_Complete(abort);
114     }
115
116     private INode<K, V> RDCSS_Complete(final boolean abort) {
117         while (true) {
118             final Object r = /* READ */ root;
119             if (r instanceof INode) {
120                 return (INode<K, V>) r;
121             }
122
123             checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r);
124             @SuppressWarnings("unchecked")
125             final RDCSS_Descriptor<K, V> desc = (RDCSS_Descriptor<K, V>) r;
126             final INode<K, V> ov = desc.old;
127             final MainNode<K, V> exp = desc.expectedmain;
128             final INode<K, V> nv = desc.nv;
129
130             if (abort) {
131                 if (CAS_ROOT(desc, ov)) {
132                     return ov;
133                 }
134
135                 // Tail recursion: return RDCSS_Complete(abort);
136                 continue;
137             }
138
139             final MainNode<K, V> oldmain = ov.gcasRead(this);
140             if (oldmain == exp) {
141                 if (CAS_ROOT(desc, nv)) {
142                     desc.committed = true;
143                     return nv;
144                 }
145
146                 // Tail recursion: return RDCSS_Complete(abort);
147                 continue;
148             }
149
150             if (CAS_ROOT(desc, ov)) {
151                 return ov;
152             }
153
154             // Tail recursion: return RDCSS_Complete(abort);
155         }
156     }
157
158     private boolean RDCSS_ROOT(final INode<K, V> ov, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
159         final RDCSS_Descriptor<K, V> desc = new RDCSS_Descriptor<> (ov, expectedmain, nv);
160         if (CAS_ROOT(ov, desc)) {
161             RDCSS_Complete(false);
162             return /* READ */desc.committed;
163         }
164
165         return false;
166     }
167
168     private void inserthc(final K k, final int hc, final V v) {
169         // TODO: this is called from serialization only, which means we should not be observing any races,
170         //       hence we should not need to pass down the entire tree, just equality (I think).
171         final boolean success = RDCSS_READ_ROOT().rec_insert(k, v, hc, 0, null, this);
172         Verify.verify(success, "Concurrent modification during serialization of map %s", this);
173     }
174
175     void add(final K key, final V value) {
176         final K k = checkNotNull(key);
177         inserthc(k, computeHash(k), checkNotNull(value));
178     }
179
180     private Optional<V> insertifhc(final K k, final int hc, final V v, final Object cond) {
181         Optional<V> res;
182         do {
183             // Keep looping as long as we do not get a reply
184             res = RDCSS_READ_ROOT().rec_insertif(k, v, hc, cond, 0, null, this);
185         } while (res == null);
186
187         return res;
188     }
189
190     @SuppressWarnings("unchecked")
191     private V lookuphc(final K k, final int hc) {
192         Object res;
193         do {
194             // Keep looping as long as RESTART is being indicated
195             res = RDCSS_READ_ROOT().rec_lookup(k, hc, 0, null, this);
196         } while (res == RESTART);
197
198         return (V) res;
199     }
200
201     private Optional<V> removehc(final K k, final Object cond, final int hc) {
202         Optional<V> res;
203         do {
204             // Keep looping as long as we do not get a reply
205             res = RDCSS_READ_ROOT().rec_remove(k, cond, hc, 0, null, this);
206         } while (res == null);
207
208         return res;
209     }
210
211     /**
212      * Ensure this instance is read-write, throw UnsupportedOperationException
213      * otherwise. Used by Map-type methods for quick check.
214      */
215     private void ensureReadWrite() {
216         if (readOnly) {
217             throw new UnsupportedOperationException("Attempted to modify a read-only view");
218         }
219     }
220
221     boolean isReadOnly() {
222         return readOnly;
223     }
224
225     /* public methods */
226
227     /**
228      * Returns a snapshot of this TrieMap. This operation is lock-free and
229      * linearizable.
230      *
231      * The snapshot is lazily updated - the first time some branch in the
232      * snapshot or this TrieMap are accessed, they are rewritten. This means
233      * that the work of rebuilding both the snapshot and this TrieMap is
234      * distributed across all the threads doing updates or accesses subsequent
235      * to the snapshot creation.
236      */
237     public TrieMap<K, V> snapshot() {
238         while (true) {
239             final INode<K, V> r = RDCSS_READ_ROOT();
240             final MainNode<K, V> expmain = r.gcasRead(this);
241             if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen(), this))) {
242                 return new TrieMap<> (r.copyToGen(new Gen(), this), equiv, readOnly);
243             }
244
245             // Tail recursion: return snapshot();
246         }
247     }
248
249     /**
250      * Returns a read-only snapshot of this TrieMap. This operation is lock-free
251      * and linearizable.
252      *
253      * The snapshot is lazily updated - the first time some branch of this
254      * TrieMap are accessed, it is rewritten. The work of creating the snapshot
255      * is thus distributed across subsequent updates and accesses on this
256      * TrieMap by all threads. Note that the snapshot itself is never rewritten
257      * unlike when calling the `snapshot` method, but the obtained snapshot
258      * cannot be modified.
259      *
260      * This method is used by other methods such as `size` and `iterator`.
261      */
262     public TrieMap<K, V> readOnlySnapshot() {
263         // Is it a snapshot of a read-only snapshot?
264         if (readOnly) {
265             return this;
266         }
267
268         while (true) {
269             final INode<K, V> r = RDCSS_READ_ROOT();
270             final MainNode<K, V> expmain = r.gcasRead(this);
271             if (RDCSS_ROOT(r, expmain, r.copyToGen (new Gen(), this))) {
272                 return new TrieMap<>(r, equiv, true);
273             }
274
275             // Tail recursion: return readOnlySnapshot();
276         }
277     }
278
279     @Override
280     public void clear() {
281         boolean success;
282         do {
283             final INode<K, V> r = RDCSS_READ_ROOT();
284             success = RDCSS_ROOT(r, r.gcasRead(this), newRootNode());
285         } while (!success);
286     }
287
288     int computeHash(final K k) {
289         return equiv.hash(k);
290     }
291
292     boolean equal(final K k1, final K k2) {
293         return equiv.equivalent(k1, k2);
294     }
295
296     @Override
297     public V get(final Object key) {
298         @SuppressWarnings("unchecked")
299         final K k = (K) checkNotNull(key);
300         return lookuphc(k, computeHash(k));
301     }
302
303     @SuppressWarnings("null")
304     private static <V> V toNullable(final Optional<V> opt) {
305         return opt.orElse(null);
306     }
307
308     @Override
309     public V put(final K key, final V value) {
310         ensureReadWrite();
311         final K k = checkNotNull(key);
312         return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), null));
313     }
314
315     @Override
316     public V remove(final Object key) {
317         ensureReadWrite();
318         @SuppressWarnings("unchecked")
319         final K k = (K) checkNotNull(key);
320         return toNullable(removehc(k, null, computeHash(k)));
321     }
322
323     @Override
324     public V putIfAbsent(final K key, final V value) {
325         ensureReadWrite();
326         final K k = checkNotNull(key);
327         return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), ABSENT));
328     }
329
330     @Override
331     public boolean remove(final Object key, final Object v) {
332         ensureReadWrite();
333         @SuppressWarnings("unchecked")
334         final K k = (K) checkNotNull(key);
335         return removehc(k, checkNotNull(v), computeHash(k)).isPresent();
336     }
337
338     @Override
339     public boolean replace(final K key, final V oldValue, final V newValue) {
340         ensureReadWrite();
341         final K k = checkNotNull(key);
342         return insertifhc(k, computeHash(k), checkNotNull(newValue), checkNotNull(oldValue)).isPresent();
343     }
344
345     @Override
346     public V replace(final K key, final V value) {
347         ensureReadWrite();
348         final K k = checkNotNull(key);
349         return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), PRESENT));
350     }
351
352     /***
353      * Return an iterator over a TrieMap.
354      *
355      * If this is a read-only snapshot, it would return a read-only iterator.
356      *
357      * If it is the original TrieMap or a non-readonly snapshot, it would return
358      * an iterator that would allow for updates.
359      *
360      * @return
361      */
362     Iterator<Entry<K, V>> iterator() {
363         return readOnly ? new TrieMapReadOnlyIterator<>(0, this) : new TrieMapIterator<>(0, this);
364     }
365
366     /***
367      * Return an iterator over a TrieMap.
368      * This is a read-only iterator.
369      *
370      * @return
371      */
372     Iterator<Entry<K, V>> readOnlyIterator() {
373         return new TrieMapReadOnlyIterator<>(0, readOnly ? this : readOnlySnapshot());
374     }
375
376     private int cachedSize() {
377         return RDCSS_READ_ROOT().cachedSize (this);
378     }
379
380     @Override
381     public int size() {
382         return readOnly ? cachedSize() : readOnlySnapshot().size();
383     }
384
385     @Override
386     public boolean containsKey(final Object key) {
387         return get(key) != null;
388     }
389
390     @Override
391     public Set<Entry<K, V>> entrySet() {
392         return entrySet;
393     }
394
395     private Object writeReplace() throws ObjectStreamException {
396         return new ExternalForm(this);
397     }
398
399     private static final class RDCSS_Descriptor<K, V> {
400         INode<K, V> old;
401         MainNode<K, V> expectedmain;
402         INode<K, V> nv;
403         volatile boolean committed = false;
404
405         RDCSS_Descriptor (final INode<K, V> old, final MainNode<K, V> expectedmain, final INode<K, V> nv) {
406             this.old = old;
407             this.expectedmain = expectedmain;
408             this.nv = nv;
409         }
410     }
411
412     /***
413      * This iterator is a read-only one and does not allow for any update
414      * operations on the underlying data structure.
415      *
416      * @param <K>
417      * @param <V>
418      */
419     private static final class TrieMapReadOnlyIterator<K, V> extends TrieMapIterator<K, V> {
420         TrieMapReadOnlyIterator (final int level, final TrieMap<K, V> ct, final boolean mustInit) {
421             super (level, ct, mustInit);
422         }
423
424         TrieMapReadOnlyIterator (final int level, final TrieMap<K, V> ct) {
425             this (level, ct, true);
426         }
427         @Override
428         void initialize () {
429             assert (ct.isReadOnly ());
430             super.initialize ();
431         }
432
433         @Override
434         public void remove () {
435             throw new UnsupportedOperationException ("Operation not supported for read-only iterators");
436         }
437
438         @Override
439         Entry<K, V> nextEntry(final Entry<K, V> rr) {
440             // Return non-updatable entry
441             return rr;
442         }
443     }
444
445     private static class TrieMapIterator<K, V> implements Iterator<Entry<K, V>> {
446         private int level;
447         protected TrieMap<K, V> ct;
448         private final boolean mustInit;
449         private final BasicNode[][] stack = new BasicNode[7][];
450         private final int[] stackpos = new int[7];
451         private int depth = -1;
452         private Iterator<Entry<K, V>> subiter = null;
453         private EntryNode<K, V> current = null;
454         private Entry<K, V> lastReturned = null;
455
456         TrieMapIterator (final int level, final TrieMap<K, V> ct, final boolean mustInit) {
457             this.level = level;
458             this.ct = ct;
459             this.mustInit = mustInit;
460             if (this.mustInit) {
461                 initialize ();
462             }
463         }
464
465         TrieMapIterator (final int level, final TrieMap<K, V> ct) {
466             this (level, ct, true);
467         }
468
469
470         @Override
471         public boolean hasNext() {
472             return (current != null) || (subiter != null);
473         }
474
475         @Override
476         public Entry<K, V> next() {
477             if (!hasNext()) {
478                 throw new NoSuchElementException();
479             }
480
481             final Entry<K, V> r;
482             if (subiter != null) {
483                 r = subiter.next();
484                 checkSubiter();
485             } else {
486                 r = current;
487                 advance();
488             }
489
490             lastReturned = r;
491             if (r != null) {
492                 final Entry<K, V> rr = r;
493                 return nextEntry(rr);
494             }
495             return r;
496         }
497
498         Entry<K, V> nextEntry(final Entry<K, V> rr) {
499             return new Entry<K, V>() {
500                 @SuppressWarnings("null")
501                 private V updated = null;
502
503                 @Override
504                 public K getKey () {
505                     return rr.getKey ();
506                 }
507
508                 @Override
509                 public V getValue () {
510                     return (updated == null) ? rr.getValue (): updated;
511                 }
512
513                 @Override
514                 public V setValue (final V value) {
515                     updated = value;
516                     return ct.replace (getKey (), value);
517                 }
518             };
519         }
520
521         private void readin (final INode<K, V> in) {
522             MainNode<K, V> m = in.gcasRead (ct);
523             if (m instanceof CNode) {
524                 CNode<K, V> cn = (CNode<K, V>) m;
525                 depth += 1;
526                 stack [depth] = cn.array;
527                 stackpos [depth] = -1;
528                 advance ();
529             } else if (m instanceof TNode) {
530                 current = (TNode<K, V>) m;
531             } else if (m instanceof LNode) {
532                 subiter = ((LNode<K, V>) m).iterator();
533                 checkSubiter ();
534             } else if (m == null) {
535                 current = null;
536             }
537         }
538
539         // @inline
540         private void checkSubiter () {
541             if (!subiter.hasNext ()) {
542                 subiter = null;
543                 advance ();
544             }
545         }
546
547         // @inline
548         void initialize () {
549 //            assert (ct.isReadOnly ());
550             readin(ct.RDCSS_READ_ROOT());
551         }
552
553         void advance () {
554             if (depth >= 0) {
555                 int npos = stackpos [depth] + 1;
556                 if (npos < stack [depth].length) {
557                     stackpos [depth] = npos;
558                     BasicNode elem = stack [depth] [npos];
559                     if (elem instanceof SNode) {
560                         current = (SNode<K, V>) elem;
561                     } else if (elem instanceof INode) {
562                         readin ((INode<K, V>) elem);
563                     }
564                 } else {
565                     depth -= 1;
566                     advance ();
567                 }
568             } else {
569                 current = null;
570             }
571         }
572
573         protected TrieMapIterator<K, V> newIterator(final int _lev, final TrieMap<K, V> _ct, final boolean _mustInit) {
574             return new TrieMapIterator<> (_lev, _ct, _mustInit);
575         }
576
577         protected void dupTo(final TrieMapIterator<K, V> it) {
578             it.level = this.level;
579             it.ct = this.ct;
580             it.depth = this.depth;
581             it.current = this.current;
582
583             // these need a deep copy
584             System.arraycopy (this.stack, 0, it.stack, 0, 7);
585             System.arraycopy (this.stackpos, 0, it.stackpos, 0, 7);
586
587             // this one needs to be evaluated
588             if (this.subiter == null) {
589                 it.subiter = null;
590             } else {
591                 List<Entry<K, V>> lst = toList (this.subiter);
592                 this.subiter = lst.iterator ();
593                 it.subiter = lst.iterator ();
594             }
595         }
596
597         // /** Returns a sequence of iterators over subsets of this iterator.
598         // * It's used to ease the implementation of splitters for a parallel
599         // version of the TrieMap.
600         // */
601         // protected def subdivide(): Seq[Iterator[(K, V)]] = if (subiter ne
602         // null) {
603         // // the case where an LNode is being iterated
604         // val it = subiter
605         // subiter = null
606         // advance()
607         // this.level += 1
608         // Seq(it, this)
609         // } else if (depth == -1) {
610         // this.level += 1
611         // Seq(this)
612         // } else {
613         // var d = 0
614         // while (d <= depth) {
615         // val rem = stack(d).length - 1 - stackpos(d)
616         // if (rem > 0) {
617         // val (arr1, arr2) = stack(d).drop(stackpos(d) + 1).splitAt(rem / 2)
618         // stack(d) = arr1
619         // stackpos(d) = -1
620         // val it = newIterator(level + 1, ct, false)
621         // it.stack(0) = arr2
622         // it.stackpos(0) = -1
623         // it.depth = 0
624         // it.advance() // <-- fix it
625         // this.level += 1
626         // return Seq(this, it)
627         // }
628         // d += 1
629         // }
630         // this.level += 1
631         // Seq(this)
632         // }
633
634         private List<Entry<K, V>> toList (final Iterator<Entry<K, V>> it) {
635             ArrayList<Entry<K, V>> list = new ArrayList<> ();
636             while (it.hasNext ()) {
637                 list.add (it.next());
638             }
639             return list;
640         }
641
642         @Override
643         public void remove() {
644             checkState(lastReturned != null);
645             ct.remove(lastReturned.getKey());
646             lastReturned = null;
647         }
648     }
649
650     /***
651      * Support for EntrySet operations required by the Map interface
652      */
653     private final class EntrySet extends AbstractSet<Entry<K, V>> {
654         @Override
655         public Iterator<Entry<K, V>> iterator() {
656             return TrieMap.this.iterator ();
657         }
658
659         @Override
660         public final boolean contains(final Object o) {
661             if (!(o instanceof Entry)) {
662                 return false;
663             }
664
665             final Entry<?, ?> e = (Entry<?, ?>) o;
666             if (e.getKey() == null) {
667                 return false;
668             }
669             final V v = get(e.getKey());
670             return v != null && v.equals(e.getValue());
671         }
672
673         @Override
674         public final boolean remove(final Object o) {
675             if (!(o instanceof Entry)) {
676                 return false;
677             }
678             final Entry<?, ?> e = (Entry<?, ?>) o;
679             final Object key = e.getKey();
680             if (key == null) {
681                 return false;
682             }
683             final Object value = e.getValue();
684             if (value == null) {
685                 return false;
686             }
687
688             return TrieMap.this.remove(key, value);
689         }
690
691         @Override
692         public final int size () {
693             return Iterators.size(iterator());
694         }
695
696         @Override
697         public final void clear () {
698             TrieMap.this.clear ();
699         }
700     }
701 }