1 /* 2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser. 3 * Copyright (C) 2011, 2013-2016 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 */ VisitorSet(GenericVisitor<Integer, Void> hashcodeVisitor, GenericVisitor<Boolean, Visitable> equalsVisitor)48 public VisitorSet(GenericVisitor<Integer, Void> hashcodeVisitor, GenericVisitor<Boolean, Visitable> equalsVisitor) { 49 this.hashcodeVisitor = hashcodeVisitor; 50 this.equalsVisitor = equalsVisitor; 51 } 52 53 @Override add(N elem)54 public boolean add(N elem) { 55 return innerSet.add(new EqualsHashcodeOverridingFacade(elem)); 56 } 57 58 @Override addAll(Collection<? extends N> col)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 clear()68 public void clear() { 69 innerSet.clear(); 70 } 71 72 @Override contains(Object elem)73 public boolean contains(Object elem) { 74 return innerSet.contains(new EqualsHashcodeOverridingFacade((N) elem)); 75 } 76 77 @Override containsAll(Collection<?> col)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 isEmpty()86 public boolean isEmpty() { 87 return innerSet.isEmpty(); 88 } 89 90 @Override iterator()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 remove(Object elem)113 public boolean remove(Object elem) { 114 return innerSet.remove(new EqualsHashcodeOverridingFacade((N) elem)); 115 } 116 117 @Override removeAll(Collection<?> col)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 retainAll(Collection<?> col)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 size()135 public int size() { 136 return innerSet.size(); 137 } 138 139 @Override toArray()140 public Object[] toArray() { 141 return innerSet.stream().map(facade -> facade.overridden).collect(Collectors.toList()).toArray(); 142 } 143 144 @Override toArray(T[] arr)145 public <T> T[] toArray(T[] arr) { 146 return innerSet.stream().map(facade -> facade.overridden).collect(Collectors.toList()).toArray(arr); 147 } 148 149 @Override toString()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 EqualsHashcodeOverridingFacade(N overridden)163 EqualsHashcodeOverridingFacade(N overridden) { 164 this.overridden = overridden; 165 } 166 167 @Override accept(GenericVisitor<R, A> v, A arg)168 public <R, A> R accept(GenericVisitor<R, A> v, A arg) { 169 throw new AssertionError(); 170 } 171 172 @Override accept(VoidVisitor<A> v, A arg)173 public <A> void accept(VoidVisitor<A> v, A arg) { 174 throw new AssertionError(); 175 } 176 177 @Override hashCode()178 public final int hashCode() { 179 return overridden.accept(hashcodeVisitor, null); 180 } 181 182 @Override equals(final Object obj)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