958c9085e38b5aac35029e3c1b360e53f535543e
[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         public boolean contains(final Object o) {
33             return o == null;
34         }
35
36         @Override
37         public int hashCode() {
38             return 0;
39         }
40
41         @Override
42         public Object getElement() {
43             return null;
44         }
45
46         @Override
47         public String toString() {
48             return "[null]";
49         }
50
51         private Object readResolve() {
52             return NULL_SINGLETON;
53         }
54     };
55
56     @SuppressWarnings("unchecked")
57     public static <E> SingletonSet<E> of(@Nonnull final E element) {
58         if (element == null) {
59             return (SingletonSet<E>) NULL_SINGLETON;
60         }
61         return new RegularSingletonSet<>(element);
62     }
63
64     public abstract E getElement();
65
66     @Override
67     public final int size() {
68         return 1;
69     }
70
71     @Override
72     public final boolean isEmpty() {
73         return false;
74     }
75
76     @Override
77     public final Iterator<E> iterator() {
78         return Iterators.singletonIterator(getElement());
79     }
80
81     @Nonnull
82     @Override
83     public final Object[] toArray() {
84         return new Object[] { getElement() };
85     }
86
87     @Nonnull
88     @SuppressWarnings("unchecked")
89     @Override
90     public final <T> T[] toArray(@Nonnull final T[] a) {
91         if (a.length > 0) {
92             a[0] = (T)getElement();
93             return a;
94         }
95
96         return (T[]) new Object[] {getElement()};
97     }
98
99     @Override
100     public final boolean add(final E e) {
101         throw new UnsupportedOperationException();
102     }
103
104     @Override
105     public final boolean remove(final Object o) {
106         throw new UnsupportedOperationException();
107     }
108
109     @Override
110     public final boolean containsAll(@Nonnull final Collection<?> c) {
111         if (c.isEmpty()) {
112             return true;
113         }
114         if (c.size() != 1) {
115             return false;
116         }
117
118         return otherContains(c);
119     }
120
121     @Override
122     public final boolean addAll(@Nonnull final Collection<? extends E> c) {
123         throw new UnsupportedOperationException();
124     }
125
126     @Override
127     public final boolean retainAll(@Nonnull final Collection<?> c) {
128         throw new UnsupportedOperationException();
129     }
130
131     @Override
132     public final boolean removeAll(@Nonnull final Collection<?> c) {
133         throw new UnsupportedOperationException();
134     }
135
136     @Override
137     public final void clear() {
138         throw new UnsupportedOperationException();
139     }
140
141     @Override
142     public abstract int hashCode();
143
144     @Override
145     public final boolean equals(final Object obj) {
146         if (obj == this) {
147             return true;
148         }
149         if (!(obj instanceof Set)) {
150             return false;
151         }
152
153         final Set<?> s = (Set<?>)obj;
154         return s.size() == 1 && otherContains(s);
155     }
156
157     private boolean otherContains(final Collection<?> other) {
158         try {
159             return other.contains(getElement());
160         } catch (ClassCastException | NullPointerException e) {
161             return false;
162         }
163     }
164
165     private static final class RegularSingletonSet<E> extends SingletonSet<E> {
166         private static final long serialVersionUID = 1L;
167         private final E element;
168
169         RegularSingletonSet(final E element) {
170             this.element = Preconditions.checkNotNull(element);
171         }
172
173         @Override
174         public boolean contains(final Object o) {
175             return element.equals(o);
176         }
177
178         @Override
179         public E getElement() {
180             return element;
181         }
182
183         @Override
184         public int hashCode() {
185             return getElement().hashCode();
186         }
187
188         @Override
189         public String toString() {
190             return "[" + element + ']';
191         }
192     }
193 }