1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2007 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.mockito.asm;
31
32/**
33 * A constant pool item. Constant pool items can be created with the 'newXXX'
34 * methods in the {@link ClassWriter} class.
35 *
36 * @author Eric Bruneton
37 */
38final class Item {
39
40    /**
41     * Index of this item in the constant pool.
42     */
43    int index;
44
45    /**
46     * Type of this constant pool item. A single class is used to represent all
47     * constant pool item types, in order to minimize the bytecode size of this
48     * package. The value of this field is one of {@link ClassWriter#INT},
49     * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
50     * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
51     * {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
52     * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
53     * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}.
54     *
55     * Special Item types are used for Items that are stored in the ClassWriter
56     * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
57     * avoid clashes with normal constant pool items in the ClassWriter constant
58     * pool's hash table. These special item types are
59     * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
60     * {@link ClassWriter#TYPE_MERGED}.
61     */
62    int type;
63
64    /**
65     * Value of this item, for an integer item.
66     */
67    int intVal;
68
69    /**
70     * Value of this item, for a long item.
71     */
72    long longVal;
73
74    /**
75     * First part of the value of this item, for items that do not hold a
76     * primitive value.
77     */
78    String strVal1;
79
80    /**
81     * Second part of the value of this item, for items that do not hold a
82     * primitive value.
83     */
84    String strVal2;
85
86    /**
87     * Third part of the value of this item, for items that do not hold a
88     * primitive value.
89     */
90    String strVal3;
91
92    /**
93     * The hash code value of this constant pool item.
94     */
95    int hashCode;
96
97    /**
98     * Link to another constant pool item, used for collision lists in the
99     * constant pool's hash table.
100     */
101    Item next;
102
103    /**
104     * Constructs an uninitialized {@link Item}.
105     */
106    Item() {
107    }
108
109    /**
110     * Constructs an uninitialized {@link Item} for constant pool element at
111     * given position.
112     *
113     * @param index index of the item to be constructed.
114     */
115    Item(final int index) {
116        this.index = index;
117    }
118
119    /**
120     * Constructs a copy of the given item.
121     *
122     * @param index index of the item to be constructed.
123     * @param i the item that must be copied into the item to be constructed.
124     */
125    Item(final int index, final Item i) {
126        this.index = index;
127        type = i.type;
128        intVal = i.intVal;
129        longVal = i.longVal;
130        strVal1 = i.strVal1;
131        strVal2 = i.strVal2;
132        strVal3 = i.strVal3;
133        hashCode = i.hashCode;
134    }
135
136    /**
137     * Sets this item to an integer item.
138     *
139     * @param intVal the value of this item.
140     */
141    void set(final int intVal) {
142        this.type = ClassWriter.INT;
143        this.intVal = intVal;
144        this.hashCode = 0x7FFFFFFF & (type + intVal);
145    }
146
147    /**
148     * Sets this item to a long item.
149     *
150     * @param longVal the value of this item.
151     */
152    void set(final long longVal) {
153        this.type = ClassWriter.LONG;
154        this.longVal = longVal;
155        this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
156    }
157
158    /**
159     * Sets this item to a float item.
160     *
161     * @param floatVal the value of this item.
162     */
163    void set(final float floatVal) {
164        this.type = ClassWriter.FLOAT;
165        this.intVal = Float.floatToRawIntBits(floatVal);
166        this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
167    }
168
169    /**
170     * Sets this item to a double item.
171     *
172     * @param doubleVal the value of this item.
173     */
174    void set(final double doubleVal) {
175        this.type = ClassWriter.DOUBLE;
176        this.longVal = Double.doubleToRawLongBits(doubleVal);
177        this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
178    }
179
180    /**
181     * Sets this item to an item that do not hold a primitive value.
182     *
183     * @param type the type of this item.
184     * @param strVal1 first part of the value of this item.
185     * @param strVal2 second part of the value of this item.
186     * @param strVal3 third part of the value of this item.
187     */
188    void set(
189        final int type,
190        final String strVal1,
191        final String strVal2,
192        final String strVal3)
193    {
194        this.type = type;
195        this.strVal1 = strVal1;
196        this.strVal2 = strVal2;
197        this.strVal3 = strVal3;
198        switch (type) {
199            case ClassWriter.UTF8:
200            case ClassWriter.STR:
201            case ClassWriter.CLASS:
202            case ClassWriter.TYPE_NORMAL:
203                hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
204                return;
205            case ClassWriter.NAME_TYPE:
206                hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
207                        * strVal2.hashCode());
208                return;
209                // ClassWriter.FIELD:
210                // ClassWriter.METH:
211                // ClassWriter.IMETH:
212            default:
213                hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
214                        * strVal2.hashCode() * strVal3.hashCode());
215        }
216    }
217
218    /**
219     * Indicates if the given item is equal to this one.
220     *
221     * @param i the item to be compared to this one.
222     * @return <tt>true</tt> if the given item if equal to this one,
223     *         <tt>false</tt> otherwise.
224     */
225    boolean isEqualTo(final Item i) {
226        if (i.type == type) {
227            switch (type) {
228                case ClassWriter.INT:
229                case ClassWriter.FLOAT:
230                    return i.intVal == intVal;
231                case ClassWriter.TYPE_MERGED:
232                case ClassWriter.LONG:
233                case ClassWriter.DOUBLE:
234                    return i.longVal == longVal;
235                case ClassWriter.UTF8:
236                case ClassWriter.STR:
237                case ClassWriter.CLASS:
238                case ClassWriter.TYPE_NORMAL:
239                    return i.strVal1.equals(strVal1);
240                case ClassWriter.TYPE_UNINIT:
241                    return i.intVal == intVal && i.strVal1.equals(strVal1);
242                case ClassWriter.NAME_TYPE:
243                    return i.strVal1.equals(strVal1)
244                            && i.strVal2.equals(strVal2);
245                    // ClassWriter.FIELD:
246                    // ClassWriter.METH:
247                    // ClassWriter.IMETH:
248                default:
249                    return i.strVal1.equals(strVal1)
250                            && i.strVal2.equals(strVal2)
251                            && i.strVal3.equals(strVal3);
252            }
253        }
254        return false;
255    }
256}
257