1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/*
2090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Copyright (C) 2007 Google Inc.
3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson *
4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License.
6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at
7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson *
8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0
9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson *
10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and
14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License.
15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */
16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.collect;
18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
19090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport com.google.common.annotations.GwtCompatible;
20090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport com.google.common.base.Preconditions;
21090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
22090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.Set;
23090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport javax.annotation.Nullable;
25090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
26090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/**
27090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Implementation of {@link ImmutableSet} with exactly one element.
28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson *
29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Kevin Bourrillion
30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Nick Kralevich
31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */
32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson@GwtCompatible(serializable = true)
33090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson@SuppressWarnings("serial") // uses writeReplace(), not default serialization
34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonfinal class SingletonImmutableSet<E> extends ImmutableSet<E> {
35090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  final transient E element;
36090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
37090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  // Non-volatile because:
38090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  //   - Integer is immutable and thus thread-safe;
39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  //   - no problems if one thread overwrites the cachedHashCode from another.
40090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  private transient Integer cachedHashCode;
41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  SingletonImmutableSet(E element) {
43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    this.element = Preconditions.checkNotNull(element);
44090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
45090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
46090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  SingletonImmutableSet(E element, int hashCode) {
47090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    // Guaranteed to be non-null by the presence of the pre-computed hash code.
48090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    this.element = element;
49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    cachedHashCode = hashCode;
50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
52090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  public int size() {
53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return 1;
54090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public boolean isEmpty() {
57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return false;
58090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
59090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
60090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public boolean contains(Object target) {
61090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return element.equals(target);
62090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public UnmodifiableIterator<E> iterator() {
65090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return Iterators.singletonIterator(element);
66090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public Object[] toArray() {
69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return new Object[] { element };
70090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
72090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @SuppressWarnings({"unchecked"})
73090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public <T> T[] toArray(T[] array) {
74090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    if (array.length == 0) {
75090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      array = ObjectArrays.newArray(array, 1);
76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    } else if (array.length > 1) {
77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      array[1] = null;
78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    }
79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    // Writes will produce ArrayStoreException when the toArray() doc requires.
80090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    Object[] objectArray = array;
81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    objectArray[0] = element;
82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return array;
83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
85090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public boolean equals(@Nullable Object object) {
86090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    if (object == this) {
87090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      return true;
88090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    }
89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    if (object instanceof Set) {
90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      Set<?> that = (Set<?>) object;
91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      return that.size() == 1 && element.equals(that.iterator().next());
92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    }
93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return false;
94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
96090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public final int hashCode() {
97090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    Integer code = cachedHashCode;
98090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    if (code == null) {
99090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson      return cachedHashCode = element.hashCode();
100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    }
101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return code;
102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override boolean isHashCodeFast() {
105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return false;
106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson
108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  @Override public String toString() {
109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    String elementToString = element.toString();
110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson    return new StringBuilder(elementToString.length() + 2)
111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson        .append('[')
112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson        .append(elementToString)
113090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson        .append(']')
114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson        .toString();
115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson  }
116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson}
117