001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.metaschema.core.util;
028
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Collection;
032import java.util.Collections;
033import java.util.Iterator;
034import java.util.LinkedList;
035import java.util.List;
036import java.util.Map;
037import java.util.Set;
038import java.util.Spliterator;
039import java.util.Spliterators;
040import java.util.stream.Collectors;
041import java.util.stream.IntStream;
042import java.util.stream.Stream;
043import java.util.stream.StreamSupport;
044
045import edu.umd.cs.findbugs.annotations.NonNull;
046import edu.umd.cs.findbugs.annotations.Nullable;
047
048public final class CollectionUtil {
049
050  private CollectionUtil() {
051    // disable construction
052  }
053
054  /**
055   * Get a {@link Stream} for the provided {@link Iterable}.
056   *
057   * @param <T>
058   *          the type to iterate on
059   * @param iterator
060   *          the iterator
061   * @return the stream
062   */
063  public static <T> Stream<T> toStream(@NonNull Iterator<T> iterator) {
064    Iterable<T> iterable = toIterable(iterator);
065    return StreamSupport.stream(iterable.spliterator(), false);
066  }
067
068  /**
069   * Get an {@link Iterable} for the provided {@link Stream}.
070   *
071   * @param <T>
072   *          the type to iterate on
073   * @param stream
074   *          the stream to iterate over
075   * @return the resulting iterable instance
076   */
077  @NonNull
078  public static <T> Iterable<T> toIterable(@NonNull Stream<T> stream) {
079    return toIterable(ObjectUtils.notNull(stream.iterator()));
080  }
081
082  /**
083   * Get an {@link Iterable} for the provided {@link Iterator}.
084   *
085   * @param <T>
086   *          the type to iterate on
087   * @param iterator
088   *          the iterator
089   * @return the resulting iterable instance
090   */
091  @NonNull
092  public static <T> Iterable<T> toIterable(@NonNull Iterator<T> iterator) {
093    return () -> iterator;
094  }
095
096  /**
097   * Get a reverse {@link Iterable} for the provided {@link List}.
098   *
099   * @param <T>
100   *          the type to iterate on
101   * @param list
102   *          the list of items to iterate over
103   * @return the resulting iterable instance
104   */
105  @NonNull
106  public static <T> Iterable<T> toDescendingIterable(@NonNull List<T> list) {
107    return toIterable(descendingIterator(list));
108  }
109
110  /**
111   * Convert the provided {@link Iterable} to a list of the same generic type.
112   *
113   * @param <T>
114   *          the collection item's generic type
115   * @param iterable
116   *          the Iterable to convert to a list
117   * @return the list
118   */
119  @NonNull
120  public static <T> List<T> toList(Iterable<T> iterable) {
121    return ObjectUtils.notNull(StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()));
122  }
123
124  /**
125   * Convert the provided {@link Iterator} to a list of the same generic type.
126   *
127   * @param <T>
128   *          the collection item's generic type
129   * @param iterator
130   *          the Iterator to convert to a list
131   * @return the list
132   */
133  @NonNull
134  public static <T> List<T> toList(Iterator<T> iterator) {
135    return ObjectUtils.notNull(
136        StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
137            .collect(Collectors.toList()));
138  }
139
140  /**
141   * Get a reverse {@link Iterator} for the provided {@link List}.
142   *
143   * @param <T>
144   *          the type to iterate on
145   * @param list
146   *          the list of items to iterate over
147   * @return the resulting Iterator instance
148   */
149  @NonNull
150  public static <T> Iterator<T> descendingIterator(@NonNull List<T> list) {
151    Iterator<T> retval;
152    if (list instanceof LinkedList) {
153      retval = ((LinkedList<T>) list).descendingIterator();
154    } else if (list instanceof ArrayList) {
155      retval = IntStream.range(0, list.size())
156          .map(i -> list.size() - 1 - i)
157          .mapToObj(list::get).iterator();
158    } else {
159      throw new UnsupportedOperationException();
160    }
161    return ObjectUtils.notNull(retval);
162  }
163
164  @NonNull
165  public static <T extends Collection<A>, A> T requireNonEmpty(@NonNull T collection) {
166    if (collection.isEmpty()) {
167      throw new IllegalStateException();
168    }
169    return collection;
170  }
171
172  @NonNull
173  public static <T extends Collection<A>, A> T requireNonEmpty(@NonNull T collection, @NonNull String message) {
174    if (collection.isEmpty()) {
175      throw new IllegalStateException(message);
176    }
177    return collection;
178  }
179
180  /**
181   * A wrapper of the {@link Collections#unmodifiableCollection(Collection)}
182   * method that ensure a {@link NonNull} result is returned.
183   *
184   * @param <T>
185   *          the collection's item type
186   * @param collection
187   *          the collection
188   * @return a non-null unmodifiable instance of the provided collection
189   */
190  @SuppressWarnings("null")
191  @NonNull
192  public static <T> Collection<T> unmodifiableCollection(@NonNull Collection<T> collection) {
193    return Collections.unmodifiableCollection(collection);
194  }
195
196  @SuppressWarnings("null")
197  @NonNull
198  public static <T> Set<T> singleton(@NonNull T value) {
199    return Collections.singleton(value);
200  }
201
202  @SuppressWarnings("null")
203  @NonNull
204  public static <T> Set<T> emptySet() {
205    return Collections.emptySet();
206  }
207
208  @SuppressWarnings("null")
209  @NonNull
210  public static <T> Set<T> unmodifiableSet(@NonNull Set<T> set) {
211    return Collections.unmodifiableSet(set);
212  }
213
214  @NonNull
215  public static <T> List<T> listOrEmpty(@Nullable List<T> list) {
216    return list == null ? emptyList() : list;
217  }
218
219  @SafeVarargs
220  @SuppressWarnings("null")
221  @NonNull
222  public static <T> List<T> listOrEmpty(@Nullable T... array) {
223    return array == null || array.length == 0 ? emptyList() : Arrays.asList(array);
224  }
225
226  @SuppressWarnings("null")
227  @NonNull
228  public static <T> List<T> emptyList() {
229    return Collections.emptyList();
230  }
231
232  @SuppressWarnings("null")
233  @NonNull
234  public static <T> List<T> unmodifiableList(@NonNull List<T> list) {
235    return Collections.unmodifiableList(list);
236  }
237
238  @SuppressWarnings("null")
239  @NonNull
240  public static <T> List<T> singletonList(@NonNull T instance) {
241    return Collections.singletonList(instance);
242  }
243
244  @SuppressWarnings("null")
245  @NonNull
246  public static <K, V> Map<K, V> emptyMap() {
247    return Collections.emptyMap();
248  }
249
250  @SuppressWarnings("null")
251  @NonNull
252  public static <K, V> Map<K, V> singletonMap(@NonNull K key, @NonNull V value) {
253    return Collections.singletonMap(key, value);
254  }
255
256  @SuppressWarnings("null")
257  @NonNull
258  public static <K, V> Map<K, V> unmodifiableMap(@NonNull Map<K, V> map) {
259    return Collections.unmodifiableMap(map);
260  }
261}