1 | /* |
---|---|
2 | * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser. |
3 | * Copyright (C) 2011, 2013-2020 The JavaParser Team. |
4 | * |
5 | * This file is part of JavaParser. |
6 | * |
7 | * JavaParser can be used either under the terms of |
8 | * a) the GNU Lesser General Public License as published by |
9 | * the Free Software Foundation, either version 3 of the License, or |
10 | * (at your option) any later version. |
11 | * b) the terms of the Apache License |
12 | * |
13 | * You should have received a copy of both licenses in LICENCE.LGPL and |
14 | * LICENCE.APACHE. Please refer to those files for details. |
15 | * |
16 | * JavaParser is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU Lesser General Public License for more details. |
20 | */ |
21 | |
22 | package com.github.javaparser.utils; |
23 | |
24 | import java.util.Collection; |
25 | import java.util.HashSet; |
26 | import java.util.Iterator; |
27 | import java.util.Set; |
28 | import java.util.stream.Collectors; |
29 | |
30 | import com.github.javaparser.ast.Node; |
31 | import com.github.javaparser.ast.visitor.GenericVisitor; |
32 | import com.github.javaparser.ast.visitor.Visitable; |
33 | import com.github.javaparser.ast.visitor.VoidVisitor; |
34 | |
35 | /** |
36 | * A set that overrides the equals and hashcode calculation of the added nodes |
37 | * by using another equals and hashcode visitor for those methods. |
38 | */ |
39 | public class VisitorSet<N extends Node> implements Set<N> { |
40 | |
41 | private final Set<EqualsHashcodeOverridingFacade> innerSet = new HashSet<>(); |
42 | private final GenericVisitor<Integer, Void> hashcodeVisitor; |
43 | private final GenericVisitor<Boolean, Visitable> equalsVisitor; |
44 | |
45 | /** |
46 | * Pass the visitors to use for equals and hashcode. |
47 | */ |
48 | public VisitorSet(GenericVisitor<Integer, Void> hashcodeVisitor, GenericVisitor<Boolean, Visitable> equalsVisitor) { |
49 | this.hashcodeVisitor = hashcodeVisitor; |
50 | this.equalsVisitor = equalsVisitor; |
51 | } |
52 | |
53 | @Override |
54 | public boolean add(N elem) { |
55 | return innerSet.add(new EqualsHashcodeOverridingFacade(elem)); |
56 | } |
57 | |
58 | @Override |
59 | public boolean addAll(Collection<? extends N> col) { |
60 | boolean modified = false; |
61 | for (N elem : col) |
62 | if (add(elem)) |
63 | modified = true; |
64 | return modified; |
65 | } |
66 | |
67 | @Override |
68 | public void clear() { |
69 | innerSet.clear(); |
70 | } |
71 | |
72 | @Override |
73 | public boolean contains(Object elem) { |
74 | return innerSet.contains(new EqualsHashcodeOverridingFacade((N) elem)); |
75 | } |
76 | |
77 | @Override |
78 | public boolean containsAll(Collection<?> col) { |
79 | for (Object elem : col) |
80 | if (!contains(elem)) |
81 | return false; |
82 | return true; |
83 | } |
84 | |
85 | @Override |
86 | public boolean isEmpty() { |
87 | return innerSet.isEmpty(); |
88 | } |
89 | |
90 | @Override |
91 | public Iterator<N> iterator() { |
92 | return new Iterator<N>() { |
93 | final Iterator<EqualsHashcodeOverridingFacade> itr = innerSet.iterator(); |
94 | |
95 | @Override |
96 | public boolean hasNext() { |
97 | return itr.hasNext(); |
98 | } |
99 | |
100 | @Override |
101 | public N next() { |
102 | return itr.next().overridden; |
103 | } |
104 | |
105 | @Override |
106 | public void remove() { |
107 | itr.remove(); |
108 | } |
109 | }; |
110 | } |
111 | |
112 | @Override |
113 | public boolean remove(Object elem) { |
114 | return innerSet.remove(new EqualsHashcodeOverridingFacade((N) elem)); |
115 | } |
116 | |
117 | @Override |
118 | public boolean removeAll(Collection<?> col) { |
119 | boolean modified = false; |
120 | for (Object elem : col) |
121 | if (remove(elem)) |
122 | modified = true; |
123 | return modified; |
124 | } |
125 | |
126 | @Override |
127 | public boolean retainAll(Collection<?> col) { |
128 | int oldSize = size(); |
129 | clear(); |
130 | addAll((Collection<? extends N>) col); |
131 | return size() != oldSize; |
132 | } |
133 | |
134 | @Override |
135 | public int size() { |
136 | return innerSet.size(); |
137 | } |
138 | |
139 | @Override |
140 | public Object[] toArray() { |
141 | return innerSet.stream().map(facade -> facade.overridden).collect(Collectors.toList()).toArray(); |
142 | } |
143 | |
144 | @Override |
145 | public <T> T[] toArray(T[] arr) { |
146 | return innerSet.stream().map(facade -> facade.overridden).collect(Collectors.toList()).toArray(arr); |
147 | } |
148 | |
149 | @Override |
150 | public String toString() { |
151 | StringBuilder sb = new StringBuilder("["); |
152 | if (size() == 0) |
153 | return sb.append("]").toString(); |
154 | for (EqualsHashcodeOverridingFacade facade : innerSet) { |
155 | sb.append(facade.overridden.toString() + ","); |
156 | } |
157 | return sb.replace(sb.length() - 2, sb.length(), "]").toString(); |
158 | } |
159 | |
160 | private class EqualsHashcodeOverridingFacade implements Visitable { |
161 | private final N overridden; |
162 | |
163 | EqualsHashcodeOverridingFacade(N overridden) { |
164 | this.overridden = overridden; |
165 | } |
166 | |
167 | @Override |
168 | public <R, A> R accept(GenericVisitor<R, A> v, A arg) { |
169 | throw new AssertionError(); |
170 | } |
171 | |
172 | @Override |
173 | public <A> void accept(VoidVisitor<A> v, A arg) { |
174 | throw new AssertionError(); |
175 | } |
176 | |
177 | @Override |
178 | public final int hashCode() { |
179 | return overridden.accept(hashcodeVisitor, null); |
180 | } |
181 | |
182 | @Override |
183 | public boolean equals(final Object obj) { |
184 | if (obj == null || !(obj instanceof VisitorSet.EqualsHashcodeOverridingFacade)) { |
185 | return false; |
186 | } |
187 | return overridden.accept(equalsVisitor, ((EqualsHashcodeOverridingFacade) obj).overridden); |
188 | } |
189 | } |
190 | |
191 | } |
192 |
Members