1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections.set;
18
19 import java.io.Serializable;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.Map;
23 import java.util.Set;
24
25 /**
26 * Decorates a <code>Map</code> to obtain <code>Set</code> behaviour.
27 * <p>
28 * This class is used to create a <code>Set</code> with the same properties as
29 * the key set of any map. Thus, a ReferenceSet can be created by wrapping a
30 * <code>ReferenceMap</code> in an instance of this class.
31 * <p>
32 * Most map implementation can be used to create a set by passing in dummy values.
33 * Exceptions include <code>BidiMap</code> implementations, as they require unique values.
34 *
35 * @since 3.1
36 * @version $Id: MapBackedSet.java 1429905 2013-01-07 17:15:14Z ggregory $
37 */
38 public final class MapBackedSet<E, V> implements Set<E>, Serializable {
39
40 /** Serialization version */
41 private static final long serialVersionUID = 6723912213766056587L;
42
43 /** The map being used as the backing store */
44 protected final Map<E, ? super V> map;
45
46 /** The dummyValue to use */
47 protected final V dummyValue;
48
49 /**
50 * Factory method to create a set from a map.
51 *
52 * @param <E> the element type
53 * @param <V> the dummy value type in the map
54 * @param map the map to decorate, must not be null
55 * @return a new map backed set
56 * @throws IllegalArgumentException if set is null
57 */
58 public static <E, V> MapBackedSet<E, V> mapBackedSet(final Map<E, ? super V> map) {
59 return mapBackedSet(map, null);
60 }
61
62 /**
63 * Factory method to create a set from a map.
64 *
65 * @param <E> the element type
66 * @param <V> the dummy value type in the map
67 * @param map the map to decorate, must not be null
68 * @param dummyValue the dummy value to use
69 * @return a new map backed set
70 * @throws IllegalArgumentException if map is null
71 */
72 public static <E, V> MapBackedSet<E, V> mapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
73 if (map == null) {
74 throw new IllegalArgumentException("The map must not be null");
75 }
76 return new MapBackedSet<E, V>(map, dummyValue);
77 }
78
79 //-----------------------------------------------------------------------
80 /**
81 * Constructor that wraps (not copies).
82 *
83 * @param map the map to decorate, must not be null
84 * @param dummyValue the dummy value to use
85 * @throws IllegalArgumentException if map is null
86 */
87 private MapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
88 super();
89 this.map = map;
90 this.dummyValue = dummyValue;
91 }
92
93 //-----------------------------------------------------------------------
94 public int size() {
95 return map.size();
96 }
97
98 public boolean isEmpty() {
99 return map.isEmpty();
100 }
101
102 public Iterator<E> iterator() {
103 return map.keySet().iterator();
104 }
105
106 public boolean contains(final Object obj) {
107 return map.containsKey(obj);
108 }
109
110 public boolean containsAll(final Collection<?> coll) {
111 return map.keySet().containsAll(coll);
112 }
113
114 public boolean add(final E obj) {
115 final int size = map.size();
116 map.put(obj, dummyValue);
117 return map.size() != size;
118 }
119
120 public boolean addAll(final Collection<? extends E> coll) {
121 final int size = map.size();
122 for (final E e : coll) {
123 map.put(e, dummyValue);
124 }
125 return map.size() != size;
126 }
127
128 public boolean remove(final Object obj) {
129 final int size = map.size();
130 map.remove(obj);
131 return map.size() != size;
132 }
133
134 public boolean removeAll(final Collection<?> coll) {
135 return map.keySet().removeAll(coll);
136 }
137
138 public boolean retainAll(final Collection<?> coll) {
139 return map.keySet().retainAll(coll);
140 }
141
142 public void clear() {
143 map.clear();
144 }
145
146 public Object[] toArray() {
147 return map.keySet().toArray();
148 }
149
150 public <T> T[] toArray(final T[] array) {
151 return map.keySet().toArray(array);
152 }
153
154 @Override
155 public boolean equals(final Object obj) {
156 return map.keySet().equals(obj);
157 }
158
159 @Override
160 public int hashCode() {
161 return map.keySet().hashCode();
162 }
163
164 }