1/*
2 * Copyright (C) 2012 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 */
16package com.google.common.collect;
17
18import static com.google.common.base.Preconditions.checkArgument;
19
20import com.google.common.annotations.GwtCompatible;
21
22import java.io.Serializable;
23import java.util.EnumMap;
24import java.util.Iterator;
25
26import javax.annotation.Nullable;
27
28/**
29 * Implementation of {@link ImmutableMap} backed by a non-empty {@link
30 * java.util.EnumMap}.
31 *
32 * @author Louis Wasserman
33 */
34@GwtCompatible(serializable = true, emulated = true)
35@SuppressWarnings("serial") // we're overriding default serialization
36final class ImmutableEnumMap<K extends Enum<K>, V> extends ImmutableMap<K, V> {
37  static <K extends Enum<K>, V> ImmutableMap<K, V> asImmutable(EnumMap<K, V> map) {
38    switch (map.size()) {
39      case 0:
40        return ImmutableMap.of();
41      case 1: {
42        Entry<K, V> entry = Iterables.getOnlyElement(map.entrySet());
43        return ImmutableMap.of(entry.getKey(), entry.getValue());
44      }
45      default:
46        return new ImmutableEnumMap<K, V>(map);
47    }
48  }
49
50  private transient final EnumMap<K, V> delegate;
51
52  private ImmutableEnumMap(EnumMap<K, V> delegate) {
53    this.delegate = delegate;
54    checkArgument(!delegate.isEmpty());
55  }
56
57  @Override
58  ImmutableSet<K> createKeySet() {
59    return new ImmutableSet<K>() {
60
61      @Override
62      public boolean contains(Object object) {
63        return delegate.containsKey(object);
64      }
65
66      @Override
67      public int size() {
68        return ImmutableEnumMap.this.size();
69      }
70
71      @Override
72      public UnmodifiableIterator<K> iterator() {
73        return Iterators.unmodifiableIterator(delegate.keySet().iterator());
74      }
75
76      @Override
77      boolean isPartialView() {
78        return true;
79      }
80    };
81  }
82
83  @Override
84  public int size() {
85    return delegate.size();
86  }
87
88  @Override
89  public boolean containsKey(@Nullable Object key) {
90    return delegate.containsKey(key);
91  }
92
93  @Override
94  public V get(Object key) {
95    return delegate.get(key);
96  }
97
98  @Override
99  ImmutableSet<Entry<K, V>> createEntrySet() {
100    return new ImmutableMapEntrySet<K, V>() {
101
102      @Override
103      ImmutableMap<K, V> map() {
104        return ImmutableEnumMap.this;
105      }
106
107      @Override
108      public UnmodifiableIterator<Entry<K, V>> iterator() {
109        return new UnmodifiableIterator<Entry<K, V>>() {
110          private final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
111
112          @Override
113          public boolean hasNext() {
114            return backingIterator.hasNext();
115          }
116
117          @Override
118          public Entry<K, V> next() {
119            Entry<K, V> entry = backingIterator.next();
120            return Maps.immutableEntry(entry.getKey(), entry.getValue());
121          }
122        };
123      }
124    };
125  }
126
127  @Override
128  boolean isPartialView() {
129    return false;
130  }
131
132  // All callers of the constructor are restricted to <K extends Enum<K>>.
133  @Override Object writeReplace() {
134    return new EnumSerializedForm<K, V>(delegate);
135  }
136
137  /*
138   * This class is used to serialize ImmutableEnumSet instances.
139   */
140  private static class EnumSerializedForm<K extends Enum<K>, V>
141      implements Serializable {
142    final EnumMap<K, V> delegate;
143    EnumSerializedForm(EnumMap<K, V> delegate) {
144      this.delegate = delegate;
145    }
146    Object readResolve() {
147      return new ImmutableEnumMap<K, V>(delegate);
148    }
149    private static final long serialVersionUID = 0;
150  }
151}
152