package org.warp.commonutils.type; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectSet; import java.util.Objects; import java.util.Optional; public class HashBiAssociation implements BiAssociation { private final Object2ObjectOpenHashMap associations; private final Object2ObjectOpenHashMap inverseAssociations; public HashBiAssociation() { this.associations = new Object2ObjectOpenHashMap<>(); this.inverseAssociations = new Object2ObjectOpenHashMap<>(); } private HashBiAssociation(Object2ObjectOpenHashMap associations, Object2ObjectOpenHashMap inverseAssociations) { this.associations = associations; this.inverseAssociations = inverseAssociations; } @Override public Optional link(T src, U dest) { Objects.requireNonNull(src); Objects.requireNonNull(dest); var previousSrc = inverseAssociations.put(dest, src); // Return immediately if the link already exists if (Objects.equals(src, previousSrc)) { return Optional.of(dest); } // Remove the previous association if (previousSrc != null) { associations.remove(previousSrc); } var previousDest = associations.put(src, dest); // Remove the previous association if (previousDest != null) { inverseAssociations.remove(previousDest); } return Optional.ofNullable(previousDest); } @Override public boolean unlink(T src, U dest) { Objects.requireNonNull(src); Objects.requireNonNull(dest); if (!Objects.equals(dest, associations.get(src))) { return false; } associations.remove(src); inverseAssociations.remove(dest); return true; } @Override public Optional unlink(T src) { Objects.requireNonNull(src); var dest = associations.remove(src); if (dest != null) { inverseAssociations.remove(dest); } return Optional.ofNullable(dest); } @Override public Optional unlinkFromSource(U dest) { Objects.requireNonNull(dest); var src = inverseAssociations.remove(dest); if (src != null) { associations.remove(src); } return Optional.ofNullable(src); } @Override public boolean hasLink(T src) { Objects.requireNonNull(src); return associations.containsKey(src); } @Override public boolean hasLinkSource(U dest) { Objects.requireNonNull(dest); return inverseAssociations.containsKey(dest); } @Override public boolean hasLink(T src, U dest) { Objects.requireNonNull(src); Objects.requireNonNull(dest); return Objects.equals(dest, associations.get(src)); } @Override public Optional getLink(T src) { Objects.requireNonNull(src); return Optional.ofNullable(associations.get(src)); } @Override public Optional getLinkSource(U dest) { Objects.requireNonNull(dest); return Optional.ofNullable(inverseAssociations.get(dest)); } @Override public void clear() { associations.clear(); inverseAssociations.clear(); } @Override public int size() { return inverseAssociations.size(); } @Override public ObjectSet getSources() { return associations.clone().keySet(); } @Override public ObjectSet getDestinations() { return inverseAssociations.clone().keySet(); } @SuppressWarnings("MethodDoesntCallSuperMethod") @Override public HashBiAssociation clone() { return new HashBiAssociation<>(associations.clone(), inverseAssociations.clone()); } }