091b40a4e8e95ec740b6ce52f933292bd6db14c1
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / ImmutableOffsetMapTemplate.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.util;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.base.MoreObjects;
14 import com.google.common.collect.ImmutableMap;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Objects;
20 import java.util.Set;
21 import java.util.function.BiFunction;
22 import org.eclipse.jdt.annotation.NonNull;
23
24 /**
25  * Template for instantiating {@link ImmutableOffsetMap} instances with a fixed set of keys. The template can then be
26  * used as a factory for instances via using {@link #instantiateTransformed(Map, BiFunction)} or, more efficiently,
27  * using {@link #instantiateWithValues(Object[])} where the argument array has values ordered corresponding to the key
28  * order defined by {@link #keySet()}.
29  *
30  * @param <K> the type of keys maintained by this template
31  */
32 public abstract class ImmutableOffsetMapTemplate<K> extends ImmutableMapTemplate<K> {
33     private static final class Ordered<K> extends ImmutableOffsetMapTemplate<K> {
34         Ordered(final Collection<K> keys) {
35             super(OffsetMapCache.orderedOffsets(keys));
36         }
37
38         @Override
39         <V> @NonNull ImmutableOffsetMap<K, V> createMap(final ImmutableMap<K, Integer> offsets, final V[] objects) {
40             return new ImmutableOffsetMap.Ordered<>(offsets, objects);
41         }
42     }
43
44     private static final class Unordered<K> extends ImmutableOffsetMapTemplate<K> {
45         Unordered(final Collection<K> keys) {
46             super(OffsetMapCache.unorderedOffsets(keys));
47         }
48
49         @Override
50         <V> @NonNull ImmutableOffsetMap<K, V> createMap(final ImmutableMap<K, Integer> offsets, final V[] objects) {
51             return new ImmutableOffsetMap.Unordered<>(offsets, objects);
52         }
53     }
54
55     private final @NonNull ImmutableMap<K, Integer> offsets;
56
57     ImmutableOffsetMapTemplate(final ImmutableMap<K, Integer> offsets) {
58         this.offsets = requireNonNull(offsets);
59     }
60
61     /**
62      * Create a template which produces Maps with specified keys, with iteration order matching the iteration order
63      * of {@code keys}. {@link #keySet()} will return these keys in exactly the same order. The resulting map will
64      * retain insertion order through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
65      *
66      * @param keys Keys in requested iteration order.
67      * @param <K> the type of keys maintained by resulting template
68      * @return A template object.
69      * @throws NullPointerException if {@code keys} or any of its elements is null
70      * @throws IllegalArgumentException if {@code keys} is does not have at least two keys
71      */
72     public static <K> @NonNull ImmutableOffsetMapTemplate<K> ordered(final Collection<K> keys) {
73         checkArgument(keys.size() > 1);
74         return new Ordered<>(keys);
75     }
76
77     /**
78      * Create a template which produces Maps with specified keys, with unconstrained iteration order. Produced maps
79      * will have the iteration order matching the order returned by {@link #keySet()}.  The resulting map will
80      * NOT retain ordering through {@link UnmodifiableMapPhase#toModifiableMap()} transformations.
81      *
82      * @param keys Keys in any iteration order.
83      * @param <K> the type of keys maintained by resulting template
84      * @return A template object.
85      * @throws NullPointerException if {@code keys} or any of its elements is null
86      * @throws IllegalArgumentException if {@code keys} is does not have at least two keys
87      */
88     public static <K> @NonNull ImmutableOffsetMapTemplate<K> unordered(final Collection<K> keys) {
89         checkArgument(keys.size() > 1);
90         return new Unordered<>(keys);
91     }
92
93     @Override
94     public final Set<K> keySet() {
95         return offsets.keySet();
96     }
97
98     @Override
99     public final <T, V> @NonNull ImmutableOffsetMap<K, V> instantiateTransformed(final Map<K, T> fromMap,
100             final BiFunction<K, T, V> valueTransformer) {
101         final int size = offsets.size();
102         checkArgument(fromMap.size() == size);
103
104         @SuppressWarnings("unchecked")
105         final V[] objects = (V[]) new Object[size];
106         for (Entry<K, T> entry : fromMap.entrySet()) {
107             final K key = requireNonNull(entry.getKey());
108             final Integer offset = offsets.get(key);
109             checkArgument(offset != null, "Key %s present in input, but not in offsets %s", key, offsets);
110
111             objects[offset.intValue()] = transformValue(key, entry.getValue(), valueTransformer);
112         }
113
114         return createMap(offsets, objects);
115     }
116
117     @Override
118     @SafeVarargs
119     public final <V> @NonNull ImmutableOffsetMap<K, V> instantiateWithValues(final V... values) {
120         checkArgument(values.length == offsets.size());
121         final V[] copy = values.clone();
122         Arrays.stream(copy).forEach(Objects::requireNonNull);
123         return createMap(offsets, values);
124     }
125
126     @Override
127     public final String toString() {
128         return MoreObjects.toStringHelper(this).add("offsets", offsets).toString();
129     }
130
131     abstract <V> @NonNull ImmutableOffsetMap<K, V> createMap(ImmutableMap<K, Integer> offsets, V[] objects);
132 }