0aacd4f5f71109d6b8285d8ee2fe1e3c3dd547ad
[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 org.opendaylight.yangtools.triemap.LookupResult.RESTART;
20
21 import com.google.common.annotations.Beta;
22 import java.io.ObjectStreamException;
23 import java.io.Serializable;
24 import java.util.AbstractMap;
25 import java.util.Iterator;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentMap;
29
30 /***
31  * This is a port of Scala's TrieMap class from the Scala Collections library. This implementation does not support
32  * null keys nor null values.
33  *
34  * @author Aleksandar Prokopec (original Scala implementation)
35  * @author Roman Levenstein (original Java 6 port)
36  * @author Robert Varga
37  *
38  * @param <K> the type of keys maintained by this map
39  * @param <V> the type of mapped values
40  */
41 @Beta
42 public abstract class TrieMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,V>, Serializable {
43     private static final long serialVersionUID = 1L;
44
45     /**
46      * EntrySet
47      */
48     private final EntrySet<K, V> entrySet = new EntrySet<>(this);
49     private final Equivalence<? super K> equiv;
50
51     TrieMap(final Equivalence<? super K> equiv) {
52         this.equiv = equiv;
53     }
54
55     public static <K, V> TrieMap<K, V> create() {
56         return new MutableTrieMap<>(Equivalence.equals());
57     }
58
59     /**
60      * Returns a snapshot of this TrieMap. This operation is lock-free and
61      * linearizable.
62      *
63      * The snapshot is lazily updated - the first time some branch in the
64      * snapshot or this TrieMap are accessed, they are rewritten. This means
65      * that the work of rebuilding both the snapshot and this TrieMap is
66      * distributed across all the threads doing updates or accesses subsequent
67      * to the snapshot creation.
68      */
69     public abstract TrieMap<K, V> mutableSnapshot();
70
71     /**
72      * Returns a read-only snapshot of this TrieMap. This operation is lock-free
73      * and linearizable.
74      *
75      * The snapshot is lazily updated - the first time some branch of this
76      * TrieMap are accessed, it is rewritten. The work of creating the snapshot
77      * is thus distributed across subsequent updates and accesses on this
78      * TrieMap by all threads. Note that the snapshot itself is never rewritten
79      * unlike when calling the `snapshot` method, but the obtained snapshot
80      * cannot be modified.
81      *
82      * This method is used by other methods such as `size` and `iterator`.
83      */
84     public abstract ImmutableTrieMap<K, V> immutableSnapshot();
85
86     @Override
87     public final boolean containsKey(final Object key) {
88         return get(key) != null;
89     }
90
91     @Override
92     public final boolean containsValue(final Object value) {
93         return super.containsValue(checkNotNull(value));
94     }
95
96     @Override
97     public final Set<Entry<K, V>> entrySet() {
98         return entrySet;
99     }
100
101     @Override
102     public final V get(final Object key) {
103         @SuppressWarnings("unchecked")
104         final K k = (K) checkNotNull(key);
105         return lookuphc(k, computeHash(k));
106     }
107
108     @Override
109     public abstract void clear();
110
111     @Override
112     public abstract V put(K key, V value);
113
114     @Override
115     public abstract V putIfAbsent(K key, V value);
116
117     @Override
118     public abstract V remove(Object key);
119
120     @Override
121     public abstract boolean remove(Object key, Object value);
122
123     @Override
124     public abstract boolean replace(K key, V oldValue, V newValue);
125
126     @Override
127     public abstract V replace(K key, V value);
128
129     @Override
130     public abstract int size();
131
132     /* internal methods implemented by subclasses */
133
134     abstract boolean isReadOnly();
135
136     abstract INode<K, V> RDCSS_READ_ROOT(boolean abort);
137
138     /* internal methods provided for subclasses */
139
140     @SuppressWarnings("null")
141     static <V> V toNullable(final Optional<V> opt) {
142         return opt.orElse(null);
143     }
144
145     final int computeHash(final K k) {
146         return equiv.hash(k);
147     }
148
149     final Object writeReplace() throws ObjectStreamException {
150         return new SerializationProxy(immutableSnapshot(), isReadOnly());
151     }
152
153     /* package-protected utility methods */
154
155     final Equivalence<? super K> equiv() {
156         return equiv;
157     }
158
159     final INode<K, V> readRoot() {
160         return RDCSS_READ_ROOT(false);
161     }
162
163     // FIXME: abort = false by default
164     final INode<K, V> readRoot(final boolean abort) {
165         return RDCSS_READ_ROOT(abort);
166     }
167
168     final INode<K, V> RDCSS_READ_ROOT() {
169         return RDCSS_READ_ROOT(false);
170     }
171
172     final boolean equal(final K k1, final K k2) {
173         return equiv.equivalent(k1, k2);
174     }
175
176     /* private implementation methods */
177
178     @SuppressWarnings("unchecked")
179     private V lookuphc(final K k, final int hc) {
180         Object res;
181         do {
182             // Keep looping as long as RESTART is being indicated
183             res = RDCSS_READ_ROOT().rec_lookup(k, hc, 0, null, this);
184         } while (res == RESTART);
185
186         return (V) res;
187     }
188
189     /**
190      * Return an iterator over a TrieMap.
191      *
192      * If this is a read-only snapshot, it would return a read-only iterator.
193      *
194      * If it is the original TrieMap or a non-readonly snapshot, it would return
195      * an iterator that would allow for updates.
196      *
197      * @return
198      */
199     final Iterator<Entry<K, V>> iterator() {
200         // FIXME: it would be nice to have a ReadWriteTrieMap with read-only iterator
201         return isReadOnly() ? new TrieMapReadOnlyIterator<>(0, this) : new TrieMapIterator<>(0, this);
202     }
203
204     /**
205      * Return an iterator over a TrieMap.
206      * This is a read-only iterator.
207      *
208      * @return
209      */
210     final Iterator<Entry<K, V>> readOnlyIterator() {
211         return new TrieMapReadOnlyIterator<>(0, immutableSnapshot());
212     }
213 }