100 lines
2.9 KiB
Java
100 lines
2.9 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.util.collections;
|
|
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.util.debug.UnimplementedError;
|
|
|
|
/**
|
|
* a debugging aid. This implementation complains if you stick an object in here which appears to use System.identityHashCode(), or
|
|
* if it detects more than BAD_HC collisions in the Set (possibly indicated a bad hash function)
|
|
*/
|
|
public class ParanoidHashSet<T> extends LinkedHashSet<T> {
|
|
public static final long serialVersionUID = 30919839181133333L;
|
|
|
|
/**
|
|
* A mapping from Integer (hashcode) -> Set of objects
|
|
*/
|
|
private final Map<Integer, Set<T>> hcFreq;
|
|
|
|
private int nAdded = 0;
|
|
|
|
/**
|
|
* If a hash set contains more than this number of items with the same hash code, complain.
|
|
*/
|
|
private final int BAD_HC = 3;
|
|
|
|
/**
|
|
* @param s
|
|
* @throws NullPointerException if s is null
|
|
*/
|
|
public ParanoidHashSet(Collection<T> s) throws NullPointerException {
|
|
super(s.size());
|
|
hcFreq = HashMapFactory.make(s.size());
|
|
for (Iterator<T> it = s.iterator(); it.hasNext();) {
|
|
add(it.next());
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public ParanoidHashSet() {
|
|
super();
|
|
hcFreq = HashMapFactory.make();
|
|
}
|
|
|
|
public ParanoidHashSet(int size) {
|
|
super(size);
|
|
hcFreq = HashMapFactory.make(size);
|
|
}
|
|
|
|
/**
|
|
* @see java.util.Collection#add(java.lang.Object)
|
|
* @throws UnimplementedError if there's a bad hash code problem
|
|
*/
|
|
@Override
|
|
public boolean add(T arg0) {
|
|
if (arg0 == null) {
|
|
throw new IllegalArgumentException("arg0 is null");
|
|
}
|
|
|
|
ParanoidHashMap.assertOverridesHashCode(arg0);
|
|
boolean result = super.add(arg0);
|
|
if (result) {
|
|
nAdded++;
|
|
int hc = arg0.hashCode();
|
|
Set<T> s = hcFreq.get(new Integer(hc));
|
|
if (s == null) {
|
|
HashSet<T> h = new LinkedHashSet<T>(1);
|
|
h.add(arg0);
|
|
hcFreq.put(new Integer(hc), h);
|
|
} else {
|
|
if (s.size() == BAD_HC) {
|
|
for (Iterator<T> it = s.iterator(); it.hasNext();) {
|
|
Object o = it.next();
|
|
System.err.println(o + " " + o.hashCode());
|
|
}
|
|
assert false : "bad hc " + arg0.getClass() + " " + arg0;
|
|
} else {
|
|
s.add(arg0);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} |