package dk.brics.jsrefactoring; /** * Lift is the algebraic datatype: * <pre> * Lift a = Bottom * | Top * | Actual a * </pre> * It can also be seen as the lattice: * <pre> * TOP (the top value) * / | \ * ..v1 v2 v3... (<i>actual</i> values) * \ | / * BOTTOM (the bottom value) * </pre> * where v<sub>i</sub> are all the values of the type parameter <tt>T</tt>. * <p/> * When comparing for instance equality, keep in mind that there exists exactly * one instance of TOP and one instance of BOTTOM. * <p/> * For the <i>actual</i> values, <tt>hashCode</tt> and <tt>equals</tt> are propagated to the * underlying instances of <tt>T</tt>. */ @SuppressWarnings({"unchecked","rawtypes"}) public abstract class Lift<T> { private Lift() {} private static class Actual<T> extends Lift<T> { private T value; public Actual(T value) { this.value = value; } @Override public T getValue() { return value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Actual other = (Actual) obj; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } } /** * Returns the unique BOTTOM instance. */ public static <T> Lift<T> bottom() { return BOTTOM; } /** * Returns the unique TOP instance. */ public static <T> Lift<T> top() { return TOP; } /** * Returns a new Lift instance containing the given value. * @param <T> type of the lift instance * @param value value contained in the lift instance * @return a newly created instance */ public static <T> Lift<T> actual(T value) { return new Actual<T>(value); } public static <T> Lift<T> leastUpperBound(Lift<T> a, Lift<T> b) { if (a == BOTTOM) return b; if (b == BOTTOM) return a; if (a == TOP || b == TOP) return TOP; if (a.getValue() == b.getValue()) return a; if (a.getValue() != null && a.getValue().equals(b.getValue())) return a; return TOP; } public Lift<T> leastUpperBoundWith(Lift<T> b) { return leastUpperBound(this, b); } public boolean isTop() { return this == TOP; } public boolean isBottom() { return this == BOTTOM; } public boolean isActual() { return this instanceof Actual<?>; } /** * Returns <tt>null</tt> if this is top or bottom, * and the value passed to {@link #actual(Object) actual} otherwise. * @return <tt>null</tt> or an object */ public T getValue() { return null; } private static final Lift BOTTOM = new Lift<Object>(){}; private static final Lift TOP = new Lift<Object>(){}; }