• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Preconditions;
21 
22 import java.util.Set;
23 
24 import javax.annotation.Nullable;
25 
26 /**
27  * Implementation of {@link ImmutableSet} with exactly one element.
28  *
29  * @author Kevin Bourrillion
30  * @author Nick Kralevich
31  */
32 @GwtCompatible(serializable = true, emulated = true)
33 @SuppressWarnings("serial") // uses writeReplace(), not default serialization
34 final class SingletonImmutableSet<E> extends ImmutableSet<E> {
35 
36   final transient E element;
37   // This is transient because it will be recalculated on the first
38   // call to hashCode().
39   //
40   // A race condition is avoided since threads will either see that the value
41   // is zero and recalculate it themselves, or two threads will see it at
42   // the same time, and both recalculate it.  If the cachedHashCode is 0,
43   // it will always be recalculated, unfortunately.
44   private transient int cachedHashCode;
45 
SingletonImmutableSet(E element)46   SingletonImmutableSet(E element) {
47     this.element = Preconditions.checkNotNull(element);
48   }
49 
SingletonImmutableSet(E element, int hashCode)50   SingletonImmutableSet(E element, int hashCode) {
51     // Guaranteed to be non-null by the presence of the pre-computed hash code.
52     this.element = element;
53     cachedHashCode = hashCode;
54   }
55 
56   @Override
size()57   public int size() {
58     return 1;
59   }
60 
isEmpty()61   @Override public boolean isEmpty() {
62     return false;
63   }
64 
contains(Object target)65   @Override public boolean contains(Object target) {
66     return element.equals(target);
67   }
68 
iterator()69   @Override public UnmodifiableIterator<E> iterator() {
70     return Iterators.singletonIterator(element);
71   }
72 
isPartialView()73   @Override boolean isPartialView() {
74     return false;
75   }
76 
77   @Override
copyIntoArray(Object[] dst, int offset)78   int copyIntoArray(Object[] dst, int offset) {
79     dst[offset] = element;
80     return offset + 1;
81   }
82 
equals(@ullable Object object)83   @Override public boolean equals(@Nullable Object object) {
84     if (object == this) {
85       return true;
86     }
87     if (object instanceof Set) {
88       Set<?> that = (Set<?>) object;
89       return that.size() == 1 && element.equals(that.iterator().next());
90     }
91     return false;
92   }
93 
hashCode()94   @Override public final int hashCode() {
95     // Racy single-check.
96     int code = cachedHashCode;
97     if (code == 0) {
98       cachedHashCode = code = element.hashCode();
99     }
100     return code;
101   }
102 
isHashCodeFast()103   @Override boolean isHashCodeFast() {
104     return cachedHashCode != 0;
105   }
106 
toString()107   @Override public String toString() {
108     String elementToString = element.toString();
109     return new StringBuilder(elementToString.length() + 2)
110         .append('[')
111         .append(elementToString)
112         .append(']')
113         .toString();
114   }
115 }
116