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);
    }
  }
  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);
  }
  private static void runUnifiedSetRetainAllFromSet(int shift) {
    MultiReaderUnifiedSet<CollidingInt> set = MultiReaderUnifiedSet.newSet();

    Set<CollidingInt> toRetain = new HashSet<CollidingInt>();

    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);
    }
  }
  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 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);
    }
  }
  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);
    }
  }
  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 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);
    }
  }
  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);
    }
  }