diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/utils/WeakHashSetTest.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/utils/WeakHashSetTest.java new file mode 100644 index 00000000000..28de991cb08 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/utils/WeakHashSetTest.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2012, 2012 Andrew Gvozdev and others. + * 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.utils; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.internal.core.WeakHashSet; +import org.eclipse.cdt.internal.core.WeakHashSetSynchronized; + +/** + * Test suite to test {@link WeakHashSet}. + */ +public class WeakHashSetTest extends TestCase { + /** + * Sample mock class with specialized hashCode() + */ + private class MockClass { + private String str; + private MockClass(String str) { + super(); + this.str = str; + } + @Override + public int hashCode() { + // for test purpose make hashcodes equal for all "str" stating with the same letter + // note that "equals()" still reports difference + String s = str.substring(0,1); + return s.hashCode(); + } + @Override + public boolean equals(Object obj) { + MockClass other = (MockClass) obj; + return str.equals(other.str); + } + } + + public static Test suite() { + return new TestSuite(WeakHashSetTest.class); + } + + /** + * Test basic methods of {@link WeakHashSet}. + */ + public void testHashSetBasic() { + // create sample objects + WeakHashSet weakSet = new WeakHashSet(); + MockClass a1 = new MockClass("a"); + MockClass a2 = new MockClass("a"); + + // check contains() + assertEquals(false, weakSet.contains(a1)); + assertEquals(null, weakSet.get(a1)); + // check add() and get() + assertSame(a1, weakSet.add(a1)); + assertSame(a1, weakSet.add(a2)); + assertSame(a1, weakSet.get(a1)); + assertSame(a1, weakSet.get(a2)); + assertEquals(true, weakSet.contains(a1)); + assertEquals(true, weakSet.contains(a2)); + // check remove() + MockClass aOld = weakSet.remove(a2); + assertSame(a1, aOld); + assertEquals(null, weakSet.get(a1)); + assertSame(a2, weakSet.add(a2)); + assertSame(a2, weakSet.add(a1)); + + // create sample objects with the same hashcode + MockClass aa = new MockClass("aa"); + MockClass ab = new MockClass("ab"); + assertEquals(aa.hashCode(), ab.hashCode()); + assertEquals(false, aa.equals(ab)); + // check add() and get() + assertEquals(false, weakSet.contains(aa)); + assertEquals(false, weakSet.contains(ab)); + assertEquals(null, weakSet.get(aa)); + assertEquals(null, weakSet.get(ab)); + assertSame(aa, weakSet.add(aa)); + assertSame(ab, weakSet.add(ab)); + assertEquals(true, weakSet.contains(aa)); + assertEquals(true, weakSet.contains(ab)); + assertSame(aa, weakSet.get(aa)); + assertSame(ab, weakSet.get(ab)); + } + + /** + * Test synchronized {@link WeakHashSetSynchronized}. + * Note that regular {@link WeakHashSet} would fail the test. + */ + public void testHashSetSyncronization() throws Exception { + final WeakHashSet weakSet = new WeakHashSetSynchronized(1); + + Thread[] threads= new Thread[5000]; + for (int i = 0; i < threads.length; i++) { + final Integer n = i; + Thread t= new Thread() { + @Override + public void run() { + weakSet.add(n); + } + }; + threads[i] = t; + t.start(); + } + + for (int i = 0; i < threads.length; i++) { + threads[i].join(); + } + assertEquals(threads.length, weakSet.size()); + + for (int i = 0; i < threads.length; i++) { + assertEquals(true, weakSet.contains(i)); + } + } +} diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java index c40a37e2dc0..e56c264c818 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/suite/AutomatedIntegrationSuite.java @@ -4,7 +4,7 @@ * 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 * Markus Schorn (Wind River Systems) @@ -35,6 +35,7 @@ import org.eclipse.cdt.internal.pdom.tests.PDOMTests; import org.eclipse.cdt.utils.CdtVariableResolverTest; import org.eclipse.cdt.utils.CommandLineUtilTest; import org.eclipse.cdt.utils.FindProgramLocationTest; +import org.eclipse.cdt.utils.WeakHashSetTest; /** * @author vhirsl @@ -75,13 +76,14 @@ public class AutomatedIntegrationSuite extends TestSuite { suite.addTest(RewriteTests.suite()); suite.addTest(CdtVariableResolverTest.suite()); suite.addTest(CommandLineUtilTest.suite()); + suite.addTest(WeakHashSetTest.suite()); suite.addTest(FindProgramLocationTest.suite()); suite.addTest(EFSExtensionTests.suite()); // Add in PDOM tests suite.addTest(PDOMTests.suite()); suite.addTest(IndexTests.suite()); - + suite.addTest(RefreshScopeTests.suite()); return suite; diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsStorage.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsStorage.java index caebe3745a7..33db176254d 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsStorage.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsStorage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2011 Andrew Gvozdev and others. + * Copyright (c) 2011, 2012 Andrew Gvozdev and others. * 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 @@ -22,6 +22,7 @@ import java.util.Set; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.internal.core.WeakHashSet; +import org.eclipse.cdt.internal.core.WeakHashSetSynchronized; /** * The class representing the (in-memory) storage for language settings entries {@link ICLanguageSettingEntry}. @@ -39,12 +40,7 @@ public class LanguageSettingsStorage implements Cloneable { * at the expense of CPU time. WeakHashSet handles garbage collection when a list is not * referenced anywhere else. See JavaDoc {@link java.lang.ref.WeakReference} about weak reference objects. */ - private static WeakHashSet> listPool = new WeakHashSet>() { - @Override - public synchronized List add(List list) { - return super.add(list); - } - }; + private static WeakHashSet> listPool = new WeakHashSetSynchronized>(); /** * Returns the list of setting entries for the given resource and language. diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/CDataUtil.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/CDataUtil.java index 4af7af794c2..6103750e7e4 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/CDataUtil.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/settings/model/util/CDataUtil.java @@ -58,6 +58,7 @@ import org.eclipse.cdt.core.settings.model.extension.CTargetPlatformData; import org.eclipse.cdt.core.settings.model.extension.impl.CDataFactory; import org.eclipse.cdt.core.settings.model.extension.impl.CDefaultLanguageData; import org.eclipse.cdt.internal.core.WeakHashSet; +import org.eclipse.cdt.internal.core.WeakHashSetSynchronized; import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; @@ -82,12 +83,7 @@ public class CDataUtil { * at the expense of CPU time. WeakHashSet handles garbage collection when a list is not * referenced anywhere else. See JavaDoc {@link java.lang.ref.WeakReference} about weak reference objects. */ - private static WeakHashSet settingEntriesPool = new WeakHashSet() { - @Override - public synchronized ICSettingEntry add(ICSettingEntry entry) { - return super.add(entry); - } - }; + private static WeakHashSet settingEntriesPool = new WeakHashSetSynchronized(); public static int genRandomNumber(){ if (randomNumber == null) { diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/WeakHashSetSynchronized.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/WeakHashSetSynchronized.java new file mode 100644 index 00000000000..c687c4a8c82 --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/WeakHashSetSynchronized.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012 Andrew Gvozdev and others. + * 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core; + +/** + * A synchronized hashset whose values can be garbage collected. + */ +public class WeakHashSetSynchronized extends WeakHashSet { + /** + * Constructor. + */ + public WeakHashSetSynchronized() { + super(5); + } + + /** + * Constructor. + * + * @param size - initial capacity. + */ + public WeakHashSetSynchronized(int size) { + super(size); + } + + @Override + synchronized public T add(T obj) { + return super.add(obj); + } + @Override + synchronized public T get(T obj) { + return super.get(obj); + } + @Override + synchronized public T remove(T obj) { + return super.remove(obj); + } +}