X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=common%2Futil%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Futil%2FImmutableOffsetMap.java;h=7e5dd349ff0b268886c966792a3134e4446feef8;hb=24d06767f3a0ead8152a745fb05eda1d4a37ba77;hp=1ff5a5c7cc7cd5cf8be864e04b853e9d448f5dc8;hpb=468bdb3273e2c827045d93feb57b18a3842dd505;p=yangtools.git diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java b/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java index 1ff5a5c7cc..7e5dd349ff 100644 --- a/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java +++ b/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java @@ -46,15 +46,42 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase toModifiableMap() { - return new MutableOffsetMap<>(this); + return MutableOffsetMap.orderedCopyOf(this); + } + + @Override + void setFields(final List keys, final V[] values) throws IOException { + setField(this, OFFSETS_FIELD, OffsetMapCache.orderedOffsets(keys)); + setField(this, ARRAY_FIELD, values); + } + } + + static final class Unordered extends ImmutableOffsetMap { + private static final long serialVersionUID = 1L; + + Unordered(final Map offsets, final V[] objects) { + super(offsets, objects); + } + + @Override + public MutableOffsetMap toModifiableMap() { + return MutableOffsetMap.unorderedCopyOf(this); + } + + @Override + void setFields(final List keys, final V[] values) throws IOException { + final Map offsets = OffsetMapCache.unorderedOffsets(keys); + + setField(this, OFFSETS_FIELD, offsets); + setField(this, ARRAY_FIELD, OffsetMapCache.adjustedArray(offsets, keys, values)); } } private static final long serialVersionUID = 1L; - private final Map offsets; - private final V[] objects; - private int hashCode; + private transient final Map offsets; + private transient final V[] objects; + private transient int hashCode; /** * Construct a new instance backed by specified key-to-offset map and array of objects. @@ -72,6 +99,8 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase toModifiableMap(); + abstract void setFields(List keys, V[] values) throws IOException; + /** * Create an {@link ImmutableOffsetMap} as a copy of an existing map. This is actually not completely true, * as this method returns an {@link ImmutableMap} for empty and singleton inputs, as those are more memory-efficient. @@ -82,8 +111,25 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase Map copyOf(@Nonnull final Map m) { + return orderedCopyOf(m); + } + + /** + * Create an {@link ImmutableOffsetMap} as a copy of an existing map. This is actually not completely true, + * as this method returns an {@link ImmutableMap} for empty and singleton inputs, as those are more memory-efficient. + * This method also recognizes {@link ImmutableOffsetMap} on input, and returns it back without doing anything else. + * It also recognizes {@link MutableOffsetMap} (as returned by {@link #toModifiableMap()}) and makes an efficient + * copy of its contents. All other maps are converted to an {@link ImmutableOffsetMap} with the same iteration + * order as input. + * + * @param m Input map, may not be null. + * @return An isolated, immutable copy of the input map + */ + @Nonnull public static Map orderedCopyOf(@Nonnull final Map m) { // Prevent a copy. Note that ImmutableMap is not listed here because of its potentially larger keySet overhead. if (m instanceof ImmutableOffsetMap || m instanceof SharedSingletonMap) { return m; @@ -102,10 +148,10 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase e = m.entrySet().iterator().next(); - return SharedSingletonMap.of(e.getKey(), e.getValue()); + return SharedSingletonMap.orderedOf(e.getKey(), e.getValue()); } - final Map offsets = OffsetMapCache.offsetsFor(m.keySet()); + final Map offsets = OffsetMapCache.orderedOffsets(m.keySet()); @SuppressWarnings("unchecked") final V[] array = (V[]) new Object[offsets.size()]; for (Entry e : m.entrySet()) { @@ -115,6 +161,49 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase(offsets, array); } + /** + * Create an {@link ImmutableOffsetMap} as a copy of an existing map. This is actually not completely true, + * as this method returns an {@link ImmutableMap} for empty and singleton inputs, as those are more memory-efficient. + * This method also recognizes {@link ImmutableOffsetMap} on input, and returns it back without doing anything else. + * It also recognizes {@link MutableOffsetMap} (as returned by {@link #toModifiableMap()}) and makes an efficient + * copy of its contents. All other maps are converted to an {@link ImmutableOffsetMap}. Iterator order is not + * guaranteed to be retained. + * + * @param m Input map, may not be null. + * @return An isolated, immutable copy of the input map + */ + @Nonnull public static Map unorderedCopyOf(@Nonnull final Map m) { + // Prevent a copy. Note that ImmutableMap is not listed here because of its potentially larger keySet overhead. + if (m instanceof ImmutableOffsetMap || m instanceof SharedSingletonMap) { + return m; + } + + // Familiar and efficient to copy + if (m instanceof MutableOffsetMap) { + return ((MutableOffsetMap) m).toUnmodifiableMap(); + } + + final int size = m.size(); + if (size == 0) { + // Shares a single object + return ImmutableMap.of(); + } + if (size == 1) { + // Efficient single-entry implementation + final Entry e = m.entrySet().iterator().next(); + return SharedSingletonMap.unorderedOf(e.getKey(), e.getValue()); + } + + final Map offsets = OffsetMapCache.unorderedOffsets(m.keySet()); + @SuppressWarnings("unchecked") + final V[] array = (V[]) new Object[offsets.size()]; + for (Entry e : m.entrySet()) { + array[offsets.get(e.getKey())] = e.getValue(); + } + + return new Unordered<>(offsets, array); + } + @Override public final int size() { return offsets.size(); @@ -313,9 +402,9 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase map, final Field field, final Object value) throws IOException { try { - field.set(this, value); + field.set(map, value); } catch (IllegalArgumentException | IllegalAccessException e) { throw new IOException("Failed to set field " + field, e); } @@ -333,7 +422,6 @@ public abstract class ImmutableOffsetMap implements UnmodifiableMapPhase