Separate out {Identity,Equality}QueuedNotificationManager
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / CollectionWrappers.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.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;
24 import java.util.Set;
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;
30
31 /**
32  * Utility class for adapting a {@link Collection}s to {@link Set}s and {@link List}s.
33  *
34  * @author Robert Varga
35  */
36 @Beta
37 @NonNullByDefault
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;
41
42         ListWrapper(final Collection<E> delegate) {
43             this.delegate = requireNonNull(delegate);
44         }
45
46         @Override
47         public Collection<E> getDelegate() {
48             return delegate;
49         }
50
51         @Override
52         public Iterator<E> iterator() {
53             return Iterators.unmodifiableIterator(delegate.iterator());
54         }
55
56         @Override
57         public int size() {
58             return delegate.size();
59         }
60
61         @Override
62         public Spliterator<E> spliterator() {
63             return delegate.spliterator();
64         }
65
66         @Override
67         public Stream<E> parallelStream() {
68             return delegate.parallelStream();
69         }
70
71         @Override
72         public Stream<E> stream() {
73             return delegate.stream();
74         }
75
76         @Override
77         public E get(final int index) {
78             return Iterables.get(delegate, index);
79         }
80     }
81
82     private static final class SetWrapper<E> extends AbstractSet<E> implements Delegator<Collection<E>> {
83         private final Collection<E> delegate;
84
85         SetWrapper(final Collection<E> delegate) {
86             this.delegate = requireNonNull(delegate);
87         }
88
89         @Override
90         public Collection<E> getDelegate() {
91             return delegate;
92         }
93
94         @Override
95         public Iterator<E> iterator() {
96             return Iterators.unmodifiableIterator(delegate.iterator());
97         }
98
99         @Override
100         public int size() {
101             return delegate.size();
102         }
103
104         @Override
105         public Spliterator<E> spliterator() {
106             return delegate.spliterator();
107         }
108
109         @Override
110         public Stream<E> parallelStream() {
111             return delegate.parallelStream();
112         }
113
114         @Override
115         public Stream<E> stream() {
116             return delegate.stream();
117         }
118     }
119
120     private CollectionWrappers() {
121
122     }
123
124     /**
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.
130      *
131      * @param collection Collection to be wrapped
132      * @return An effectively-immutable wrapper of the collection.
133      * @throws NullPointerException if collection is null
134      */
135     public static <E> List<E> wrapAsList(final Collection<E> collection) {
136         if (collection.isEmpty()) {
137             return ImmutableList.of();
138         }
139         if (collection instanceof SetWrapper) {
140             return wrapAsList(((SetWrapper<E>) collection).getDelegate());
141         }
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);
146         }
147
148         return new ListWrapper<>(collection);
149     }
150
151     /**
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.
158      *
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
163      */
164     public static <E> Set<E> wrapAsSet(final Collection<E> collection) {
165         if (collection.isEmpty()) {
166             return ImmutableSet.of();
167         }
168         if (collection instanceof ListWrapper) {
169             return wrapAsSet(((ListWrapper<E>) collection).getDelegate());
170         }
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);
175         }
176
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);
180     }
181 }