/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o 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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.editor;
/**
* Switch is used to hold the lookup values and branch targets of a tableswitch
* or lookup switch instruction.
* <p>
* The tableswitch low-to-high range of values is represented by storing each
* lookup value in the range. This allows the tableswitch to be replaced with a
* lookupswitch if branches are deleted.
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*/
public class Switch {
private Label defaultTarget;
private Label[] targets;
private int[] values;
/**
* Constructor.
*
* @param defaultTarget
* The default target of the switch.
* @param targets
* The non-default branch targets of the switch.
* @param values
* The lookup values of the switch. This array must be the same
* size as the targets array.
*/
public Switch(final Label defaultTarget, final Label[] targets,
final int[] values) {
this.defaultTarget = defaultTarget;
this.targets = targets;
this.values = values;
sort();
uniq();
}
/**
* Set the default target of the switch.
*
* @param target
* The default target of the switch.
*/
public void setDefaultTarget(final Label target) {
defaultTarget = target;
}
/**
* Get the default target of the switch.
*
* @return The default target of the switch.
*/
public Label defaultTarget() {
return defaultTarget;
}
/**
* Get the non-default branch targets of the switch. The targets are sorted
* by the corresponding lookup value.
*
* @return The non-default branch targets of the switch.
*/
public Label[] targets() {
return targets;
}
/**
* Get the lookup values of the switch, sorted low to high.
*
* @return The lookup values of the switch.
*/
public int[] values() {
return values;
}
/**
* Check if the all the values in the range of lookup values are contiguous.
* If they are, a table switch can be used. If not a lookupswitch can be
* used.
*
* @return true if contiguous, false if not.
*/
public boolean hasContiguousValues() {
return values.length == highValue() - lowValue() + 1;
}
/**
* Get the low value in the range the lookup values.
*
* @return The low value.
*/
public int lowValue() {
return values[0];
}
/**
* Get the high value in the range the lookup values.
*
* @return The high value.
*/
public int highValue() {
return values[values.length - 1];
}
/**
* Sort the targets and values arrays so that values is sorted low to high.
*/
private void sort() {
quicksort(0, values.length - 1);
}
/**
* Utility function to sort the targets and values arrays so that values is
* sorted low to high.
*
* @param p
* The low index of the portion of the array to sort.
* @param r
* The high index of the portion of the array to sort.
*/
private void quicksort(final int p, final int r) {
if (p < r) {
final int q = partition(p, r);
quicksort(p, q);
quicksort(q + 1, r);
}
}
/**
* Utility function to sort the targets and values arrays so that values is
* sorted low to high.
* <p>
* Partition the arrays so that the values less than values[p] are to the
* left.
*
* @param p
* The low index of the portion of the array to sort.
* @param r
* The high index of the portion of the array to sort.
* @return The index at which the partition finished.
*/
private int partition(final int p, final int r) {
final int x = values[p];
int i = p - 1;
int j = r + 1;
while (true) {
do {
j--;
} while (values[j] > x);
do {
i++;
} while (values[i] < x);
if (i < j) {
final int v = values[i];
values[i] = values[j];
values[j] = v;
final Label t = targets[i];
targets[i] = targets[j];
targets[j] = t;
} else {
return j;
}
}
}
/**
* Remove duplicates from the values and targets arrays.
*/
private void uniq() {
if (values.length == 0) {
return;
}
final int[] v = new int[values.length];
final Label[] t = new Label[values.length];
v[0] = values[0];
t[0] = targets[0];
int j = 1;
for (int i = 1; i < values.length; i++) {
if (v[j - 1] != values[i]) {
v[j] = values[i];
t[j] = targets[i];
j++;
}
}
values = new int[j];
System.arraycopy(v, 0, values, 0, j);
targets = new Label[j];
System.arraycopy(t, 0, targets, 0, j);
}
/**
* Convert the operand to a string.
*
* @return A string representation of the operand.
*/
public String toString() {
return "" + values.length + " pairs";
}
}