View Javadoc
1   /*
2    * Copyright (C) 2009 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 static com.google.common.base.Preconditions.checkNotNull;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  
28  /**
29   * GWT emulated version of {@link ImmutableSet}.  For the unsorted sets, they
30   * are thin wrapper around {@link java.util.Collections#emptySet()}, {@link
31   * Collections#singleton(Object)} and {@link java.util.LinkedHashSet} for
32   * empty, singleton and regular sets respectively.  For the sorted sets, it's
33   * a thin wrapper around {@link java.util.TreeSet}.
34   *
35   * @see ImmutableSortedSet
36   *
37   * @author Hayward Chan
38   */
39  @SuppressWarnings("serial")  // Serialization only done in GWT.
40  public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> {
41    ImmutableSet() {}
42  
43    // Casting to any type is safe because the set will never hold any elements.
44    @SuppressWarnings({"unchecked"})
45    public static <E> ImmutableSet<E> of() {
46      return (ImmutableSet<E>) EmptyImmutableSet.INSTANCE;
47    }
48  
49    public static <E> ImmutableSet<E> of(E element) {
50      return new SingletonImmutableSet<E>(element);
51    }
52  
53    @SuppressWarnings("unchecked")
54    public static <E> ImmutableSet<E> of(E e1, E e2) {
55      return create(e1, e2);
56    }
57  
58    @SuppressWarnings("unchecked")
59    public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
60      return create(e1, e2, e3);
61    }
62  
63    @SuppressWarnings("unchecked")
64    public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
65      return create(e1, e2, e3, e4);
66    }
67  
68    @SuppressWarnings("unchecked")
69    public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
70      return create(e1, e2, e3, e4, e5);
71    }
72  
73    @SuppressWarnings("unchecked")
74    public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
75      int size = others.length + 6;
76      List<E> all = new ArrayList<E>(size);
77      Collections.addAll(all, e1, e2, e3, e4, e5, e6);
78      Collections.addAll(all, others);
79      return copyOf(all.iterator());
80    }
81  
82    public static <E> ImmutableSet<E> copyOf(E[] elements) {
83      checkNotNull(elements);
84      switch (elements.length) {
85        case 0:
86          return of();
87        case 1:
88          return of(elements[0]);
89        default:
90          return create(elements);
91      }
92    }
93  
94    public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) {
95      Iterable<? extends E> iterable = elements;
96      return copyOf(iterable);
97    }
98  
99    public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
100     if (elements instanceof ImmutableSet && !(elements instanceof ImmutableSortedSet)) {
101       @SuppressWarnings("unchecked") // all supported methods are covariant
102       ImmutableSet<E> set = (ImmutableSet<E>) elements;
103       return set;
104     }
105     return copyOf(elements.iterator());
106   }
107 
108   public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
109     if (!elements.hasNext()) {
110       return of();
111     }
112     E first = elements.next();
113     if (!elements.hasNext()) {
114       // TODO: Remove "ImmutableSet.<E>" when eclipse bug is fixed.
115       return ImmutableSet.<E>of(first);
116     }
117 
118     Set<E> delegate = Sets.newLinkedHashSet();
119     delegate.add(checkNotNull(first));
120     do {
121       delegate.add(checkNotNull(elements.next()));
122     } while (elements.hasNext());
123 
124     return unsafeDelegate(delegate);
125   }
126 
127   // Factory methods that skips the null checks on elements, only used when
128   // the elements are known to be non-null.
129   static <E> ImmutableSet<E> unsafeDelegate(Set<E> delegate) {
130     switch (delegate.size()) {
131       case 0:
132         return of();
133       case 1:
134         return new SingletonImmutableSet<E>(delegate.iterator().next());
135       default:
136         return new RegularImmutableSet<E>(delegate);
137     }
138   }
139 
140   private static <E> ImmutableSet<E> create(E... elements) {
141     // Create the set first, to remove duplicates if necessary.
142     Set<E> set = Sets.newLinkedHashSet();
143     Collections.addAll(set, elements);
144     for (E element : set) {
145       checkNotNull(element);
146     }
147 
148     switch (set.size()) {
149       case 0:
150         return of();
151       case 1:
152         return new SingletonImmutableSet<E>(set.iterator().next());
153       default:
154         return new RegularImmutableSet<E>(set);
155     }
156   }
157 
158   @Override public boolean equals(Object obj) {
159     return Sets.equalsImpl(this, obj);
160   }
161 
162   @Override public int hashCode() {
163     return Sets.hashCodeImpl(this);
164   }
165 
166   public static <E> Builder<E> builder() {
167     return new Builder<E>();
168   }
169 
170   public static class Builder<E> extends ImmutableCollection.Builder<E> {
171     // accessed directly by ImmutableSortedSet
172     final ArrayList<E> contents = Lists.newArrayList();
173 
174     public Builder() {}
175 
176     @Override public Builder<E> add(E element) {
177       contents.add(checkNotNull(element));
178       return this;
179     }
180 
181     @Override public Builder<E> add(E... elements) {
182       checkNotNull(elements); // for GWT
183       contents.ensureCapacity(contents.size() + elements.length);
184       super.add(elements);
185       return this;
186     }
187 
188     @Override public Builder<E> addAll(Iterable<? extends E> elements) {
189       if (elements instanceof Collection) {
190         Collection<?> collection = (Collection<?>) elements;
191         contents.ensureCapacity(contents.size() + collection.size());
192       }
193       super.addAll(elements);
194       return this;
195     }
196 
197     @Override public Builder<E> addAll(Iterator<? extends E> elements) {
198       super.addAll(elements);
199       return this;
200     }
201 
202     @Override public ImmutableSet<E> build() {
203       return copyOf(contents.iterator());
204     }
205   }
206 }