package com.sap.runlet.abstractinterpreter.objects;
import java.util.Iterator;
import com.sap.runlet.abstractinterpreter.repository.Snapshot;
/**
* Wraps an existing {@link RunletObject}, delegates all methods to the wrapped object and defines {@link #equals} and
* {@link #hashCode} based on the {@link #logicallyEquals(RunletObject) logical equality} and {@link #logicalHashCode()
* logical hash code}, respectively.
*
* @author Axel Uhl (D043530)
*/
public class LogicallyEqualsWrapper<LinkEndMetaObject, TypeUsage, ClassUsage extends TypeUsage> extends
RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> {
private final RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> wrappedObject;
public LogicallyEqualsWrapper(RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> wrappedObject) {
super(wrappedObject.getType());
this.wrappedObject = wrappedObject;
}
public int size() {
return wrappedObject.size();
}
public TypeUsage getType() {
return wrappedObject.getType();
}
public Iterator<RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage>> iterator() {
return wrappedObject.iterator();
}
/**
* Objects may be nested {@link MultiValuedObject multi-objects}, for example because
* method calls with output multiplicity <tt>n</tt> are called on a multi-object. This is
* particularly inconvenient in case a client wants to deal with elementary objects that
* are no multi-objects. This operation flattens an object to the extent that its
* {@link #iterator()} operation is guaranteed to return only objects that are not
* multi-objects.
*/
public Iterable<RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage>> flatten() {
return wrappedObject.flatten();
}
public boolean isEmpty() {
return wrappedObject.isEmpty();
}
/**
* Logical equality implements the "==" operator of the programming model which
* is defined slightly different from the Java equality of the {@link LogicallyEqualsWrapper}s
* representing them in the interpreter. In particular, there is this issue of
* the {@link Snapshot}. While in the interpreter it is essential to be able to
* distinguish otherwise equal instances if they come from different snapshots,
* for a logical equality comparison the snapshot does not matter. For example,
* if the number 42 was obtained from snapshot 7, then navigating an association
* from that copy of 42 shall navigate using snapshot 7. However, if this copy of 42
* is compared to any other copy of 42, the result should be that these are logically
* equal.<p>
*
* The default implementation used here defaults to the Java equality. Subclasses
* that know about snapshots need to distinguish, though.
*/
public boolean logicallyEquals(RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> other) {
return wrappedObject.equals(other);
}
/**
* Computes a hash code that is the same for two objects that compare equal with
* {@link #equalsWithinSameSnapshot}. By default, this is the {@link #logicalHashCode()},
* but entities should redefine this to be ID-based.
*/
public int hashCodeWithinSnapshot() {
return wrappedObject.logicalHashCode();
}
/**
* Computes a hash code that is based only on those features that also contribute to
* the definition of {@link #logicallyEquals(LogicallyEqualsWrapper)}. The default implementation
* is to use the regular hash code.
*/
public int logicalHashCode() {
return wrappedObject.hashCode();
}
/**
* Equality and hash code are mapped to logical equality and logical hash code of the wrapped
* object by this wrapper.
*/
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
return wrappedObject.logicallyEquals(
((LogicallyEqualsWrapper<LinkEndMetaObject, TypeUsage, ClassUsage>) o).getWrappedObject());
}
/**
* Equality and hash code are mapped to logical equality and logical hash code of the wrapped
* object by this wrapper.
*/
@Override
public int hashCode() {
return wrappedObject.logicalHashCode();
}
public RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> getWrappedObject() {
return wrappedObject;
}
@Override
public String toString() {
return wrappedObject.toString();
}
}