com.ibm.wala.fixedpoint.impl.GeneralStatement Maven / Gradle / Ivy
Show all versions of com.ibm.wala.util Show documentation
/*
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*/
package com.ibm.wala.fixedpoint.impl;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.AbstractStatement;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.IVariable;
import org.jspecify.annotations.NullUnmarked;
/** Represents a single step in an iterative solver */
public abstract class GeneralStatement>
extends AbstractStatement> {
protected final T lhs;
protected final T[] rhs;
private final int hashCode;
private final AbstractOperator operator;
/**
* Evaluate this equation, setting a new value for the left-hand side.
*
* @return a constant defined by {@link FixedPointConstants} that reflects whether the lhs value
* changed
*/
@Override
public byte evaluate() {
return operator.evaluate(lhs, rhs);
}
/**
* Return the left-hand side of this equation.
*
* @return the lattice cell this equation computes
*/
@Override
public T getLHS() {
return lhs;
}
/**
* Does this equation contain an appearance of a given cell?
*
* Note: this uses reference equality, assuming that the variables are canonical! This is
* fragile. TODO: Address it perhaps, but be careful not to sacrifice efficiency.
*
* @param cell the cell in question
* @return true or false
*/
@Override
public boolean hasVariable(T cell) {
if (lhs == cell) {
return true;
}
for (T rh : rhs) {
if (rh == cell) return true;
}
return false;
}
/**
* Constructor for case of zero operands on the right-hand side.
*
* @param lhs the lattice cell set by this equation
* @param operator the equation operator
*/
@NullUnmarked
public GeneralStatement(T lhs, AbstractOperator operator) {
super();
if (operator == null) {
throw new IllegalArgumentException("null operator");
}
this.operator = operator;
this.lhs = lhs;
this.rhs = null;
this.hashCode = makeHashCode();
}
/**
* Constructor for case of two operands on the right-hand side.
*
* @param lhs the lattice cell set by this equation
* @param operator the equation operator
* @param op1 the first operand on the rhs
* @param op2 the second operand on the rhs
*/
public GeneralStatement(T lhs, AbstractOperator operator, T op1, T op2) {
super();
if (operator == null) {
throw new IllegalArgumentException("null operator");
}
this.operator = operator;
this.lhs = lhs;
rhs = makeRHS(2);
rhs[0] = op1;
rhs[1] = op2;
this.hashCode = makeHashCode();
}
/**
* Constructor for case of three operands on the right-hand side.
*
* @param lhs the lattice cell set by this equation
* @param operator the equation operator
* @param op1 the first operand on the rhs
* @param op2 the second operand on the rhs
* @param op3 the third operand on the rhs
*/
public GeneralStatement(T lhs, AbstractOperator operator, T op1, T op2, T op3) {
super();
if (operator == null) {
throw new IllegalArgumentException("null operator");
}
this.operator = operator;
rhs = makeRHS(3);
this.lhs = lhs;
rhs[0] = op1;
rhs[1] = op2;
rhs[2] = op3;
this.hashCode = makeHashCode();
}
/**
* Constructor for case of more than three operands on the right-hand side.
*
* @param lhs the lattice cell set by this equation
* @param operator the equation operator
* @param rhs the operands of the right-hand side in order
* @throws IllegalArgumentException if rhs is null
*/
public GeneralStatement(T lhs, AbstractOperator operator, T[] rhs) {
super();
if (operator == null) {
throw new IllegalArgumentException("null operator");
}
if (rhs == null) {
throw new IllegalArgumentException("rhs is null");
}
this.operator = operator;
this.lhs = lhs;
this.rhs = rhs.clone();
this.hashCode = makeHashCode();
}
/** TODO: use a better hash code? */
private static final int[] primes = {331, 337, 347, 1277};
private int makeHashCode() {
int result = operator.hashCode();
if (lhs != null) result += lhs.hashCode() * primes[0];
for (int i = 0; i < Math.min(rhs.length, 2); i++) {
if (rhs[i] != null) {
result += primes[i + 1] * rhs[i].hashCode();
}
}
return result;
}
protected abstract T[] makeRHS(int size);
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (getClass().equals(o.getClass())) {
GeneralStatement> other = (GeneralStatement>) o;
if (hashCode == other.hashCode) {
if (lhs == null || other.lhs == null) {
if (other.lhs != lhs) {
return false;
}
} else if (!lhs.equals(other.lhs)) {
return false;
}
if (operator.equals(other.operator) && rhs.length == other.rhs.length) {
for (int i = 0; i < rhs.length; i++) {
if (rhs[i] == null || other.rhs[i] == null) {
if (other.rhs[i] != rhs[i]) {
return false;
}
} else if (!rhs[i].equals(other.rhs[i])) {
return false;
}
}
return true;
}
}
}
return false;
}
@Override
public AbstractOperator getOperator() {
return operator;
}
@Override
public T[] getRHS() {
return rhs;
}
}