--- /dev/null
+/*
+ * (C) Copyright 2017 Pantheon Technologies, s.r.o. and others.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yangtools.triemap;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.util.Map.Entry;
+
+/**
+ * External serialization object for use with TrieMap objects. This hides the implementation details, such as object
+ * hierarchy. It also makes handling read-only snapshots more elegant.
+ *
+ * @author Robert Varga
+ */
+final class ExternalForm implements Externalizable {
+ private static final long serialVersionUID = 1L;
+
+ private TrieMap<Object, Object> map;
+ private boolean readOnly;
+
+ public ExternalForm() {
+ // For Externalizable
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ ExternalForm(final TrieMap<?, ?> map) {
+ this.map = ((TrieMap)map).readOnlySnapshot();
+ this.readOnly = map.isReadOnly();
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeObject(map.equiv());
+ out.writeInt(map.size());
+ for (Entry<Object, Object> e : map.entrySet()) {
+ out.writeObject(e.getKey());
+ out.writeObject(e.getValue());
+ }
+ out.writeBoolean(readOnly);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ @SuppressWarnings("unchecked")
+ final Equivalence<Object> equiv = (Equivalence<Object>) in.readObject();
+ Preconditions.checkArgument(equiv != null);
+ map = new TrieMap<>(equiv);
+
+ final int size = in.readInt();
+ for (int i = 0; i < size; ++i) {
+ map.add(in.readObject(), in.readObject());
+ }
+
+ readOnly = in.readBoolean();
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ return Verify.verifyNotNull(readOnly ? map.readOnlySnapshot() : map);
+ }
+}
package org.opendaylight.yangtools.triemap;
import com.google.common.base.Preconditions;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.lang.reflect.Field;
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.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
private static final AtomicReferenceFieldUpdater<TrieMap, Object> ROOT_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root");
private static final long serialVersionUID = 1L;
- private static final Field READONLY_FIELD;
-
- static {
- final Field f;
- try {
- f = TrieMap.class.getDeclaredField("readOnly");
- } catch (NoSuchFieldException e) {
- throw new ExceptionInInitializerError(e);
- } catch (SecurityException e) {
- throw new ExceptionInInitializerError(e);
- }
- f.setAccessible(true);
- READONLY_FIELD = f;
- }
/**
* EntrySet
*/
- private transient final EntrySet entrySet = new EntrySet ();
-
+ private final EntrySet entrySet = new EntrySet();
private final Equivalence<? super K> equiv;
+ private final boolean readOnly;
- private transient volatile Object root;
- private final transient boolean readOnly;
+ private volatile Object root;
- TrieMap(final INode<K, V> r, final Equivalence<? super K> equiv, final boolean readOnly) {
+ private TrieMap(final INode<K, V> r, final Equivalence<? super K> equiv, final boolean readOnly) {
this.root = r;
this.equiv = equiv;
this.readOnly = readOnly;
}
+ TrieMap(final Equivalence<? super K> equiv) {
+ this(newRootNode(), equiv, false);
+ }
+
public TrieMap() {
- this(newRootNode(), Equivalence.equals(), false);
+ this(Equivalence.equals());
}
/* internal methods */
+ final Equivalence<? super K> equiv() {
+ return equiv;
+ }
+
private static <K,V> INode<K, V> newRootNode() {
final Gen gen = new Gen();
return new INode<>(gen, new CNode<>(gen));
return insertifhc (key, hc, value, null).orElse(null);
}
- TrieMap<K, V> add(final K k, final V v) {
- final int hc = computeHash (k);
- inserthc (k, hc, v);
- return this;
+ void add(final K k, final V v) {
+ inserthc(k, computeHash(k), v);
}
@Override
return entrySet;
}
+ private Object writeReplace() throws ObjectStreamException {
+ return new ExternalForm(this);
+ }
+
private static final class RDCSS_Descriptor<K, V> {
INode<K, V> old;
MainNode<K, V> expectedmain;
}
}
- private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
- inputStream.defaultReadObject();
- this.root = newRootNode();
-
- final boolean ro = inputStream.readBoolean();
- final int size = inputStream.readInt();
- for (int i = 0; i < size; ++i) {
- final K key = (K)inputStream.readObject();
- final V value = (V)inputStream.readObject();
- add(key, value);
- }
-
- // Propagate the read-only bit
- try {
- READONLY_FIELD.setBoolean(this, ro);
- } catch (IllegalAccessException e) {
- throw new IOException("Failed to set read-only flag", e);
- }
- }
-
- private void writeObject(final ObjectOutputStream outputStream) throws IOException {
- outputStream.defaultWriteObject();
-
- final Map<K, V> ro = readOnlySnapshot();
- outputStream.writeBoolean(readOnly);
- outputStream.writeInt(ro.size());
-
- for (Entry<K, V> e : ro.entrySet()) {
- outputStream.writeObject(e.getKey());
- outputStream.writeObject(e.getValue());
- }
- }
}