/* * Copyright 2014 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.concurrent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.set.MutableSet; import com.gs.collections.impl.CollidingInt; import com.gs.collections.impl.block.factory.Procedures; import com.gs.collections.impl.factory.Lists; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.set.mutable.MultiReaderUnifiedSet; import com.gs.collections.impl.test.SerializeTestHelper; import com.gs.collections.impl.test.Verify; import org.junit.Assert; import org.junit.Test; public class MultiReaderUnifiedSetAcceptanceTest { @Test public void testUnifiedSet() { MultiReaderUnifiedSet<Integer> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { Assert.assertTrue(set.add(i)); } Verify.assertSize(size, set); for (int i = 0; i < size; i++) { Verify.assertContains(i, set); } for (int i = 0; i < size; i += 2) { Assert.assertTrue(set.remove(i)); } Verify.assertSize(size / 2, set); for (int i = 1; i < size; i += 2) { Verify.assertContains(i, set); } } @Test public void testUnifiedSetClear() { assertUnifiedSetClear(0); assertUnifiedSetClear(1); assertUnifiedSetClear(2); assertUnifiedSetClear(3); } private static void assertUnifiedSetClear(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { Assert.assertTrue(set.add(new CollidingInt(i, shift))); } set.clear(); Verify.assertEmpty(set); for (int i = 0; i < size; i++) { Verify.assertNotContains(new CollidingInt(i, shift), set); } } @Test public void testUnifiedSetForEach() { assertUnifiedSetForEach(0); assertUnifiedSetForEach(1); assertUnifiedSetForEach(2); assertUnifiedSetForEach(3); } private static void assertUnifiedSetForEach(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { Assert.assertTrue(set.add(new CollidingInt(i, shift))); } MutableList<CollidingInt> keys = FastList.newList(size); set.forEach(Procedures.cast(keys::add)); Verify.assertSize(size, keys); Collections.sort(keys); for (int i = 0; i < size; i++) { Verify.assertItemAtIndex(new CollidingInt(i, shift), i, keys); } } @Test public void testUnifiedSetForEachWith() { assertUnifiedSetForEachWith(0); assertUnifiedSetForEachWith(1); assertUnifiedSetForEachWith(2); assertUnifiedSetForEachWith(3); } private static void assertUnifiedSetForEachWith(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { Assert.assertTrue(set.add(new CollidingInt(i, shift))); } MutableList<CollidingInt> keys = FastList.newList(size); set.forEachWith((key, s) -> { Assert.assertEquals("foo", s); keys.add(key); }, "foo"); Verify.assertSize(size, keys); Collections.sort(keys); for (int i = 0; i < size; i++) { Verify.assertItemAtIndex(new CollidingInt(i, shift), i, keys); } } @Test public void testUnifiedSetForEachWithIndex() { assertUnifiedSetForEachWithIndex(0); assertUnifiedSetForEachWithIndex(1); assertUnifiedSetForEachWithIndex(2); assertUnifiedSetForEachWithIndex(3); } private static void assertUnifiedSetForEachWithIndex(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { Assert.assertTrue(set.add(new CollidingInt(i, shift))); } MutableList<CollidingInt> keys = FastList.newList(size); int[] prevIndex = new int[1]; set.forEachWithIndex((key, index) -> { Assert.assertEquals(prevIndex[0], index); prevIndex[0]++; keys.add(key); }); Verify.assertSize(size, keys); Collections.sort(keys); for (int i = 0; i < size; i++) { Verify.assertItemAtIndex(new CollidingInt(i, shift), i, keys); } } @Test public void testUnifiedSetAddAll() { assertUnifiedSetAddAll(0); assertUnifiedSetAddAll(1); assertUnifiedSetAddAll(2); assertUnifiedSetAddAll(3); } private static void assertUnifiedSetAddAll(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } MultiReaderUnifiedSet<CollidingInt> newSet = MultiReaderUnifiedSet.newSet(size); newSet.addAll(set); Verify.assertSize(size, newSet); for (int i = 0; i < size; i++) { Verify.assertContains(new CollidingInt(i, shift), newSet); } } @Test public void testUnifiedSetAddAllWithHashSet() { assertUnifiedSetAddAllWithHashSet(0); assertUnifiedSetAddAllWithHashSet(1); assertUnifiedSetAddAllWithHashSet(2); assertUnifiedSetAddAllWithHashSet(3); } private static void assertUnifiedSetAddAllWithHashSet(int shift) { Set<CollidingInt> set = new HashSet<>(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } MultiReaderUnifiedSet<CollidingInt> newSet = MultiReaderUnifiedSet.newSet(size); newSet.addAll(set); Verify.assertSize(size, newSet); for (int i = 0; i < size; i++) { Verify.assertContains(new CollidingInt(i, shift), newSet); } MultiReaderUnifiedSet<CollidingInt> newSet2 = MultiReaderUnifiedSet.newSet(); newSet2.addAll(set); Verify.assertSize(size, newSet2); for (int i = 0; i < size; i++) { Verify.assertContains(new CollidingInt(i, shift), newSet2); } } @Test public void testUnifiedSetReplace() { assertUnifiedSetReplace(0); assertUnifiedSetReplace(1); assertUnifiedSetReplace(2); assertUnifiedSetReplace(3); } private static void assertUnifiedSetReplace(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } Verify.assertSize(size, set); for (int i = 0; i < size; i++) { Verify.assertContains(new CollidingInt(i, shift), set); } } @Test public void testUnifiedSetRetainAllFromList() { runUnifiedSetRetainAllFromList(0); runUnifiedSetRetainAllFromList(1); runUnifiedSetRetainAllFromList(2); runUnifiedSetRetainAllFromList(3); } private static void runUnifiedSetRetainAllFromList(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); MutableList<CollidingInt> toRetain = Lists.mutable.of(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); if (i % 2 == 0) { toRetain.add(new CollidingInt(i, shift)); } } Verify.assertSize(size, set); Assert.assertTrue(set.containsAll(toRetain)); Assert.assertTrue(set.retainAll(toRetain)); Assert.assertTrue(set.containsAll(toRetain)); Assert.assertFalse(set.retainAll(toRetain)); // a second call should not modify the set Verify.assertSize(size / 2, set); for (int i = 0; i < size; i += 2) { Verify.assertContains(new CollidingInt(i, shift), set); } } @Test public void testUnifiedSetRetainAllFromSet() { runUnifiedSetRetainAllFromSet(0); runUnifiedSetRetainAllFromSet(1); runUnifiedSetRetainAllFromSet(2); runUnifiedSetRetainAllFromSet(3); } private static void runUnifiedSetRetainAllFromSet(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); Set<CollidingInt> toRetain = new HashSet<>(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); if (i % 2 == 0) { toRetain.add(new CollidingInt(i, shift)); } } Verify.assertSize(size, set); Assert.assertTrue(set.containsAll(toRetain)); Assert.assertTrue(set.retainAll(toRetain)); Assert.assertTrue(set.containsAll(toRetain)); Assert.assertFalse(set.retainAll(toRetain)); // a second call should not modify the set Verify.assertSize(size / 2, set); for (int i = 0; i < size; i += 2) { Verify.assertContains(new CollidingInt(i, shift), set); } } @Test public void testUnifiedSetToArray() { runUnifiedSetToArray(0); runUnifiedSetToArray(1); runUnifiedSetToArray(2); runUnifiedSetToArray(3); } private static void runUnifiedSetToArray(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } Verify.assertSize(size, set); Object[] keys = set.toArray(); Assert.assertEquals(size, keys.length); Arrays.sort(keys); for (int i = 0; i < size; i++) { Verify.assertItemAtIndex(new CollidingInt(i, shift), i, keys); } } @Test public void testUnifiedSetSerialize() { runUnifiedSetSerialize(0); runUnifiedSetSerialize(1); runUnifiedSetSerialize(2); runUnifiedSetSerialize(3); } private static void runUnifiedSetSerialize(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); } set.add(null); set = SerializeTestHelper.serializeDeserialize(set); Verify.assertSize(size + 1, set); for (int i = 0; i < size; i++) { Verify.assertContains(new CollidingInt(i, shift), set); } Verify.assertContains(null, set); } @Test public void testUnifiedSetKeySetToArrayDest() { MutableSet<Integer> set = MultiReaderUnifiedSet.newSetWith(1, 2, 3, 4); // deliberately to small to force the method to allocate one of the correct size Integer[] dest = new Integer[2]; Integer[] result = set.toArray(dest); Verify.assertSize(4, result); Arrays.sort(result); Assert.assertArrayEquals(new Integer[]{1, 2, 3, 4}, result); } @Test public void testUnifiedSetEqualsAndHashCode() { assertUnifiedSetEqualsAndHashCode(0); assertUnifiedSetEqualsAndHashCode(1); assertUnifiedSetEqualsAndHashCode(2); assertUnifiedSetEqualsAndHashCode(3); } private static void assertUnifiedSetEqualsAndHashCode(int shift) { MutableSet<CollidingInt> set1 = MultiReaderUnifiedSet.newSet(); Set<CollidingInt> set2 = new HashSet<>(); MutableSet<CollidingInt> set3 = MultiReaderUnifiedSet.newSet(); MutableSet<CollidingInt> set4 = MultiReaderUnifiedSet.newSet(); int size = 100000; for (int i = 0; i < size; i++) { set1.add(new CollidingInt(i, shift)); set2.add(new CollidingInt(i, shift)); set3.add(new CollidingInt(i, shift)); set4.add(new CollidingInt(size - i - 1, shift)); } Assert.assertEquals(set1, set2); Assert.assertEquals(set1.hashCode(), set2.hashCode()); Verify.assertSetsEqual(set1, set3); Verify.assertEqualsAndHashCode(set1, set3); Verify.assertSetsEqual(set2, set4); Assert.assertEquals(set4, set2); Assert.assertEquals(set2.hashCode(), set4.hashCode()); } @Test public void testUnifiedSetRemoveAll() { runUnifiedSetRemoveAll(0); runUnifiedSetRemoveAll(1); runUnifiedSetRemoveAll(2); runUnifiedSetRemoveAll(3); } private static void runUnifiedSetRemoveAll(int shift) { MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet(); List<CollidingInt> toRemove = new ArrayList<>(); int size = 100000; for (int i = 0; i < size; i++) { set.add(new CollidingInt(i, shift)); if (i % 2 == 0) { toRemove.add(new CollidingInt(i, shift)); } } Verify.assertSize(size, set); Assert.assertTrue(set.removeAll(toRemove)); Assert.assertFalse(set.removeAll(toRemove)); // a second call should not modify the set Verify.assertSize(size / 2, set); for (int i = 1; i < size; i += 2) { Verify.assertContains(new CollidingInt(i, shift), set); } } @Test public void testUnifiedSetPutDoesNotReplace() { this.assertUnifiedSetPutDoesNotReplace(0); this.assertUnifiedSetPutDoesNotReplace(1); this.assertUnifiedSetPutDoesNotReplace(2); this.assertUnifiedSetPutDoesNotReplace(3); this.assertUnifiedSetPutDoesNotReplace(4); } private void assertUnifiedSetPutDoesNotReplace(int shift) { MultiReaderUnifiedSet<CollidingIntWithFlag> set = MultiReaderUnifiedSet.newSet(); for (int i = 0; i < 1000; i++) { Assert.assertTrue(set.add(new CollidingIntWithFlag(i, shift, false))); } Assert.assertEquals(1000, set.size()); for (int i = 0; i < 1000; i++) { Assert.assertFalse(set.add(new CollidingIntWithFlag(i, shift, true))); } Assert.assertEquals(1000, set.size()); set.withReadLockAndDelegate(delegate -> { for (CollidingIntWithFlag ciwf : delegate) { Assert.assertFalse(ciwf.isFlag()); } }); } private static final class CollidingIntWithFlag extends CollidingInt { private static final long serialVersionUID = 1L; private final boolean flag; private CollidingIntWithFlag(int value, int shift, boolean flag) { super(value, shift); this.flag = flag; } public boolean isFlag() { return this.flag; } } }