|  | 
|  | 1 | +package com.thealgorithms.datastructures.crdt; | 
|  | 2 | + | 
|  | 3 | +import java.util.HashSet; | 
|  | 4 | +import java.util.Set; | 
|  | 5 | + | 
|  | 6 | +/** | 
|  | 7 | + * TwoPhaseSet (2P-Set) is a state-based CRDT (Conflict-free Replicated Data Type) designed for managing sets | 
|  | 8 | + * with support for both addition and removal operations in a distributed and concurrent environment. | 
|  | 9 | + * It combines two G-Sets (grow-only sets) - one set for additions and another set (tombstone set) for removals. | 
|  | 10 | + * Once an element is removed and placed in the tombstone set, it cannot be re-added, adhering to "remove-wins" semantics. | 
|  | 11 | + * This implementation supports querying the presence of elements, adding elements, removing elements, | 
|  | 12 | + * comparing with other 2P-Sets, and merging two 2P-Sets while preserving the remove-wins semantics. | 
|  | 13 | + * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) | 
|  | 14 | + * | 
|  | 15 | + * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah) | 
|  | 16 | + */ | 
|  | 17 | + | 
|  | 18 | +public class TwoPSet { | 
|  | 19 | +    private Set<String> setA; | 
|  | 20 | +    private Set<String> setR; | 
|  | 21 | + | 
|  | 22 | +    /** | 
|  | 23 | +     * Constructs an empty Two-Phase Set. | 
|  | 24 | +     */ | 
|  | 25 | +    public TwoPSet() { | 
|  | 26 | +        this.setA = new HashSet<>(); | 
|  | 27 | +        this.setR = new HashSet<>(); | 
|  | 28 | +    } | 
|  | 29 | + | 
|  | 30 | +    /** | 
|  | 31 | +     * Checks if an element is in the set and has not been removed. | 
|  | 32 | +     * | 
|  | 33 | +     * @param element The element to be checked. | 
|  | 34 | +     * @return True if the element is in the set and has not been removed, otherwise false. | 
|  | 35 | +     */ | 
|  | 36 | +    public boolean lookup(String element) { | 
|  | 37 | +        return setA.contains(element) && !setR.contains(element); | 
|  | 38 | +    } | 
|  | 39 | + | 
|  | 40 | +    /** | 
|  | 41 | +     * Adds an element to the set. | 
|  | 42 | +     * | 
|  | 43 | +     * @param element The element to be added. | 
|  | 44 | +     */ | 
|  | 45 | +    public void add(String element) { | 
|  | 46 | +        setA.add(element); | 
|  | 47 | +    } | 
|  | 48 | + | 
|  | 49 | +    /** | 
|  | 50 | +     * Removes an element from the set. The element will be placed in the tombstone set. | 
|  | 51 | +     * | 
|  | 52 | +     * @param element The element to be removed. | 
|  | 53 | +     */ | 
|  | 54 | +    public void remove(String element) { | 
|  | 55 | +        if (lookup(element)) { | 
|  | 56 | +            setR.add(element); | 
|  | 57 | +        } | 
|  | 58 | +    } | 
|  | 59 | + | 
|  | 60 | +    /** | 
|  | 61 | +     * Compares the current 2P-Set with another 2P-Set. | 
|  | 62 | +     * | 
|  | 63 | +     * @param otherSet The other 2P-Set to compare with. | 
|  | 64 | +     * @return True if both SetA and SetR are subset, otherwise false. | 
|  | 65 | +     */ | 
|  | 66 | +    public boolean compare(TwoPSet otherSet) { | 
|  | 67 | +        return otherSet.setA.containsAll(setA) && otherSet.setR.containsAll(setR); | 
|  | 68 | +    } | 
|  | 69 | + | 
|  | 70 | +    /** | 
|  | 71 | +     * Merges the current 2P-Set with another 2P-Set. | 
|  | 72 | +     * | 
|  | 73 | +     * @param otherSet The other 2P-Set to merge with. | 
|  | 74 | +     * @return A new 2P-Set containing the merged elements. | 
|  | 75 | +     */ | 
|  | 76 | +    public TwoPSet merge(TwoPSet otherSet) { | 
|  | 77 | +        TwoPSet mergedSet = new TwoPSet(); | 
|  | 78 | +        mergedSet.setA.addAll(this.setA); | 
|  | 79 | +        mergedSet.setA.addAll(otherSet.setA); | 
|  | 80 | +        mergedSet.setR.addAll(this.setR); | 
|  | 81 | +        mergedSet.setR.addAll(otherSet.setR); | 
|  | 82 | +        return mergedSet; | 
|  | 83 | +    } | 
|  | 84 | +} | 
0 commit comments