1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.cf.code; 18 19 import com.android.dx.util.IntList; 20 import com.android.dx.util.MutabilityControl; 21 22 /** 23 * List of (value, target) mappings representing the choices of a 24 * {@code tableswitch} or {@code lookupswitch} instruction. It 25 * also holds the default target for the switch. 26 */ 27 public final class SwitchList extends MutabilityControl { 28 /** {@code non-null;} list of test values */ 29 private final IntList values; 30 31 /** 32 * {@code non-null;} list of targets corresponding to the test values; there 33 * is always one extra element in the target list, to hold the 34 * default target 35 */ 36 private final IntList targets; 37 38 /** ultimate size of the list */ 39 private int size; 40 41 /** 42 * Constructs an instance. 43 * 44 * @param size {@code >= 0;} the number of elements to be in the table 45 */ SwitchList(int size)46 public SwitchList(int size) { 47 super(true); 48 this.values = new IntList(size); 49 this.targets = new IntList(size + 1); 50 this.size = size; 51 } 52 53 /** {@inheritDoc} */ 54 @Override setImmutable()55 public void setImmutable() { 56 values.setImmutable(); 57 targets.setImmutable(); 58 super.setImmutable(); 59 } 60 61 /** 62 * Gets the size of the list. 63 * 64 * @return {@code >= 0;} the list size 65 */ size()66 public int size() { 67 return size; 68 } 69 70 /** 71 * Gets the indicated test value. 72 * 73 * @param n {@code >= 0;}, < size(); which index 74 * @return the test value 75 */ getValue(int n)76 public int getValue(int n) { 77 return values.get(n); 78 } 79 80 /** 81 * Gets the indicated target. Asking for the target at {@code size()} 82 * returns the default target. 83 * 84 * @param n {@code >= 0, <= size();} which index 85 * @return {@code >= 0;} the target 86 */ getTarget(int n)87 public int getTarget(int n) { 88 return targets.get(n); 89 } 90 91 /** 92 * Gets the default target. This is just a shorthand for 93 * {@code getTarget(size())}. 94 * 95 * @return {@code >= 0;} the default target 96 */ getDefaultTarget()97 public int getDefaultTarget() { 98 return targets.get(size); 99 } 100 101 /** 102 * Gets the list of all targets. This includes one extra element at the 103 * end of the list, which holds the default target. 104 * 105 * @return {@code non-null;} the target list 106 */ getTargets()107 public IntList getTargets() { 108 return targets; 109 } 110 111 /** 112 * Gets the list of all case values. 113 * 114 * @return {@code non-null;} the case value list 115 */ getValues()116 public IntList getValues() { 117 return values; 118 } 119 120 /** 121 * Sets the default target. It is only valid to call this method 122 * when all the non-default elements have been set. 123 * 124 * @param target {@code >= 0;} the absolute (not relative) default target 125 * address 126 */ setDefaultTarget(int target)127 public void setDefaultTarget(int target) { 128 throwIfImmutable(); 129 130 if (target < 0) { 131 throw new IllegalArgumentException("target < 0"); 132 } 133 134 if (targets.size() != size) { 135 throw new RuntimeException("non-default elements not all set"); 136 } 137 138 targets.add(target); 139 } 140 141 /** 142 * Adds the given item. 143 * 144 * @param value the test value 145 * @param target {@code >= 0;} the absolute (not relative) target address 146 */ add(int value, int target)147 public void add(int value, int target) { 148 throwIfImmutable(); 149 150 if (target < 0) { 151 throw new IllegalArgumentException("target < 0"); 152 } 153 154 values.add(value); 155 targets.add(target); 156 } 157 158 /** 159 * Shrinks this instance if possible, removing test elements that 160 * refer to the default target. This is only valid after the instance 161 * is fully populated, including the default target (naturally). 162 */ removeSuperfluousDefaults()163 public void removeSuperfluousDefaults() { 164 throwIfImmutable(); 165 166 int sz = size; 167 168 if (sz != (targets.size() - 1)) { 169 throw new IllegalArgumentException("incomplete instance"); 170 } 171 172 int defaultTarget = targets.get(sz); 173 int at = 0; 174 175 for (int i = 0; i < sz; i++) { 176 int target = targets.get(i); 177 if (target != defaultTarget) { 178 if (i != at) { 179 targets.set(at, target); 180 values.set(at, values.get(i)); 181 } 182 at++; 183 } 184 } 185 186 if (at != sz) { 187 values.shrink(at); 188 targets.set(at, defaultTarget); 189 targets.shrink(at + 1); 190 size = at; 191 } 192 } 193 } 194