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 com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Iterables;
17 import com.google.common.collect.Iterators;
18 import java.util.AbstractList;
19 import java.util.AbstractSet;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.List;
25 import java.util.Spliterator;
26 import java.util.stream.Stream;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.opendaylight.yangtools.concepts.Delegator;
29 import org.opendaylight.yangtools.concepts.Immutable;
32 * Utility class for adapting a {@link Collection}s to {@link Set}s and {@link List}s.
34 * @author Robert Varga
38 public final class CollectionWrappers {
39 private static final class ListWrapper<E> extends AbstractList<E> implements Delegator<Collection<E>> {
40 private final Collection<E> delegate;
42 ListWrapper(final Collection<E> delegate) {
43 this.delegate = requireNonNull(delegate);
47 public Collection<E> getDelegate() {
52 public Iterator<E> iterator() {
53 return Iterators.unmodifiableIterator(delegate.iterator());
58 return delegate.size();
62 public Spliterator<E> spliterator() {
63 return delegate.spliterator();
67 public Stream<E> parallelStream() {
68 return delegate.parallelStream();
72 public Stream<E> stream() {
73 return delegate.stream();
77 public E get(final int index) {
78 return Iterables.get(delegate, index);
82 private static final class SetWrapper<E> extends AbstractSet<E> implements Delegator<Collection<E>> {
83 private final Collection<E> delegate;
85 SetWrapper(final Collection<E> delegate) {
86 this.delegate = requireNonNull(delegate);
90 public Collection<E> getDelegate() {
95 public Iterator<E> iterator() {
96 return Iterators.unmodifiableIterator(delegate.iterator());
101 return delegate.size();
105 public Spliterator<E> spliterator() {
106 return delegate.spliterator();
110 public Stream<E> parallelStream() {
111 return delegate.parallelStream();
115 public Stream<E> stream() {
116 return delegate.stream();
120 private CollectionWrappers() {
125 * Wrap the specified {@link Collection} as a {@link List}. If the collection is already a List, it is wrapped in
126 * a {@link Collections#unmodifiableList(List)} to prevent mutability leaking. If the collection is determined
127 * to be empty, an empty list is returned instead. If the collection is a known-immutable implementation of List
128 * interface, it is returned unwrapped. Backing collection is required to be effectively immutable. If this
129 * requirement is violated, the returned object may behave in unpredictable ways.
131 * @param collection Collection to be wrapped
132 * @return An effectively-immutable wrapper of the collection.
133 * @throws NullPointerException if collection is null
135 public static <E> List<E> wrapAsList(final Collection<E> collection) {
136 if (collection.isEmpty()) {
137 return ImmutableList.of();
139 if (collection instanceof SetWrapper) {
140 return wrapAsList(((SetWrapper<E>) collection).getDelegate());
142 if (collection instanceof List) {
143 final List<E> cast = (List<E>) collection;
144 return cast instanceof ListWrapper || cast instanceof Immutable || cast instanceof ImmutableList
145 ? cast : Collections.unmodifiableList(cast);
148 return new ListWrapper<>(collection);
152 * Wrap the specified {@link Collection} as a {@link Set}. If the collection is already a Set, it is wrapped in
153 * a {@link Collections#unmodifiableSet(Set)} to prevent mutability leaking. If the collection is determined
154 * to be empty, an empty set is returned instead. If the collection is a known-immutable implementation of Set
155 * interface, it is returned unwrapped. The collection is checked for duplicates at instantiation time, such that
156 * it effectively implements the Set contract. Backing collection is required to be effectively immutable. If this
157 * requirement is violated, the returned object may behave in unpredictable ways.
159 * @param collection Collection to be wrapped
160 * @return An effectively-immutable wrapper of the collection.
161 * @throws NullPointerException if collection is null or any of its elements is null
162 * @throws IllegalArgumentException if the collection's contents do not conform to the Set contract
164 public static <E> Set<E> wrapAsSet(final Collection<E> collection) {
165 if (collection.isEmpty()) {
166 return ImmutableSet.of();
168 if (collection instanceof ListWrapper) {
169 return wrapAsSet(((ListWrapper<E>) collection).getDelegate());
171 if (collection instanceof Set) {
172 final Set<E> cast = (Set<E>) collection;
173 return cast instanceof SetWrapper || cast instanceof Immutable || cast instanceof SingletonSet
174 || cast instanceof ImmutableSet ? cast : Collections.unmodifiableSet(cast);
177 final Set<E> check = ImmutableSet.copyOf(collection);
178 checkArgument(collection.size() == check.size(), "Supplied collection %s has duplicate elements", collection);
179 return new SetWrapper<>(collection);