001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.util;
018
019import static java.util.Objects.requireNonNull;
020
021import java.util.AbstractMap;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.LinkedHashMap;
027import java.util.LinkedHashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031import java.util.function.Consumer;
032
033/**
034 * Provides a set of methods that produce unmodifiable copies of collections.
035 *
036 * @since 4.0.0
037 */
038public final class UnmodifiableCollections {
039
040    private UnmodifiableCollections() {}
041
042    /**
043     * Creates an unmodifiable copy of the given {@link List} instance.
044     *
045     * @param original the list to be copied
046     * @param <E> the type of every item in the entry
047     * @return a unmodifiable copy of the given {@link List} instance
048     *
049     * @since 4.0.0
050     */
051    public static <E> List<E> copyOf(final List<E> original) {
052        switch (original.size()) {
053            case 0:
054                return Collections.emptyList();
055            case 1:
056                return Collections.singletonList(original.get(0));
057            default:
058                return Collections.unmodifiableList(new ArrayList<>(original));
059        }
060    }
061
062    /**
063     * Creates an unmodifiable copy of the given {@link Set} instance.
064     *
065     * @param original the set to be copied
066     * @param <E> the type of every item in the entry
067     * @return a unmodifiable copy of the given {@link Set} instance
068     * @since 4.0.0
069     */
070    public static <E> Set<E> copyOf(final Set<E> original) {
071        switch (original.size()) {
072            case 0:
073                return Collections.emptySet();
074            case 1:
075                return Collections.singleton(original.iterator().next());
076            default:
077                return Collections.unmodifiableSet(new LinkedHashSet<>(original));
078        }
079    }
080
081    /**
082     * Creates an unmodifiable copy of the given {@link Map} instance.
083     *
084     * @param original the map to be copied
085     * @param <K> key type of the map
086     * @param <V> value type of the map
087     * @return an unmodifiable copy of the given {@link Map} instance.
088     * @since 4.1.0
089     */
090    public static <K, V> Map<K, V> copyOf(final Map<K, V> original) {
091        switch (original.size()) {
092            case 0:
093                return Collections.emptyMap();
094            case 1:
095                final Map.Entry<K, V> entry = original.entrySet().iterator().next();
096                return Collections.singletonMap(entry.getKey(), entry.getValue());
097            default:
098                if (original instanceof LinkedHashMap<?, ?>) {
099                    return Collections.unmodifiableMap(new LinkedHashMap<>(original));
100                } else {
101                    return Collections.unmodifiableMap(new HashMap<>(original));
102                }
103        }
104    }
105
106    /**
107     * Creates an unmodifiable copy of the given array as a list,
108     * preserving order.
109     *
110     * @param original the array to be copied into a list
111     * @param <E> the type of every item in the entry
112     * @return a unmodifiable copy of the given array as a {@link List} instance
113     * @since 4.0.0
114     */
115    @SafeVarargs
116    @SuppressWarnings("varargs")
117    public static <E> List<E> toList(final E... original) {
118        switch (original.length) {
119            case 0:
120                return Collections.emptyList();
121            case 1:
122                return Collections.singletonList(original[0]);
123            default:
124                return Collections.unmodifiableList(new ArrayList<>(Arrays.asList(original)));
125        }
126    }
127
128    /**
129     * Creates an unmodifiable copy of the given array as a set.
130     *
131     * @param original the array to be copied into a set
132     * @param <E> the type of every item in the entry
133     * @return a unmodifiable copy of the given array as a {@link Set} instance
134     * @since 4.0.0
135     */
136    @SafeVarargs
137    @SuppressWarnings("varargs")
138    public static <E> Set<E> toSet(final E... original) {
139        switch (original.length) {
140            case 0:
141                return Collections.emptySet();
142            case 1:
143                return Collections.singleton(original[0]);
144            default:
145                return Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(original)));
146        }
147    }
148
149    /**
150     * Build an unmodifiable map.
151     *
152     * @param <K> key type
153     * @param <V> value type
154     * @param handler consumer that will populate the map wih keys
155     * @return a new unmodifiable map
156     * @since 4.0.0
157     */
158    public static <K, V> Map<K, V> buildMap(final Consumer<Map<K, V>> handler) {
159        final Map<K, V> builder = new LinkedHashMap<>();
160        requireNonNull(handler, "handler").accept(builder);
161        return Collections.unmodifiableMap(builder);
162    }
163
164    /**
165     * Creates an immutable instance of {@link Map.Entry}.
166     *
167     * @param key the key in the entry
168     * @param value the value in the entry
169     * @param <K> the key's type
170     * @param <V> the value's type
171     * @return the new map entry
172     * @since 4.0.0
173     */
174    public static <K, V> Map.Entry<K, V> immutableMapEntry(final K key, final V value) {
175        return new AbstractMap.SimpleImmutableEntry<>(key, value);
176    }
177
178}