FileDocCategorySizeDatePackage
SwitchList.javaAPI DocAndroid 1.5 API5129Wed May 06 22:41:02 BST 2009com.android.dx.cf.code

SwitchList.java

/*
 * 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</code> or <code>lookupswitch</code> instruction. It
 * also holds the default target for the switch.
 */
public final class SwitchList extends MutabilityControl {
    /** non-null; list of test values */
    private final IntList values;

    /**
     * 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 >= 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 >= 0; the list size
     */
    public int size() {
        return size;
    }

    /**
     * Gets the indicated test value.
     * 
     * @param n >= 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()</code>
     * returns the default target.
     * 
     * @param n >= 0, <= size(); which index
     * @return >= 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())</code>.
     * 
     * @return >= 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 non-null; the target list
     */
    public IntList getTargets() {
        return targets;
    }

    /**
     * Gets the list of all case values.
     * 
     * @return 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 >= 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 >= 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;
        }
    }
}