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.collections4.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.Objects;
24 import java.util.Set;
25 import java.util.function.Predicate;
26
27 /**
28 * Decorates a {@code Map} to obtain {@code Set} behavior.
29 * <p>
30 * This class is used to create a {@code Set} with the same properties as
31 * the key set of any map. Thus, a ReferenceSet can be created by wrapping a
32 * {@code ReferenceMap} in an instance of this class.
33 * </p>
34 * <p>
35 * Most map implementation can be used to create a set by passing in dummy values.
36 * Exceptions include {@code BidiMap} implementations, as they require unique values.
37 * </p>
38 *
39 * @param <E> the type of the elements in this set
40 * @param <V> the dummy value type in this map
41 * @since 3.1
42 */
43 public final class MapBackedSet<E, V> implements Set<E>, Serializable {
44
45 /** Serialization version */
46 private static final long serialVersionUID = 6723912213766056587L;
47
48 /**
49 * Factory method to create a set from a map.
50 *
51 * @param <E> the element type
52 * @param <V> the dummy value type in the map
53 * @param map the map to decorate, must not be null
54 * @return a new map backed set
55 * @throws NullPointerException if map is null
56 * @since 4.0
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 NullPointerException if map is null
71 * @since 4.0
72 */
73 public static <E, V> MapBackedSet<E, V> mapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
74 return new MapBackedSet<>(map, dummyValue);
75 }
76
77 /** The map being used as the backing store */
78 private final Map<E, ? super V> map;
79
80 /** The dummyValue to use */
81 private final V dummyValue;
82
83 /**
84 * Constructor that wraps (not copies).
85 *
86 * @param map the map to decorate, must not be null
87 * @param dummyValue the dummy value to use
88 * @throws NullPointerException if map is null
89 */
90 private MapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
91 this.map = Objects.requireNonNull(map, "map");
92 this.dummyValue = dummyValue;
93 }
94
95 @Override
96 public boolean add(final E obj) {
97 final int size = map.size();
98 map.put(obj, dummyValue);
99 return map.size() != size;
100 }
101
102 @Override
103 public boolean addAll(final Collection<? extends E> coll) {
104 final int size = map.size();
105 for (final E e : coll) {
106 map.put(e, dummyValue);
107 }
108 return map.size() != size;
109 }
110
111 @Override
112 public void clear() {
113 map.clear();
114 }
115
116 @Override
117 public boolean contains(final Object obj) {
118 return map.containsKey(obj);
119 }
120
121 @Override
122 public boolean containsAll(final Collection<?> coll) {
123 return map.keySet().containsAll(coll);
124 }
125
126 @Override
127 public boolean equals(final Object obj) {
128 return map.keySet().equals(obj);
129 }
130
131 @Override
132 public int hashCode() {
133 return map.keySet().hashCode();
134 }
135
136 @Override
137 public boolean isEmpty() {
138 return map.isEmpty();
139 }
140
141 @Override
142 public Iterator<E> iterator() {
143 return map.keySet().iterator();
144 }
145
146 @Override
147 public boolean remove(final Object obj) {
148 final int size = map.size();
149 map.remove(obj);
150 return map.size() != size;
151 }
152
153 @Override
154 public boolean removeAll(final Collection<?> coll) {
155 return map.keySet().removeAll(coll);
156 }
157
158 /**
159 * @since 4.4
160 */
161 @Override
162 public boolean removeIf(final Predicate<? super E> filter) {
163 return map.keySet().removeIf(filter);
164 }
165
166 @Override
167 public boolean retainAll(final Collection<?> coll) {
168 return map.keySet().retainAll(coll);
169 }
170
171 @Override
172 public int size() {
173 return map.size();
174 }
175
176 @Override
177 public Object[] toArray() {
178 return map.keySet().toArray();
179 }
180
181 @Override
182 public <T> T[] toArray(final T[] array) {
183 return map.keySet().toArray(array);
184 }
185
186 }