2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.util;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.MoreObjects;
13 import com.google.common.collect.ImmutableMap;
14 import java.util.Arrays;
15 import java.util.Collection;
17 import java.util.Objects;
19 import java.util.function.BiFunction;
20 import org.eclipse.jdt.annotation.NonNull;
23 * Template for instantiating {@link ImmutableOffsetMap} instances with a fixed set of keys. The template can then be
24 * used as a factory for instances via using {@link #instantiateTransformed(Map, BiFunction)} or, more efficiently,
25 * using {@link #instantiateWithValues(Object[])} where the argument array has values ordered corresponding to the key
26 * order defined by {@link #keySet()}.
28 * @param <K> the type of keys maintained by this template
30 public abstract sealed class ImmutableOffsetMapTemplate<K> extends ImmutableMapTemplate<K> {
31 private static final class Ordered<K> extends ImmutableOffsetMapTemplate<K> {
32 Ordered(final Collection<K> keys) {
33 super(OffsetMapCache.orderedOffsets(keys));
37 <V> @NonNull ImmutableOffsetMap<K, V> createMap(final ImmutableMap<K, Integer> offsets, final V[] objects) {
38 return new ImmutableOffsetMap.Ordered<>(offsets, objects);
42 private static final class Unordered<K> extends ImmutableOffsetMapTemplate<K> {
43 Unordered(final Collection<K> keys) {
44 super(OffsetMapCache.unorderedOffsets(keys));
48 <V> @NonNull ImmutableOffsetMap<K, V> createMap(final ImmutableMap<K, Integer> offsets, final V[] objects) {
49 return new ImmutableOffsetMap.Unordered<>(offsets, objects);
53 private final @NonNull ImmutableMap<K, Integer> offsets;
55 private ImmutableOffsetMapTemplate(final ImmutableMap<K, Integer> offsets) {
56 this.offsets = requireNonNull(offsets);
60 * Create a template which produces Maps with specified keys, with iteration order matching the iteration order
61 * of {@code keys}. {@link #keySet()} will return these keys in exactly the same order. The resulting map will
62 * retain insertion order through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
64 * @param keys Keys in requested iteration order.
65 * @param <K> the type of keys maintained by resulting template
66 * @return A template object.
67 * @throws NullPointerException if {@code keys} or any of its elements is null
68 * @throws IllegalArgumentException if {@code keys} is does not have at least two keys
70 public static <K> @NonNull ImmutableOffsetMapTemplate<K> ordered(final Collection<K> keys) {
72 return new Ordered<>(keys);
76 * Create a template which produces Maps with specified keys, with unconstrained iteration order. Produced maps
77 * will have the iteration order matching the order returned by {@link #keySet()}. The resulting map will
78 * NOT retain ordering through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
80 * @param keys Keys in any iteration order.
81 * @param <K> the type of keys maintained by resulting template
82 * @return A template object.
83 * @throws NullPointerException if {@code keys} or any of its elements is null
84 * @throws IllegalArgumentException if {@code keys} is does not have at least two keys
86 public static <K> @NonNull ImmutableOffsetMapTemplate<K> unordered(final Collection<K> keys) {
88 return new Unordered<>(keys);
92 public final Set<K> keySet() {
93 return offsets.keySet();
97 public final <T, V> @NonNull ImmutableOffsetMap<K, V> instantiateTransformed(final Map<K, T> fromMap,
98 final BiFunction<K, T, V> valueTransformer) {
99 final int size = offsets.size();
100 checkSize(size, fromMap.size());
102 @SuppressWarnings("unchecked")
103 final var objects = (V[]) new Object[size];
104 for (var entry : fromMap.entrySet()) {
105 final var key = requireNonNull(entry.getKey());
106 objects[offsetOf(key)] = transformValue(key, entry.getValue(), valueTransformer);
109 return createMap(offsets, objects);
112 private int offsetOf(final K key) {
113 final var offset = offsets.get(key);
114 if (offset == null) {
115 throw new IllegalArgumentException("Key " + key + " present in input, but not in offsets " + offsets);
122 public final <V> ImmutableOffsetMap<K, V> instantiateWithValues(final V... values) {
123 checkSize(offsets.size(), values.length);
124 final var copy = values.clone();
125 Arrays.stream(copy).forEach(Objects::requireNonNull);
126 return createMap(offsets, values);
130 public final String toString() {
131 return MoreObjects.toStringHelper(this).add("offsets", offsets).toString();
134 abstract <V> @NonNull ImmutableOffsetMap<K, V> createMap(ImmutableMap<K, Integer> offsets, V[] objects);
136 private static void checkTwoKeys(final Collection<?> keys) {
137 final var size = keys.size();
139 throw new IllegalArgumentException("Expected at least 2 keys, " + size + " supplied");