package com.sap.runlet.abstractinterpreter.objects; import java.util.Iterator; import java.util.NoSuchElementException; import javax.naming.OperationNotSupportedException; import com.sap.runlet.abstractinterpreter.util.TypeService; public final class EmptyObject<LinkEndMetaObject, MetaClass, TypeUsage, ClassUsage extends TypeUsage> extends RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> { private final TypeService<TypeUsage> typeService; static final String MESSAGE = "<empty>"; /** * Reusable iterator implementation with empty behavior. */ private Iterator<RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage>> staticIterator = new Iterator<RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage>>() { @Override public boolean hasNext() { return false; } @Override public RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> next() { throw new NoSuchElementException("called next twice on a single-valued object"); } @Override public void remove() { throw new RuntimeException(new OperationNotSupportedException( "no remove on RiverObject")); } }; /** * The class service is required to check type conformance in {@link #logicallyEquals(RunletObject)}. */ public EmptyObject(TypeUsage type, TypeService<TypeUsage> typeService) { super(type); this.typeService = typeService; } public final int size() { return 0; } public Iterator<RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage>> iterator() { return staticIterator; } @Override public String toString() { return MESSAGE; } /** * An EmptyObject is always logically equals to all other EmptyObjects * with a conforming {@link TypeDefinition}. */ public boolean logicallyEquals(RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> other) { return this.size() == other.size() && typeService.aConformsToB(this.getType(), other.getType()); } /** * Computes a hash code that is based only on those features that also contribute to * the definition of {@link #logicallyEquals(RunletObject)}. */ public int logicalHashCode() { return getType().hashCode(); } }