blob: 0ee12789175c15cfe983ffe9ecb61365996883d4 [file] [log] [blame]
Madan Jampani83c27832015-12-07 10:42:13 -08001/*
2 * Copyright 2015 Open Networking Laboratory
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 org.onlab.util;
17
18import java.util.Collection;
19import java.util.Iterator;
20import java.util.Map;
21import java.util.Set;
22import java.util.concurrent.atomic.AtomicBoolean;
23import java.util.function.Predicate;
24
25import com.google.common.collect.Iterators;
26import static com.google.common.base.Preconditions.checkNotNull;
27
28/**
29 * A Set providing additional get, insertOrReplace and conditionalRemove methods.
30 */
31public class ExtendedSet<E> implements Set<E> {
32
33 private final Map<E, E> map;
34
35 /**
36 * Constructs a new instance by backing it with the supplied Map.
37 * <p>
38 * Constructed ExtendedSet will have the same concurrency properties as that of the supplied Map.
39 *
40 * @param map input map.
41 */
42 public ExtendedSet(Map<E, E> map) {
43 this.map = map;
44 }
45
46 /**
47 * Returns set element that is equal to the specified object.
48 * @param o
49 * @return
50 */
51 public E get(Object o) {
52 return map.get(o);
53 }
54
55 /**
56 * Inserts the entry if it is not already in the set otherwise replaces the existing entry
57 * if the supplied predicate evaluates to true.
58 * @param entry entry to add
59 * @param entryTest predicate that is used to evaluate if the existing entry should be replaced
60 * @return true if the set is updated; false otherwise
61 */
62 public boolean insertOrReplace(E entry, Predicate<E> entryTest) {
63 AtomicBoolean updated = new AtomicBoolean(false);
64 map.compute(checkNotNull(entry), (k, v) -> {
65 if (v == null || entryTest.test(v)) {
66 updated.set(true);
67 return entry;
68 }
69 return v;
70 });
71 return updated.get();
72 }
73
74 /**
75 * Removes the entry if the supplied predicate evaluates to true.
76 * @param entry entry to remove
77 * @param entryTest predicate that is used to evaluated aginst the existing entry. Return value of
78 * true implies value should be removed.
79 * @return true if the set is updated; false otherwise
80 */
81 public boolean conditionalRemove(E entry, Predicate<E> entryTest) {
82 AtomicBoolean updated = new AtomicBoolean(false);
83 map.compute(entry, (k, v) -> {
84 if (entryTest.test(v)) {
85 updated.set(true);
86 return null;
87 }
88 return v;
89 });
90 return updated.get();
91 }
92
93 @Override
94 public int size() {
95 return map.size();
96 }
97
98 @Override
99 public boolean isEmpty() {
100 return map.isEmpty();
101 }
102
103 @Override
104 public boolean contains(Object o) {
105 return map.containsKey(o);
106 }
107
108 @Override
109 public Iterator<E> iterator() {
110 return Iterators.transform(map.entrySet().iterator(), Map.Entry::getValue);
111 }
112
113 @Override
114 public Object[] toArray() {
115 return map.values().toArray();
116 }
117
118 @Override
119 public <T> T[] toArray(T[] a) {
120 return map.values().toArray(a);
121 }
122
123 @Override
124 public boolean add(E e) {
125 return map.putIfAbsent(e, e) == null;
126 }
127
128 @Override
129 public boolean remove(Object o) {
130 return map.remove(o) != null;
131 }
132
133 @Override
134 public boolean containsAll(Collection<?> c) {
135 return c.stream()
136 .map(map::containsKey)
137 .reduce(Boolean::logicalAnd)
138 .orElse(true);
139 }
140
141 @Override
142 public boolean addAll(Collection<? extends E> c) {
143 return c.stream()
144 .map(e -> map.putIfAbsent(e, e) == null)
145 .reduce(Boolean::logicalOr)
146 .orElse(false);
147 }
148
149 @Override
150 public boolean retainAll(Collection<?> c) {
151 return c.stream()
152 .filter(e -> !map.containsKey(e))
153 .map(e -> map.remove(e) != null)
154 .reduce(Boolean::logicalOr)
155 .orElse(false);
156 }
157
158 @Override
159 public boolean removeAll(Collection<?> c) {
160 return c.stream()
161 .map(e -> map.remove(e) != null)
162 .reduce(Boolean::logicalOr)
163 .orElse(false);
164 }
165
166 @Override
167 public void clear() {
168 map.clear();
169 }
170}