/* * AndOrOptimizer.java * @Author Oleg Gorobets * Created: 13.08.2007 * CVS-ID: $Id: *************************************************************************/ package org.swfparser; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import org.swfparser.operation.AndOperation; import org.swfparser.operation.BinaryLogicalOperation; import org.swfparser.operation.NotOperation; import org.swfparser.operation.TrueOperation; import org.swfparser.operation.OrOperation; import org.swfparser.operation.FalseOperation; public class AndOrOptimizer implements Operation { private static Logger logger = Logger.getLogger(AndOrOptimizer.class); // private BinaryLogicalOperation operation; private Operation optimizedOperation; private static int instanceId = 0; public AndOrOptimizer(BinaryLogicalOperation operation) { // this.operation = operation; instanceId++; this.optimizedOperation = optimizeOperation(operation); } protected Operation optimizeOperation(BinaryLogicalOperation op) { if (op instanceof AndOperation) { return optimizeAnd((AndOperation)op); } else if (op instanceof OrOperation) { return optimizeOr((OrOperation)op); } else { return op; } } public Operation getOptimizedOperation() { return optimizedOperation; } protected Operation optimizeAnd(AndOperation op) { logger.debug("Optimizing AND("+instanceId+"): "+op); // logger.debug("Optimizing AND for"+op1+" and "+op2); Operation op1 = op.getLeftOp(); Operation op2 = op.getRightOp(); if (op1 instanceof TrueOperation) { logger.debug("Result("+instanceId+") is "+op2); return op2; } if (op2 instanceof TrueOperation) { logger.debug("Result("+instanceId+") is "+op1); return op1; } if (op1 instanceof FalseOperation || op2 instanceof FalseOperation) { logger.debug("Result("+instanceId+") is false"); return new FalseOperation(); } if (isNegative(op1, op2)) { logger.debug("Result("+instanceId+") is false"); return new FalseOperation(); } if (isTheSame(op1, op2)) { logger.debug("Result("+instanceId+") is "+op1); return op1; } if (op1 instanceof BinaryLogicalOperation && op2 instanceof BinaryLogicalOperation) { return new AndOperation(optimizeOperation((BinaryLogicalOperation)op1),optimizeOperation((BinaryLogicalOperation)op2)); } else if (op1 instanceof BinaryLogicalOperation) { return new AndOperation(optimizeOperation((BinaryLogicalOperation)op1),op2); } else if (op2 instanceof BinaryLogicalOperation) { return new AndOperation(op1,optimizeOperation((BinaryLogicalOperation)op2)); } logger.debug("No optimization for AND("+instanceId+") "+op); return op; } protected Operation optimizeOr(OrOperation op) { logger.debug("Optimizing OR("+instanceId+"): "+op); // logger.debug("Optimizing AND for"+op1+" and "+op2); Operation op1 = op.getLeftOp(); Operation op2 = op.getRightOp(); if (op1 instanceof TrueOperation || op2 instanceof TrueOperation) { logger.debug("Result("+instanceId+") is true"); return new TrueOperation(); } if (op1 instanceof FalseOperation) { logger.debug("Result("+instanceId+") is "+op2); return op2; } if (op2 instanceof FalseOperation) { logger.debug("Result("+instanceId+") is "+op1); return op1; } if (isNegative(op1, op2)) { logger.debug("Result("+instanceId+") is true"); return new TrueOperation(); } if (isTheSame(op1, op2)) { logger.debug("Result("+instanceId+") is "+op1); return op1; } if (op1 instanceof BinaryLogicalOperation && op2 instanceof BinaryLogicalOperation) { return new OrOperation(optimizeOperation((BinaryLogicalOperation)op1),optimizeOperation((BinaryLogicalOperation)op2)); } else if (op1 instanceof BinaryLogicalOperation) { OrOperation optimized = new OrOperation(optimizeOperation((BinaryLogicalOperation)op1),op2); return optimizeOr1(optimized); } else if (op2 instanceof BinaryLogicalOperation) { OrOperation optimized = new OrOperation(op1,optimizeOperation((BinaryLogicalOperation)op2)); return optimizeOr1(optimized); } logger.debug("No optimization for OR("+instanceId+") "+op); return op; } protected boolean isNegative(Operation op1,Operation op2) { boolean isNegative = false; if (op1 instanceof NotOperation) { isNegative = ((NotOperation)op1).getOp().equals(op2); } if (op2 instanceof NotOperation) { isNegative = ((NotOperation)op2).getOp().equals(op1); } return isNegative; } protected boolean isTheSame(Operation op1,Operation op2) { boolean isTheSame = false; if (op1 instanceof NotOperation && op2 instanceof NotOperation) { isTheSame = ((NotOperation)op1).getOp().equals(((NotOperation)op2).getOp()); } else { isTheSame = op1.equals(op2); } return isTheSame; } /** * Optimize: * 1) x || (!x && y) == x || y * 2) x || (x && y) == x * * @return */ protected Operation optimizeOr1(OrOperation op) { Operation op1 = op.getLeftOp(); Operation op2 = op.getRightOp(); if (op1 instanceof AndOperation && !(op2 instanceof AndOperation)) { return optimizeOr1(op2,(AndOperation) op1); } if (op2 instanceof AndOperation && !(op1 instanceof AndOperation)) { return optimizeOr1(op1,(AndOperation) op2); } return op; } protected Operation optimizeOr1(Operation op1, AndOperation op2) { Operation andArg1 = op2.getLeftOp(); Operation andArg2 = op2.getRightOp(); if (andArg1.equals(op1) || andArg2.equals(op1)) { logger.debug("Result("+instanceId+") is "+op1); return op1; } if (andArg1.equals(new NotOperation(op1))) { Operation result = new OrOperation(op1,andArg2); logger.debug("Result("+instanceId+") is "+result); return result; } if (andArg2.equals(new NotOperation(op1))) { Operation result = new OrOperation(op1,andArg1); logger.debug("Result("+instanceId+") is "+result); return result; } return new OrOperation(op1,op2); } public int getArgsNumber() { return 2; } public int getPriority() { return 0; } public String getStringValue(int level) { return optimizedOperation.getStringValue(level); } public List<Operation> getOperations() { return Arrays.asList(optimizedOperation); } }