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 com.google.common.annotations.GwtCompatible;
20  import com.google.errorprone.annotations.concurrent.LazyInit;
21  import java.io.Serializable;
22  import java.util.Collection;
23  import java.util.EnumSet;
24  import java.util.Spliterator;
25  import java.util.function.Consumer;
26  
27  /**
28   * Implementation of {@link ImmutableSet} backed by a non-empty {@link
29   * java.util.EnumSet}.
30   *
31   * @author Jared Levy
32   */
33  @GwtCompatible(serializable = true, emulated = true)
34  @SuppressWarnings("serial") // we're overriding default serialization
35  final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
36    @SuppressWarnings("rawtypes") // necessary to compile against Java 8
37    static ImmutableSet asImmutable(EnumSet set) {
38      switch (set.size()) {
39        case 0:
40          return ImmutableSet.of();
41        case 1:
42          return ImmutableSet.of(Iterables.getOnlyElement(set));
43        default:
44          return new ImmutableEnumSet(set);
45      }
46    }
47  
48    /*
49     * Notes on EnumSet and <E extends Enum<E>>:
50     *
51     * This class isn't an arbitrary ForwardingImmutableSet because we need to
52     * know that calling {@code clone()} during deserialization will return an
53     * object that no one else has a reference to, allowing us to guarantee
54     * immutability. Hence, we support only {@link EnumSet}.
55     */
56    private final transient EnumSet<E> delegate;
57  
58    private ImmutableEnumSet(EnumSet<E> delegate) {
59      this.delegate = delegate;
60    }
61  
62    @Override
63    boolean isPartialView() {
64      return false;
65    }
66  
67    @Override
68    public UnmodifiableIterator<E> iterator() {
69      return Iterators.unmodifiableIterator(delegate.iterator());
70    }
71  
72    @Override
73    public Spliterator<E> spliterator() {
74      return delegate.spliterator();
75    }
76  
77    @Override
78    public void forEach(Consumer<? super E> action) {
79      delegate.forEach(action);
80    }
81  
82    @Override
83    public int size() {
84      return delegate.size();
85    }
86  
87    @Override
88    public boolean contains(Object object) {
89      return delegate.contains(object);
90    }
91  
92    @Override
93    public boolean containsAll(Collection<?> collection) {
94      if (collection instanceof ImmutableEnumSet<?>) {
95        collection = ((ImmutableEnumSet<?>) collection).delegate;
96      }
97      return delegate.containsAll(collection);
98    }
99  
100   @Override
101   public boolean isEmpty() {
102     return delegate.isEmpty();
103   }
104 
105   @Override
106   public boolean equals(Object object) {
107     if (object == this) {
108       return true;
109     }
110     if (object instanceof ImmutableEnumSet) {
111       object = ((ImmutableEnumSet<?>) object).delegate;
112     }
113     return delegate.equals(object);
114   }
115 
116   @Override
117   boolean isHashCodeFast() {
118     return true;
119   }
120 
121   @LazyInit
122   private transient int hashCode;
123 
124   @Override
125   public int hashCode() {
126     int result = hashCode;
127     return (result == 0) ? hashCode = delegate.hashCode() : result;
128   }
129 
130   @Override
131   public String toString() {
132     return delegate.toString();
133   }
134 
135   // All callers of the constructor are restricted to <E extends Enum<E>>.
136   @Override
137   Object writeReplace() {
138     return new EnumSerializedForm<E>(delegate);
139   }
140 
141   /*
142    * This class is used to serialize ImmutableEnumSet instances.
143    */
144   private static class EnumSerializedForm<E extends Enum<E>> implements Serializable {
145     final EnumSet<E> delegate;
146 
147     EnumSerializedForm(EnumSet<E> delegate) {
148       this.delegate = delegate;
149     }
150 
151     Object readResolve() {
152       // EJ2 #76: Write readObject() methods defensively.
153       return new ImmutableEnumSet<E>(delegate.clone());
154     }
155 
156     private static final long serialVersionUID = 0;
157   }
158 }