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