org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate Maven / Gradle / Ivy
/*
* Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.util;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import org.eclipse.jdt.annotation.NonNull;
/**
* Template for instantiating {@link ImmutableOffsetMap} instances with a fixed set of keys. The template can then be
* used as a factory for instances via using {@link #instantiateTransformed(Map, BiFunction)} or, more efficiently,
* using {@link #instantiateWithValues(Object[])} where the argument array has values ordered corresponding to the key
* order defined by {@link #keySet()}.
*
* @param the type of keys maintained by this template
*/
public abstract sealed class ImmutableOffsetMapTemplate extends ImmutableMapTemplate {
private static final class Ordered extends ImmutableOffsetMapTemplate {
Ordered(final Collection keys) {
super(OffsetMapCache.orderedOffsets(keys));
}
@Override
@NonNull ImmutableOffsetMap createMap(final ImmutableMap offsets, final V[] objects) {
return new ImmutableOffsetMap.Ordered<>(offsets, objects);
}
}
private static final class Unordered extends ImmutableOffsetMapTemplate {
Unordered(final Collection keys) {
super(OffsetMapCache.unorderedOffsets(keys));
}
@Override
@NonNull ImmutableOffsetMap createMap(final ImmutableMap offsets, final V[] objects) {
return new ImmutableOffsetMap.Unordered<>(offsets, objects);
}
}
private final @NonNull ImmutableMap offsets;
private ImmutableOffsetMapTemplate(final ImmutableMap offsets) {
this.offsets = requireNonNull(offsets);
}
/**
* Create a template which produces Maps with specified keys, with iteration order matching the iteration order
* of {@code keys}. {@link #keySet()} will return these keys in exactly the same order. The resulting map will
* retain insertion order through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
*
* @param keys Keys in requested iteration order.
* @param the type of keys maintained by resulting template
* @return A template object.
* @throws NullPointerException if {@code keys} or any of its elements is null
* @throws IllegalArgumentException if {@code keys} is does not have at least two keys
*/
public static @NonNull ImmutableOffsetMapTemplate ordered(final Collection keys) {
checkArgument(keys.size() > 1);
return new Ordered<>(keys);
}
/**
* Create a template which produces Maps with specified keys, with unconstrained iteration order. Produced maps
* will have the iteration order matching the order returned by {@link #keySet()}. The resulting map will
* NOT retain ordering through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
*
* @param keys Keys in any iteration order.
* @param the type of keys maintained by resulting template
* @return A template object.
* @throws NullPointerException if {@code keys} or any of its elements is null
* @throws IllegalArgumentException if {@code keys} is does not have at least two keys
*/
public static @NonNull ImmutableOffsetMapTemplate unordered(final Collection keys) {
checkArgument(keys.size() > 1);
return new Unordered<>(keys);
}
@Override
public final Set keySet() {
return offsets.keySet();
}
@Override
public final @NonNull ImmutableOffsetMap instantiateTransformed(final Map fromMap,
final BiFunction valueTransformer) {
final int size = offsets.size();
checkArgument(fromMap.size() == size);
@SuppressWarnings("unchecked")
final V[] objects = (V[]) new Object[size];
for (Entry entry : fromMap.entrySet()) {
final K key = requireNonNull(entry.getKey());
objects[offsetOf(key)] = transformValue(key, entry.getValue(), valueTransformer);
}
return createMap(offsets, objects);
}
@SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE",
justification = "SpotBugs does not grok checkArgument()")
private int offsetOf(final K key) {
final Integer offset = offsets.get(key);
checkArgument(offset != null, "Key %s present in input, but not in offsets %s", key, offsets);
return offset;
}
@Override
@SafeVarargs
public final @NonNull ImmutableOffsetMap instantiateWithValues(final V... values) {
checkArgument(values.length == offsets.size());
final V[] copy = values.clone();
Arrays.stream(copy).forEach(Objects::requireNonNull);
return createMap(offsets, values);
}
@Override
public final String toString() {
return MoreObjects.toStringHelper(this).add("offsets", offsets).toString();
}
abstract @NonNull ImmutableOffsetMap createMap(ImmutableMap offsets, V[] objects);
}