/* Soot - a J*va Optimization Framework * Copyright (C) 2011 Richard Xiao * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.jimple.spark.geom.geomE; import soot.jimple.spark.geom.geomPA.RectangleNode; import soot.jimple.spark.geom.geomPA.SegmentNode; import soot.jimple.spark.geom.geomE.GeometricManager; import soot.jimple.spark.geom.geomPA.IFigureManager; /** * Currently, we apply a naive management strategy: * For each type of object, we maintain a linked list. If we insert a new object, we don't test if * all the geometric objects on the plane together can cover the new object. Instead, we test if there is * one object already covers the new object. * * @author xiao * */ public class GeometricManager implements IFigureManager { public static final int Divisions = 2; // The type ID for different figures public static final int ONE_TO_ONE = 0; public static final int MANY_TO_MANY = 1; public static final int Undefined_Mapping = -1; private SegmentNode header[] = { null, null }; private int size[] = { 0, 0 }; private boolean hasNewFigure = false; public SegmentNode[] getFigures() { return header; } public int[] getSizes() { return size; } public boolean isThereUnprocessedFigures() { return hasNewFigure; } /** * Remove the new labels for all the figures. */ public void flush() { hasNewFigure = false; for ( int i = 0; i < Divisions; ++i ) { SegmentNode p = header[i]; while ( p != null && p.is_new == true ) { p.is_new = false; p = p.next; } } } /** * Insert a new figure into this manager if it is not covered by any exisiting figure. */ public SegmentNode addNewFigure(int code, RectangleNode pnew) { SegmentNode p; // We first check if there is an existing object contains this new object if ( checkRedundancy( code, pnew ) ) return null; // Oppositely, we check if any existing objects are obsoleted filterOutDuplicates( code, pnew ); // Ok, now we generate a copy if ( code == GeometricManager.ONE_TO_ONE ) p = new SegmentNode( pnew ); else p = new RectangleNode( pnew ); hasNewFigure = true; p.next = header[code]; header[code] = p; size[code]++; return p; } /** * Merge the set of objects in the same category into one. */ public void mergeFigures( int buget_size ) { RectangleNode p; // We don't merge the figures if there are no new figures in this geometric manager if ( !hasNewFigure ) return; for ( int i = 0; i < Divisions; ++i ) { p = null; if ( size[i] > buget_size && header[i].is_new == true ) { // Merging is finding the bounding rectangles for every type of objects switch ( i ) { case GeometricManager.ONE_TO_ONE: p = mergeOneToOne(); break; case GeometricManager.MANY_TO_MANY: p = mergeManyToMany(); break; } } if ( p != null ) { if ( i == GeometricManager.ONE_TO_ONE ) { if ( checkRedundancy(GeometricManager.MANY_TO_MANY, p) ) continue; filterOutDuplicates(GeometricManager.MANY_TO_MANY, p); } p.next = header[GeometricManager.MANY_TO_MANY]; header[GeometricManager.MANY_TO_MANY] = p; size[GeometricManager.MANY_TO_MANY]++; } } } /** * The lines that are included in some rectangles can be deleted. */ public void removeUselessSegments() { SegmentNode pnew = header[GeometricManager.ONE_TO_ONE]; SegmentNode q = null; int countAll = 0; while (pnew != null) { SegmentNode temp = pnew.next; if (!isContainedInRectangles(pnew)) { pnew.next = q; q = pnew; ++countAll; } pnew = temp; } size[GeometricManager.ONE_TO_ONE] = countAll; header[GeometricManager.ONE_TO_ONE] = q; } /** * Is the input line covered by any rectangle? * @param pnew, must be a line * @return */ private boolean isContainedInRectangles(SegmentNode pnew) { SegmentNode p = header[ GeometricManager.MANY_TO_MANY ]; while ( p != null ) { if (pnew.I1 >= p.I1 && pnew.I2 >= p.I2) { if ((pnew.I1 + pnew.L) <= (p.I1 + p.L) && (pnew.I2 + pnew.L) <= (p.I2 + ((RectangleNode) p).L_prime)) return true; } p = p.next; } return false; } /** * Judge if the newly added geometric shape is redundant. * @param code * @param pnew * @return */ private boolean checkRedundancy(int code, RectangleNode pnew) { // Expand it temporarily if (code == GeometricManager.ONE_TO_ONE) pnew.L_prime = pnew.L; // Check redundancy for ( int i = code; i <= GeometricManager.MANY_TO_MANY; ++i ) { SegmentNode p = header[i]; while ( p != null ) { switch ( i ) { case GeometricManager.ONE_TO_ONE: if ( (p.I2 - p.I1) == (pnew.I2 - pnew.I1) ) { // Have the same intercept and it is completely contained in an existing segment if ( pnew.I1 >= p.I1 && (pnew.I1 + pnew.L) <= (p.I1 + p.L) ) return true; } break; case GeometricManager.MANY_TO_MANY: if ( pnew.I1 >= p.I1 && pnew.I2 >= p.I2 ) { if ( (pnew.I1 + pnew.L) <= (p.I1 + p.L) && (pnew.I2 + pnew.L_prime) <= (p.I2 + ((RectangleNode)p).L_prime) ) return true; } break; } p = p.next; } } return false; } /** * Drop the redundant existing objects. * @param code * @param p */ private void filterOutDuplicates(int code, SegmentNode p) { boolean flag; SegmentNode q_head, q_tail; SegmentNode pold; int countAll; for ( int i = code; i > -1; --i ) { pold = header[i]; q_head = null; q_tail = null; countAll = 0; while ( pold != null ) { flag = false; switch ( i ) { case GeometricManager.ONE_TO_ONE: if ( code == GeometricManager.MANY_TO_MANY ) { if (pold.I1 >= p.I1 && pold.I2 >= p.I2) { if ((pold.I1 + pold.L) <= (p.I1 + p.L) && (pold.I2 + pold.L) <= (p.I2 + ((RectangleNode) p).L_prime)) flag = true; } } else { if ( (p.I2 - p.I1) == (pold.I2 - pold.I1) ) { if ( pold.I1 >= p.I1 && (pold.I1 + pold.L) <= (p.I1 + p.L) ) flag = true; } } break; case GeometricManager.MANY_TO_MANY: if ( pold.I1 >= p.I1 && pold.I2 >= p.I2 ) { if ( (pold.I1 + pold.L) <= (p.I1 + p.L) && (pold.I2 + ((RectangleNode)pold).L_prime) <= (p.I2 + ((RectangleNode)p).L_prime) ) flag = true; } break; } if ( flag == false ) { if ( q_head == null ) q_head = pold; else q_tail.next = pold; q_tail = pold; ++countAll; } pold = pold.next; } if ( q_tail != null ) q_tail.next = null; header[i] = q_head; size[i] = countAll; } } /** * Find the bounding rectangle for all the rectangle figures. * @return */ private RectangleNode mergeManyToMany() { long x_min = Long.MAX_VALUE, y_min = Long.MAX_VALUE; long x_max = Long.MIN_VALUE, y_max = Long.MIN_VALUE; RectangleNode p = (RectangleNode)header[GeometricManager.MANY_TO_MANY]; while ( p != null ) { if ( p.I1 < x_min ) x_min = p.I1; if ( p.I2 < y_min ) y_min = p.I2; if ( p.I1 + p.L > x_max ) x_max = p.I1 + p.L; if ( p.I2 + p.L_prime > y_max ) y_max = p.I2 + p.L_prime; p = (RectangleNode)p.next; } // We assume the list has at least one element p = (RectangleNode)header[GeometricManager.MANY_TO_MANY]; header[GeometricManager.MANY_TO_MANY] = null; size[GeometricManager.MANY_TO_MANY] = 0; p.I1 = x_min; p.I2 = y_min; p.L = x_max - x_min; p.L_prime = y_max - y_min; p.next = null; return p; } /** * Find the bounding rectangle for all segment figures. * @return */ private RectangleNode mergeOneToOne() { long x_min = Long.MAX_VALUE, y_min = Long.MAX_VALUE; long x_max = Long.MIN_VALUE, y_max = Long.MIN_VALUE; SegmentNode p = header[GeometricManager.ONE_TO_ONE]; header[GeometricManager.ONE_TO_ONE] = null; size[GeometricManager.ONE_TO_ONE] = 0; while ( p != null ) { if ( p.I1 < x_min ) x_min = p.I1; if ( p.I2 < y_min ) y_min = p.I2; if ( p.I1 + p.L > x_max ) x_max = p.I1 + p.L; if ( p.I2 + p.L > y_max ) y_max = p.I2 + p.L; p = p.next; } RectangleNode q = new RectangleNode(); q.I1 = x_min; q.I2 = y_min; q.L = x_max - x_min; q.L_prime = y_max - y_min; return q; } }