Do not use ListenerRegistration
[mdsal.git] / binding / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / util / BindingMap.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, 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.yang.binding.util;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.ImmutableMap;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.stream.Collector;
19 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.binding.Key;
22 import org.opendaylight.yangtools.yang.binding.KeyAware;
23
24 /**
25  * Utility class for instantiating Maps containing {@link KeyAware} values. Unlike normal Map instantiation
26  * utilities, methods in this class index values via their identifier, hence providing a more convenient API, amenable
27  * to fluent builders.
28  *
29  * <p>
30  * A typical example of use with generated DataObjects looks like this:
31  * <pre>
32  *   <code>
33  *     Foo foo = new FooBuilder()
34  *          .setBar(BindingMap.of(
35  *              new BarBuilder().setName("one").build(),
36  *              new BarBuilder().setName("two").build()))
37  *          .build();
38  *   </code>
39  * </pre>
40  *
41  * <p>
42  * Another alternative is to use builders:
43  * <pre>
44  *   <code>
45  *     Foo foo = new FooBuilder()
46  *          .setBar(BindingMap.&lt;BarKey, Bar&gt;builder()
47  *              .add(new BarBuilder().setName("one").build())
48  *              .add(new BarBuilder().setName("two").build())
49  *              .build())
50  *          .build();
51  *   </code>
52  * </pre>
53  *
54  * <p>
55  * This class allows for two modes of operation:
56  * <ul>
57  *   <li>Unordered, available through {@link #of(KeyAware...)}/{@link #builder()} family of functions. Maps
58  *       instantiated through this, preferred, interface will have their iteration order randomized, as explain in
59  *       Java 9+ unmodifiable collections.</li>
60  *   <li>Ordered, available through {@link #ordered(KeyAware...)}/{@link #orderedBuilder()} family of functions.
61  *       Maps instantiated through this interface have a predictable iteration order, as per {@link ImmutableMap}
62  *       class design. The use of this interface is generally discouraged, as it may lead to code relying on map
63  *       iteration order. Nevertheless it may prove useful where the goal is to have predictable outcomes and hence
64  *       is provided for completeness.</li>
65  * </ul>
66  */
67 @Beta
68 public final class BindingMap {
69     private BindingMap() {
70         // Hidden on purpose
71     }
72
73     /**
74      * Returns an unmodifiable map containing a single mapping.
75      *
76      * @param <K> the {@code Map}'s key type
77      * @param <V> the {@code Map}'s value type
78      * @param v1 the mapping's value
79      * @return a {@code Map} containing the specified value
80      * @throws NullPointerException if the value is {@code null}
81      */
82     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1) {
83         return Map.of(v1.key(), v1);
84     }
85
86     /**
87      * Returns an unmodifiable map containing two mappings. The resulting map is <b>NOT</b> guaranteed retain iteration
88      * order of mappings.
89      *
90      * @param <K> the {@code Map}'s key type
91      * @param <V> the {@code Map}'s value type
92      * @param v1 the first mapping's value
93      * @param v2 the second mapping's value
94      * @return a {@code Map} containing the specified mappings
95      * @throws IllegalArgumentException if the values contain duplicate keys
96      * @throws NullPointerException if any value is {@code null}
97      */
98     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2) {
99         return Map.of(v1.key(), v1, v2.key(), v2);
100     }
101
102     /**
103      * Returns an unmodifiable map containing three mappings. The resulting map is <b>NOT</b> guaranteed to retain
104      * iteration order of mappings.
105      *
106      * @param <K> the {@code Map}'s key type
107      * @param <V> the {@code Map}'s value type
108      * @param v1 the first mapping's value
109      * @param v2 the second mapping's value
110      * @param v3 the third mapping's value
111      * @return a {@code Map} containing the specified mappings
112      * @throws IllegalArgumentException if the values contain duplicate keys
113      * @throws NullPointerException if any value is {@code null}
114      */
115     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
116             final V v3) {
117         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3);
118     }
119
120     /**
121      * Returns an unmodifiable map containing four mappings. The resulting map is <b>NOT</b> guaranteed to retain
122      * iteration order of mappings.
123      *
124      * @param <K> the {@code Map}'s key type
125      * @param <V> the {@code Map}'s value type
126      * @param v1 the first mapping's value
127      * @param v2 the second mapping's value
128      * @param v3 the third mapping's value
129      * @param v4 the fourth mapping's value
130      * @return a {@code Map} containing the specified mappings
131      * @throws IllegalArgumentException if the values contain duplicate keys
132      * @throws NullPointerException if any value is {@code null}
133      */
134     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
135             final V v3, final V v4) {
136         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4);
137     }
138
139     /**
140      * Returns an unmodifiable map containing five mappings. The resulting map is <b>NOT</b> guaranteed to retain
141      * iteration order of mappings.
142      *
143      * @param <K> the {@code Map}'s key type
144      * @param <V> the {@code Map}'s value type
145      * @param v1 the first mapping's value
146      * @param v2 the second mapping's value
147      * @param v3 the third mapping's value
148      * @param v4 the fourth mapping's value
149      * @param v5 the fifth mapping's value
150      * @return a {@code Map} containing the specified mappings
151      * @throws IllegalArgumentException if the values contain duplicate keys
152      * @throws NullPointerException if any value is {@code null}
153      */
154     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
155             final V v3, final V v4, final V v5) {
156         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5);
157     }
158
159     /**
160      * Returns an unmodifiable map containing six mappings. The resulting map is <b>NOT</b> guaranteed to retain
161      * iteration order of mappings.
162      *
163      * @param <K> the {@code Map}'s key type
164      * @param <V> the {@code Map}'s value type
165      * @param v1 the first mapping's value
166      * @param v2 the second mapping's value
167      * @param v3 the third mapping's value
168      * @param v4 the fourth mapping's value
169      * @param v5 the fifth mapping's value
170      * @param v6 the sixth mapping's value
171      * @return a {@code Map} containing the specified mappings
172      * @throws IllegalArgumentException if the values contain duplicate keys
173      * @throws NullPointerException if any value is {@code null}
174      */
175     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
176             final V v3, final V v4, final V v5, final V v6) {
177         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6);
178     }
179
180     /**
181      * Returns an unmodifiable map containing seven mappings. The resulting map is <b>NOT</b> guaranteed to retain
182      * iteration order of mappings.
183      *
184      * @param <K> the {@code Map}'s key type
185      * @param <V> the {@code Map}'s value type
186      * @param v1 the first mapping's value
187      * @param v2 the second mapping's value
188      * @param v3 the third mapping's value
189      * @param v4 the fourth mapping's value
190      * @param v5 the fifth mapping's value
191      * @param v6 the sixth mapping's value
192      * @param v7 the seventh mapping's value
193      * @return a {@code Map} containing the specified mappings
194      * @throws IllegalArgumentException if the values contain duplicate keys
195      * @throws NullPointerException if any value is {@code null}
196      */
197     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
198             final V v3, final V v4, final V v5, final V v6, final V v7) {
199         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7);
200     }
201
202     /**
203      * Returns an unmodifiable map containing eight mappings. The resulting map is <b>NOT</b> guaranteed to retain
204      * iteration order of mappings.
205      *
206      * @param <K> the {@code Map}'s key type
207      * @param <V> the {@code Map}'s value type
208      * @param v1 the first mapping's value
209      * @param v2 the second mapping's value
210      * @param v3 the third mapping's value
211      * @param v4 the fourth mapping's value
212      * @param v5 the fifth mapping's value
213      * @param v6 the sixth mapping's value
214      * @param v7 the seventh mapping's value
215      * @param v8 the eighth mapping's value
216      * @return a {@code Map} containing the specified mappings
217      * @throws IllegalArgumentException if the values contain duplicate keys
218      * @throws NullPointerException if any value is {@code null}
219      */
220     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
221             final V v3, final V v4, final V v5, final V v6, final V v7, final V v8) {
222         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
223             v8.key(), v8);
224     }
225
226     /**
227      * Returns an unmodifiable map containing nine mappings. The resulting map is <b>NOT</b> guaranteed to retain
228      * iteration order of mappings.
229      *
230      * @param <K> the {@code Map}'s key type
231      * @param <V> the {@code Map}'s value type
232      * @param v1 the first mapping's value
233      * @param v2 the second mapping's value
234      * @param v3 the third mapping's value
235      * @param v4 the fourth mapping's value
236      * @param v5 the fifth mapping's value
237      * @param v6 the sixth mapping's value
238      * @param v7 the seventh mapping's value
239      * @param v8 the eighth mapping's value
240      * @param v9 the ninth mapping's value
241      * @return a {@code Map} containing the specified mappings
242      * @throws IllegalArgumentException if the values contain duplicate keys
243      * @throws NullPointerException if any value is {@code null}
244      */
245     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
246             final V v3, final V v4, final V v5, final V v6, final V v7, final V v8, final V v9) {
247         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
248             v8.key(), v8, v9.key(), v9);
249     }
250
251     /**
252      * Returns an unmodifiable map containing ten mappings. The resulting map is <b>NOT</b> guaranteed to retain
253      * iteration order of mappings.
254      *
255      * @param <K> the {@code Map}'s key type
256      * @param <V> the {@code Map}'s value type
257      * @param v1 the first mapping's value
258      * @param v2 the second mapping's value
259      * @param v3 the third mapping's value
260      * @param v4 the fourth mapping's value
261      * @param v5 the fifth mapping's value
262      * @param v6 the sixth mapping's value
263      * @param v7 the seventh mapping's value
264      * @param v8 the eighth mapping's value
265      * @param v9 the ninth mapping's value
266      * @param v10 the ninth mapping's value
267      * @return a {@code Map} containing the specified mappings
268      * @throws IllegalArgumentException if the values contain duplicate keys
269      * @throws NullPointerException if any value is {@code null}
270      */
271     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
272             final V v3, final V v4, final V v5, final V v6, final V v7, final V v8, final V v9, final V v10) {
273         return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
274             v8.key(), v8, v9.key(), v9, v10.key(), v10);
275     }
276
277     /**
278      * Returns an unmodifiable map containing given values. The resulting map is <b>NOT</b> guaranteed to retain
279      * iteration order of the input array.
280      *
281      * @param <K> the {@code Map}'s key type
282      * @param <V> the {@code Map}'s value type
283      * @param values values from which the map is populated
284      * @return a {@code Map} containing the specified values
285      * @throws IllegalArgumentException if there are any duplicate keys in the provided values
286      * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
287      */
288     @SafeVarargs
289     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V... values) {
290         return of(Arrays.asList(values));
291     }
292
293     /**
294      * Returns an unmodifiable map containing given values. The resulting map is <b>NOT</b> guaranteed to retain
295      * iteration order of the input collection.
296      *
297      * @param <K> the {@code Map}'s key type
298      * @param <V> the {@code Map}'s value type
299      * @param values values from which the map is populated
300      * @return a {@code Map} containing the specified values
301      * @throws IllegalArgumentException if there are any duplicate keys in the provided values
302      * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
303      */
304     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(
305             final Collection<V> values) {
306         return values.stream().collect(toMap());
307     }
308
309     /**
310      * Returns a collector which collects binding {@link KeyAware} objects into an unmodifiable map. The resulting
311      * map is <b>NOT</b> guaranteed to retain iteration order of the stream it collects.
312      *
313      * @param <K> the {@code Map}'s key type
314      * @param <V> the {@code Map}'s value type
315      * @return A collector that accumulates the input elements into an unmodifiable map.
316      */
317     public static <K extends Key<V>, V extends KeyAware<K>>
318             @NonNull Collector<V, ?, ? extends Map<K, V>> toMap() {
319         return Collectors.toUnmodifiableMap(KeyAware::key, v -> v);
320     }
321
322     /**
323      * Create a builder on an unmodifiable map, which does not retain value insertion order. The builder will be
324      * pre-sized to hold {@value Builder#DEFAULT_INITIAL_CAPACITY} elements.
325      *
326      * @param <K> the {@code Map}'s key type
327      * @param <V> the {@code Map}'s value type
328      * @return A {@link Builder} instance.
329      */
330     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> builder() {
331         return builder(Builder.DEFAULT_INITIAL_CAPACITY);
332     }
333
334     /**
335      * Create a builder on an unmodifiable map, which does not retain value insertion order. The builder will be
336      * pre-sized to hold specified number of elements.
337      *
338      * @param <K> the {@code Map}'s key type
339      * @param <V> the {@code Map}'s value type
340      * @param expectedSize Expected number of values in the resulting map
341      * @return A {@link Builder} instance.
342      */
343     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> builder(
344             final int expectedSize) {
345         return new UnorderedBuilder<>(expectedSize);
346     }
347
348     /**
349      * Returns an unmodifiable map containing two mappings. The resulting map will retain iteration order of mappings.
350      *
351      * @param <K> the {@code Map}'s key type
352      * @param <V> the {@code Map}'s value type
353      * @param v1 the first mapping's value
354      * @param v2 the second mapping's value
355      * @return a {@code Map} containing the specified mappings
356      * @throws IllegalArgumentException if the values contain duplicate keys
357      * @throws NullPointerException if any value is {@code null}
358      */
359     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
360             final V v2) {
361         return ImmutableMap.of(v1.key(), v1, v2.key(), v2);
362     }
363
364     /**
365      * Returns an unmodifiable map containing three mappings. The resulting map will retain iteration order of mappings.
366      *
367      * @param <K> the {@code Map}'s key type
368      * @param <V> the {@code Map}'s value type
369      * @param v1 the first mapping's value
370      * @param v2 the second mapping's value
371      * @param v3 the third mapping's value
372      * @return a {@code Map} containing the specified mappings
373      * @throws IllegalArgumentException if the values contain duplicate keys
374      * @throws NullPointerException if any value is {@code null}
375      */
376     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
377             final V v2, final V v3) {
378         return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3);
379     }
380
381     /**
382      * Returns an unmodifiable map containing four mappings. The resulting map will retain iteration order of mappings.
383      *
384      * @param <K> the {@code Map}'s key type
385      * @param <V> the {@code Map}'s value type
386      * @param v1 the first mapping's value
387      * @param v2 the second mapping's value
388      * @param v3 the third mapping's value
389      * @param v4 the fourth mapping's value
390      * @return a {@code Map} containing the specified mappings
391      * @throws IllegalArgumentException if the values contain duplicate keys
392      * @throws NullPointerException if any value is {@code null}
393      */
394     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
395             final V v2, final V v3, final V v4) {
396         return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4);
397     }
398
399     /**
400      * Returns an unmodifiable map containing five mappings. The resulting map will retain iteration order of mappings.
401      *
402      * @param <K> the {@code Map}'s key type
403      * @param <V> the {@code Map}'s value type
404      * @param v1 the first mapping's value
405      * @param v2 the second mapping's value
406      * @param v3 the third mapping's value
407      * @param v4 the fourth mapping's value
408      * @param v5 the fifth mapping's value
409      * @return a {@code Map} containing the specified mappings
410      * @throws IllegalArgumentException if the values contain duplicate keys
411      * @throws NullPointerException if any value is {@code null}
412      */
413     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
414             final V v2, final V v3, final V v4, final V v5) {
415         return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5);
416     }
417
418     /**
419      * Returns an unmodifiable map containing given values. Resulting {@code Map} will retain the iteration order of
420      * values.
421      *
422      * @param <K> the {@code Map}'s key type
423      * @param <V> the {@code Map}'s value type
424      * @param values values from which the map is populated
425      * @return a {@code Map} containing the specified values
426      * @throws IllegalArgumentException if there are any duplicate keys in the provided values
427      * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
428      */
429     @SafeVarargs
430     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V... values) {
431         return ordered(Arrays.asList(values));
432     }
433
434     /**
435      * Returns an unmodifiable map containing given values. Resulting {@code Map} will retain the iteration order of
436      * values.
437      *
438      * @param <K> the {@code Map}'s key type
439      * @param <V> the {@code Map}'s value type
440      * @param values values from which the map is populated
441      * @return a {@code Map} containing the specified values
442      * @throws IllegalArgumentException if there are any duplicate keys in the provided values
443      * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
444      */
445     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(
446             final Collection<V> values) {
447         return values.stream().collect(toOrderedMap());
448     }
449
450     /**
451      * Returns a collector which collects binding {@link KeyAware} objects into an unmodifiable map. The resulting
452      * map will retain iteration order of the stream it collects.
453      *
454      * @param <K> the {@code Map}'s key type
455      * @param <V> the {@code Map}'s value type
456      * @return A collector that accumulates the input elements into an unmodifiable map.
457      */
458     public static <K extends Key<V>, V extends KeyAware<K>>
459             @NonNull Collector<V, ?, ? extends Map<K, V>> toOrderedMap() {
460         return ImmutableMap.<V, K, V>toImmutableMap(KeyAware::key, v -> v);
461     }
462
463     /**
464      * Create a builder on an unmodifiable map, which retains value insertion order. The builder will be pre-sized to
465      * hold {@value Builder#DEFAULT_INITIAL_CAPACITY} elements.
466      *
467      * @param <K> the {@code Map}'s key type
468      * @param <V> the {@code Map}'s value type
469      * @return A {@link Builder} instance.
470      */
471     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> orderedBuilder() {
472         return orderedBuilder(Builder.DEFAULT_INITIAL_CAPACITY);
473     }
474
475     /**
476      * Create a builder on an unmodifiable map, which retains value insertion order. The builder will be pre-sized to
477      * hold specified number of elements.
478      *
479      * @param <K> the {@code Map}'s key type
480      * @param <V> the {@code Map}'s value type
481      * @param expectedSize Expected number of values in the resulting map
482      * @return A {@link Builder} instance.
483      */
484     public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> orderedBuilder(
485             final int expectedSize) {
486         return new OrderedBuilder<>(expectedSize);
487     }
488
489     /**
490      * Builder producing a Map containing binding {@link KeyAware} values.
491      *
492      * @param <K> the {@code Map}'s key type
493      * @param <V> the {@code Map}'s value type
494      */
495     public abstract static class Builder<K extends Key<V>, V extends KeyAware<K>> {
496         static final int DEFAULT_INITIAL_CAPACITY = 4;
497
498         Builder() {
499             // Hidden on purpose
500         }
501
502         /**
503          * Add a value to this builder.
504          *
505          * @param value the value to add
506          * @return this builder
507          * @throws NullPointerException if value is {@code null}
508          */
509         public final @NonNull Builder<K, V> add(final V value) {
510             addEntry(value.key(), value);
511             return this;
512         }
513
514         /**
515          * Add values to this builder.
516          *
517          * @param values the values to add
518          * @return this builder
519          * @throws NullPointerException if value is, or contains, {@code null}
520          */
521         @SafeVarargs
522         public final @NonNull Builder<K, V> addAll(final V... values) {
523             return addAll(Arrays.asList(values));
524         }
525
526         /**
527          * Add values to this builder.
528          *
529          * @param values the values to add
530          * @return this builder
531          * @throws NullPointerException if value is, or contains, {@code null}
532          */
533         public final @NonNull Builder<K, V> addAll(final Collection<V> values) {
534             addEntries(Collections2.transform(values, value -> Map.entry(value.key(), value)));
535             return this;
536         }
537
538         /**
539          * Build map from existing map entries in this builder.
540          *
541          * @return Resulting map
542          * @throws IllegalArgumentException if duplicate keys were added
543          */
544         public abstract @NonNull Map<K, V> build();
545
546         /**
547          * Add map entry identified by its {@code key} and containing {@code value} to this builder.
548          *
549          * @param key Key of the map entry
550          * @param value Value of the map entry
551          */
552         abstract void addEntry(K key, V value);
553
554         /**
555          * Add collection of map entries to this builder.
556          *
557          * @param entries Map entries to add
558          */
559         abstract void addEntries(Collection<Entry<K, V>> entries);
560     }
561
562     private static final class OrderedBuilder<K extends Key<V>, V extends KeyAware<K>>
563             extends Builder<K, V> {
564         private final ImmutableMap.Builder<K, V> delegate;
565
566         OrderedBuilder(final int expectedSize) {
567             delegate = ImmutableMap.builderWithExpectedSize(expectedSize);
568         }
569
570         @Override
571         public Map<K, V> build() {
572             return delegate.build();
573         }
574
575         @Override
576         void addEntry(final K key, final V value) {
577             delegate.put(key, value);
578         }
579
580         @Override
581         void addEntries(final Collection<Entry<K, V>> entries) {
582             delegate.putAll(entries);
583         }
584     }
585
586     private static final class UnorderedBuilder<K extends Key<V>, V extends KeyAware<K>>
587             extends Builder<K, V> {
588         private final ArrayList<Entry<K, V>> buffer;
589
590         UnorderedBuilder(final int expectedSize) {
591             buffer = new ArrayList<>(expectedSize);
592         }
593
594         @Override
595         @SuppressWarnings("unchecked")
596         public Map<K, V> build() {
597             return Map.ofEntries(buffer.toArray(new Entry[0]));
598         }
599
600         @Override
601         void addEntry(final K key, final V value) {
602             buffer.add(Map.entry(key, value));
603         }
604
605         @Override
606         void addEntries(final Collection<Entry<K, V>> entries) {
607             buffer.addAll(entries);
608         }
609     }
610 }