TwoPhaseSet implements CrdtAddRemoveSet<ElementType, Set<ElementType>, TwoPhaseSet<ElementType>> { public TwoPhaseSet<ElementType> remove(ElementType e){ if (removed.contains(e) || !added.contains(e)){ return this; } Set<ElementType> eSet = new HashSet<>(Collections.singletonList(e)); return this.merge(new TwoPhaseSet<>(eSet, eSet)); } TwoPhaseSet(); @SafeVarargs  TwoPhaseSet(ElementType... elements);  TwoPhaseSet(Set<ElementType> set);  TwoPhaseSet(TwoPhaseSet<ElementType> first, TwoPhaseSet<ElementType> second);   TwoPhaseSet(Set<ElementType> added, Set<ElementType> removed); TwoPhaseSet<ElementType> add(ElementType e); TwoPhaseSet<ElementType> remove(ElementType e); @Override TwoPhaseSet<ElementType> merge(TwoPhaseSet<ElementType> other); @Override Set<ElementType> value(); @Override TwoPhaseSet<ElementType> optimize(); @Override boolean equals(Object obj);  }
@Test public void immutabilityTest(){ TwoPhaseSet<String> set = new TwoPhaseSet<>(sampleSet); TwoPhaseSet<String> newSet = set.remove("b"); Assert.assertNotEquals(set, newSet); Assert.assertEquals(set, new TwoPhaseSet<>(sampleSet)); }