154 lines
3.3 KiB
Java
154 lines
3.3 KiB
Java
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<T, U> implements BiAssociation<T, U> {
|
|
|
|
private final Object2ObjectOpenHashMap<T, U> associations;
|
|
private final Object2ObjectOpenHashMap<U, T> inverseAssociations;
|
|
|
|
public HashBiAssociation() {
|
|
this.associations = new Object2ObjectOpenHashMap<>();
|
|
this.inverseAssociations = new Object2ObjectOpenHashMap<>();
|
|
}
|
|
|
|
private HashBiAssociation(Object2ObjectOpenHashMap<T, U> associations,
|
|
Object2ObjectOpenHashMap<U, T> inverseAssociations) {
|
|
this.associations = associations;
|
|
this.inverseAssociations = inverseAssociations;
|
|
}
|
|
|
|
@Override
|
|
public Optional<U> 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<U> unlink(T src) {
|
|
Objects.requireNonNull(src);
|
|
|
|
var dest = associations.remove(src);
|
|
|
|
if (dest != null) {
|
|
inverseAssociations.remove(dest);
|
|
}
|
|
|
|
return Optional.ofNullable(dest);
|
|
}
|
|
|
|
@Override
|
|
public Optional<T> 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<U> getLink(T src) {
|
|
Objects.requireNonNull(src);
|
|
|
|
return Optional.ofNullable(associations.get(src));
|
|
}
|
|
|
|
@Override
|
|
public Optional<T> 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<T> getSources() {
|
|
return associations.clone().keySet();
|
|
}
|
|
|
|
@Override
|
|
public ObjectSet<U> getDestinations() {
|
|
return inverseAssociations.clone().keySet();
|
|
}
|
|
|
|
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
|
@Override
|
|
public HashBiAssociation<T, U> clone() {
|
|
return new HashBiAssociation<>(associations.clone(), inverseAssociations.clone());
|
|
}
|
|
}
|