af024857da5c39de2437a13ab4169ec6ac512ca0
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / SingletonSet.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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 com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Iterators;
13 import java.io.Serializable;
14 import java.util.Collection;
15 import java.util.Iterator;
16 import java.util.Set;
17 import javax.annotation.Nonnull;
18 import org.opendaylight.yangtools.concepts.Immutable;
19
20 /**
21  * A {@link Set} containing a single value. For some reason neither Java nor Guava provide direct access to the retained
22  * element -- which is desirable in some situations, as is the case in {@link SharedSingletonMap#entrySet()}.
23  */
24 @Beta
25 public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable {
26     private static final long serialVersionUID = 1L;
27
28     private static final SingletonSet<?> NULL_SINGLETON = new SingletonSet<Object>() {
29         private static final long serialVersionUID = 1L;
30
31         @Override
32         @SuppressWarnings("checkstyle:parameterName")
33         public boolean contains(final Object o) {
34             return o == null;
35         }
36
37         @Override
38         @SuppressWarnings("checkstyle:equalsHashCode")
39         public int hashCode() {
40             return 0;
41         }
42
43         @Override
44         public Object getElement() {
45             return null;
46         }
47
48         @Override
49         public String toString() {
50             return "[null]";
51         }
52
53         private Object readResolve() {
54             return NULL_SINGLETON;
55         }
56     };
57
58     @SuppressWarnings("unchecked")
59     public static <E> SingletonSet<E> of(@Nonnull final E element) {
60         if (element == null) {
61             return (SingletonSet<E>) NULL_SINGLETON;
62         }
63         return new RegularSingletonSet<>(element);
64     }
65
66     public abstract E getElement();
67
68     @Override
69     public final int size() {
70         return 1;
71     }
72
73     @Override
74     public final boolean isEmpty() {
75         return false;
76     }
77
78     @Override
79     public final Iterator<E> iterator() {
80         return Iterators.singletonIterator(getElement());
81     }
82
83     @Nonnull
84     @Override
85     public final Object[] toArray() {
86         return new Object[] { getElement() };
87     }
88
89     @Nonnull
90     @SuppressWarnings({ "unchecked", "checkstyle:parameterName" })
91     @Override
92     public final <T> T[] toArray(@Nonnull final T[] a) {
93         if (a.length > 0) {
94             a[0] = (T)getElement();
95             return a;
96         }
97
98         return (T[]) new Object[] {getElement()};
99     }
100
101     @Override
102     @SuppressWarnings("checkstyle:parameterName")
103     public final boolean add(final E e) {
104         throw new UnsupportedOperationException();
105     }
106
107     @Override
108     @SuppressWarnings("checkstyle:parameterName")
109     public final boolean remove(final Object o) {
110         throw new UnsupportedOperationException();
111     }
112
113     @Override
114     @SuppressWarnings("checkstyle:parameterName")
115     public final boolean containsAll(@Nonnull final Collection<?> c) {
116         if (c.isEmpty()) {
117             return true;
118         }
119         if (c.size() != 1) {
120             return false;
121         }
122
123         return otherContains(c);
124     }
125
126     @Override
127     @SuppressWarnings("checkstyle:parameterName")
128     public final boolean addAll(@Nonnull final Collection<? extends E> c) {
129         throw new UnsupportedOperationException();
130     }
131
132     @Override
133     @SuppressWarnings("checkstyle:parameterName")
134     public final boolean retainAll(@Nonnull final Collection<?> c) {
135         throw new UnsupportedOperationException();
136     }
137
138     @Override
139     @SuppressWarnings("checkstyle:parameterName")
140     public final boolean removeAll(@Nonnull final Collection<?> c) {
141         throw new UnsupportedOperationException();
142     }
143
144     @Override
145     public final void clear() {
146         throw new UnsupportedOperationException();
147     }
148
149     @Override
150     public abstract int hashCode();
151
152     @Override
153     @SuppressWarnings("checkstyle:equalsHashCode")
154     public final boolean equals(final Object obj) {
155         if (obj == this) {
156             return true;
157         }
158         if (!(obj instanceof Set)) {
159             return false;
160         }
161
162         final Set<?> s = (Set<?>)obj;
163         return s.size() == 1 && otherContains(s);
164     }
165
166     private boolean otherContains(final Collection<?> other) {
167         try {
168             return other.contains(getElement());
169         } catch (ClassCastException | NullPointerException e) {
170             return false;
171         }
172     }
173
174     private static final class RegularSingletonSet<E> extends SingletonSet<E> {
175         private static final long serialVersionUID = 1L;
176         private final E element;
177
178         RegularSingletonSet(final E element) {
179             this.element = Preconditions.checkNotNull(element);
180         }
181
182         @Override
183         @SuppressWarnings("checkstyle:parameterName")
184         public boolean contains(final Object o) {
185             return element.equals(o);
186         }
187
188         @Override
189         public E getElement() {
190             return element;
191         }
192
193         @Override
194         @SuppressWarnings("checkstyle:equalsHashCode")
195         public int hashCode() {
196             return getElement().hashCode();
197         }
198
199         @Override
200         public String toString() {
201             return "[" + element + ']';
202         }
203     }
204 }