/* * 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.FixedSizeList; /** * List of "line number" entries, which are the contents of * {@code LineNumberTable} attributes. */ public final class LineNumberList extends FixedSizeList { /** {@code non-null;} zero-size instance */ public static final LineNumberList EMPTY = new LineNumberList(0); /** * Returns an instance which is the concatenation of the two given * instances. * * @param list1 {@code non-null;} first instance * @param list2 {@code non-null;} second instance * @return {@code non-null;} combined instance */ public static LineNumberList concat(LineNumberList list1, LineNumberList list2) { if (list1 == EMPTY) { // easy case return list2; } int sz1 = list1.size(); int sz2 = list2.size(); LineNumberList result = new LineNumberList(sz1 + sz2); for (int i = 0; i < sz1; i++) { result.set(i, list1.get(i)); } for (int i = 0; i < sz2; i++) { result.set(sz1 + i, list2.get(i)); } return result; } /** * Constructs an instance. * * @param count the number of elements to be in the list */ public LineNumberList(int count) { super(count); } /** * Gets the indicated item. * * @param n {@code >= 0;} which item * @return {@code null-ok;} the indicated item */ public Item get(int n) { return (Item) get0(n); } /** * Sets the item at the given index. * * @param n {@code >= 0, < size();} which element * @param item {@code non-null;} the item */ public void set(int n, Item item) { if (item == null) { throw new NullPointerException("item == null"); } set0(n, item); } /** * Sets the item at the given index. * * @param n {@code >= 0, < size();} which element * @param startPc {@code >= 0;} start pc of this item * @param lineNumber {@code >= 0;} corresponding line number */ public void set(int n, int startPc, int lineNumber) { set0(n, new Item(startPc, lineNumber)); } /** * Gets the line number associated with the given address. * * @param pc {@code >= 0;} the address to look up * @return {@code >= -1;} the associated line number, or {@code -1} if * none is known */ public int pcToLine(int pc) { /* * Line number entries don't have to appear in any particular * order, so we have to do a linear search. TODO: If * this turns out to be a bottleneck, consider sorting the * list prior to use. */ int sz = size(); int bestPc = -1; int bestLine = -1; for (int i = 0; i < sz; i++) { Item one = get(i); int onePc = one.getStartPc(); if ((onePc <= pc) && (onePc > bestPc)) { bestPc = onePc; bestLine = one.getLineNumber(); if (bestPc == pc) { // We can't do better than this break; } } } return bestLine; } /** * Item in a line number table. */ public static class Item { /** {@code >= 0;} start pc of this item */ private final int startPc; /** {@code >= 0;} corresponding line number */ private final int lineNumber; /** * Constructs an instance. * * @param startPc {@code >= 0;} start pc of this item * @param lineNumber {@code >= 0;} corresponding line number */ public Item(int startPc, int lineNumber) { if (startPc < 0) { throw new IllegalArgumentException("startPc < 0"); } if (lineNumber < 0) { throw new IllegalArgumentException("lineNumber < 0"); } this.startPc = startPc; this.lineNumber = lineNumber; } /** * Gets the start pc of this item. * * @return the start pc */ public int getStartPc() { return startPc; } /** * Gets the line number of this item. * * @return the line number */ public int getLineNumber() { return lineNumber; } } }