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
17package com.google.common.collect;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.Iterator;
25import java.util.List;
26import 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.
40public 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}
207