1/*
2 * Copyright (C) 2008 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
17package com.android.dx.dex.code;
18
19import com.android.dx.rop.cst.CstType;
20import com.android.dx.util.FixedSizeList;
21
22/**
23 * Table of catch entries. Each entry includes a range of code
24 * addresses for which it is valid and an associated {@link
25 * CatchHandlerList}.
26 */
27public final class CatchTable extends FixedSizeList
28        implements Comparable<CatchTable> {
29    /** {@code non-null;} empty instance */
30    public static final CatchTable EMPTY = new CatchTable(0);
31
32    /**
33     * Constructs an instance. All indices initially contain {@code null}.
34     *
35     * @param size {@code >= 0;} the size of the table
36     */
37    public CatchTable(int size) {
38        super(size);
39    }
40
41    /**
42     * Gets the element at the given index. It is an error to call
43     * this with the index for an element which was never set; if you
44     * do that, this will throw {@code NullPointerException}.
45     *
46     * @param n {@code >= 0, < size();} which index
47     * @return {@code non-null;} element at that index
48     */
49    public Entry get(int n) {
50        return (Entry) get0(n);
51    }
52
53    /**
54     * Sets the entry at the given index.
55     *
56     * @param n {@code >= 0, < size();} which index
57     * @param entry {@code non-null;} the entry to set at {@code n}
58     */
59    public void set(int n, Entry entry) {
60        set0(n, entry);
61    }
62
63    /** {@inheritDoc} */
64    public int compareTo(CatchTable other) {
65        if (this == other) {
66            // Easy out.
67            return 0;
68        }
69
70        int thisSize = size();
71        int otherSize = other.size();
72        int checkSize = Math.min(thisSize, otherSize);
73
74        for (int i = 0; i < checkSize; i++) {
75            Entry thisEntry = get(i);
76            Entry otherEntry = other.get(i);
77            int compare = thisEntry.compareTo(otherEntry);
78            if (compare != 0) {
79                return compare;
80            }
81        }
82
83        if (thisSize < otherSize) {
84            return -1;
85        } else if (thisSize > otherSize) {
86            return 1;
87        }
88
89        return 0;
90    }
91
92    /**
93     * Entry in a catch list.
94     */
95    public static class Entry implements Comparable<Entry> {
96        /** {@code >= 0;} start address */
97        private final int start;
98
99        /** {@code > start;} end address (exclusive) */
100        private final int end;
101
102        /** {@code non-null;} list of catch handlers */
103        private final CatchHandlerList handlers;
104
105        /**
106         * Constructs an instance.
107         *
108         * @param start {@code >= 0;} start address
109         * @param end {@code > start;} end address (exclusive)
110         * @param handlers {@code non-null;} list of catch handlers
111         */
112        public Entry(int start, int end, CatchHandlerList handlers) {
113            if (start < 0) {
114                throw new IllegalArgumentException("start < 0");
115            }
116
117            if (end <= start) {
118                throw new IllegalArgumentException("end <= start");
119            }
120
121            if (handlers.isMutable()) {
122                throw new IllegalArgumentException("handlers.isMutable()");
123            }
124
125            this.start = start;
126            this.end = end;
127            this.handlers = handlers;
128        }
129
130        /** {@inheritDoc} */
131        @Override
132        public int hashCode() {
133            int hash = (start * 31) + end;
134            hash = (hash * 31) + handlers.hashCode();
135            return hash;
136        }
137
138        /** {@inheritDoc} */
139        @Override
140        public boolean equals(Object other) {
141            if (other instanceof Entry) {
142                return (compareTo((Entry) other) == 0);
143            }
144
145            return false;
146        }
147
148        /** {@inheritDoc} */
149        public int compareTo(Entry other) {
150            if (start < other.start) {
151                return -1;
152            } else if (start > other.start) {
153                return 1;
154            }
155
156            if (end < other.end) {
157                return -1;
158            } else if (end > other.end) {
159                return 1;
160            }
161
162            return handlers.compareTo(other.handlers);
163        }
164
165        /**
166         * Gets the start address.
167         *
168         * @return {@code >= 0;} the start address
169         */
170        public int getStart() {
171            return start;
172        }
173
174        /**
175         * Gets the end address (exclusive).
176         *
177         * @return {@code > start;} the end address (exclusive)
178         */
179        public int getEnd() {
180            return end;
181        }
182
183        /**
184         * Gets the handlers.
185         *
186         * @return {@code non-null;} the handlers
187         */
188        public CatchHandlerList getHandlers() {
189            return handlers;
190        }
191    }
192}
193