/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dx.cf.code; import com.android.dx.util.IntList; import com.android.dx.util.MutabilityControl; /** * List of (value, target) mappings representing the choices of a * {@code tableswitch} or {@code lookupswitch} instruction. It * also holds the default target for the switch. */ public final class SwitchList extends MutabilityControl { /** {@code non-null;} list of test values */ private final IntList values; /** * {@code non-null;} list of targets corresponding to the test values; there * is always one extra element in the target list, to hold the * default target */ private final IntList targets; /** ultimate size of the list */ private int size; /** * Constructs an instance. * * @param size {@code >= 0;} the number of elements to be in the table */ public SwitchList(int size) { super(true); this.values = new IntList(size); this.targets = new IntList(size + 1); this.size = size; } /** {@inheritDoc} */ @Override public void setImmutable() { values.setImmutable(); targets.setImmutable(); super.setImmutable(); } /** * Gets the size of the list. * * @return {@code >= 0;} the list size */ public int size() { return size; } /** * Gets the indicated test value. * * @param n {@code >= 0;}, < size(); which index * @return the test value */ public int getValue(int n) { return values.get(n); } /** * Gets the indicated target. Asking for the target at {@code size()} * returns the default target. * * @param n {@code >= 0, <= size();} which index * @return {@code >= 0;} the target */ public int getTarget(int n) { return targets.get(n); } /** * Gets the default target. This is just a shorthand for * {@code getTarget(size())}. * * @return {@code >= 0;} the default target */ public int getDefaultTarget() { return targets.get(size); } /** * Gets the list of all targets. This includes one extra element at the * end of the list, which holds the default target. * * @return {@code non-null;} the target list */ public IntList getTargets() { return targets; } /** * Gets the list of all case values. * * @return {@code non-null;} the case value list */ public IntList getValues() { return values; } /** * Sets the default target. It is only valid to call this method * when all the non-default elements have been set. * * @param target {@code >= 0;} the absolute (not relative) default target * address */ public void setDefaultTarget(int target) { throwIfImmutable(); if (target < 0) { throw new IllegalArgumentException("target < 0"); } if (targets.size() != size) { throw new RuntimeException("non-default elements not all set"); } targets.add(target); } /** * Adds the given item. * * @param value the test value * @param target {@code >= 0;} the absolute (not relative) target address */ public void add(int value, int target) { throwIfImmutable(); if (target < 0) { throw new IllegalArgumentException("target < 0"); } values.add(value); targets.add(target); } /** * Shrinks this instance if possible, removing test elements that * refer to the default target. This is only valid after the instance * is fully populated, including the default target (naturally). */ public void removeSuperfluousDefaults() { throwIfImmutable(); int sz = size; if (sz != (targets.size() - 1)) { throw new IllegalArgumentException("incomplete instance"); } int defaultTarget = targets.get(sz); int at = 0; for (int i = 0; i < sz; i++) { int target = targets.get(i); if (target != defaultTarget) { if (i != at) { targets.set(at, target); values.set(at, values.get(i)); } at++; } } if (at != sz) { values.shrink(at); targets.set(at, defaultTarget); targets.shrink(at + 1); size = at; } } }