1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.evaluation.value;
22
23import proguard.classfile.ClassConstants;
24
25/**
26 * This class represents a partially evaluated instruction offset. It can
27 * contain 0 or more specific instruction offsets.
28 *
29 * @author Eric Lafortune
30 */
31public class InstructionOffsetValue extends Category1Value
32{
33    public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue();
34
35
36    private int[] values;
37
38
39    private InstructionOffsetValue()
40    {
41    }
42
43
44    public InstructionOffsetValue(int value)
45    {
46        this.values = new int[] { value };
47    }
48
49
50    public InstructionOffsetValue(int[] values)
51    {
52        this.values = values;
53    }
54
55
56    public int instructionOffsetCount()
57    {
58        return values == null ? 0 : values.length;
59    }
60
61
62    public int instructionOffset(int index)
63    {
64        return values[index];
65    }
66
67
68    /**
69     * Returns whether the given value is present in this list of instruction
70     * offsets.
71     */
72    public boolean contains(int value)
73    {
74        if (values != null)
75        {
76            for (int index = 0; index < values.length; index++)
77            {
78                if (values[index] == value)
79                {
80                    return true;
81                }
82            }
83        }
84
85        return false;
86    }
87
88
89    /**
90     * Returns the minimum value from this list of instruction offsets.
91     * Returns <code>Integer.MAX_VALUE</code> if the list is empty.
92     */
93    public int minimumValue()
94    {
95        int minimumValue = Integer.MAX_VALUE;
96
97        if (values != null)
98        {
99            for (int index = 0; index < values.length; index++)
100            {
101                int value = values[index];
102
103                if (minimumValue > value)
104                {
105                    minimumValue = value;
106                }
107            }
108        }
109
110        return minimumValue;
111    }
112
113
114    /**
115     * Returns the maximum value from this list of instruction offsets.
116     * Returns <code>Integer.MIN_VALUE</code> if the list is empty.
117     */
118    public int maximumValue()
119    {
120        int maximumValue = Integer.MIN_VALUE;
121
122        if (values != null)
123        {
124            for (int index = 0; index < values.length; index++)
125            {
126                int value = values[index];
127
128                if (maximumValue < value)
129                {
130                    maximumValue = value;
131                }
132            }
133        }
134
135        return maximumValue;
136    }
137
138
139    /**
140     * Returns the generalization of this InstructionOffsetValue and the given
141     * other InstructionOffsetValue. The values of the other InstructionOffsetValue
142     * are guaranteed to remain at the end of the list, in the same order.
143     */
144    public final Value generalize(InstructionOffsetValue other)
145    {
146        // If the values array of either is null, return the other one.
147        if (this.values == null)
148        {
149            return other;
150        }
151
152        if (other.values == null)
153        {
154            return this;
155        }
156
157        // Compute the length of the union of the arrays.
158        int newLength = this.values.length;
159        for (int index = 0; index < other.values.length; index++)
160        {
161            if (!this.contains(other.values[index]))
162            {
163                newLength++;
164            }
165        }
166
167        // If the length of the union array is equal to the length of the values
168        // array of either, return it.
169        if (newLength == other.values.length)
170        {
171            return other;
172        }
173
174        // The ordering of the this array may not be right, so we can't just
175        // use it.
176        //if (newLength == this.values.length)
177        //{
178        //    return this;
179        //}
180
181        // Create the union array.
182        int[] newValues = new int[newLength];
183
184        int newIndex = 0;
185
186        // Copy the values that are different from the other array.
187        for (int index = 0; index < this.values.length; index++)
188        {
189            if (!other.contains(this.values[index]))
190            {
191                newValues[newIndex++] = this.values[index];
192            }
193        }
194
195        // Copy the values from the other array.
196        for (int index = 0; index < other.values.length; index++)
197        {
198            newValues[newIndex++] = other.values[index];
199        }
200
201        return new InstructionOffsetValue(newValues);
202    }
203
204
205    // Implementations for Value.
206
207    public final InstructionOffsetValue instructionOffsetValue()
208    {
209        return this;
210    }
211
212    public boolean isSpecific()
213    {
214        return true;
215    }
216
217    public boolean isParticular()
218    {
219        return true;
220    }
221
222    public final Value generalize(Value other)
223    {
224        return this.generalize(other.instructionOffsetValue());
225    }
226
227    public final int computationalType()
228    {
229        return TYPE_INSTRUCTION_OFFSET;
230    }
231
232    public final String internalType()
233    {
234        return String.valueOf(ClassConstants.INTERNAL_TYPE_INT);
235    }
236
237
238    // Implementations for Object.
239
240    public boolean equals(Object object)
241    {
242        if (object == null ||
243            this.getClass() != object.getClass())
244        {
245            return false;
246        }
247
248        InstructionOffsetValue other = (InstructionOffsetValue)object;
249        if (this.values == other.values)
250        {
251            return true;
252        }
253
254        if (this.values  == null ||
255            other.values == null ||
256            this.values.length != other.values.length)
257        {
258            return false;
259        }
260
261        for (int index = 0; index < other.values.length; index++)
262        {
263            if (!this.contains(other.values[index]))
264            {
265                return false;
266            }
267        }
268
269        return true;
270    }
271
272
273    public int hashCode()
274    {
275        int hashCode = this.getClass().hashCode();
276
277        if (values != null)
278        {
279            for (int index = 0; index < values.length; index++)
280            {
281                hashCode ^= values[index];
282            }
283        }
284
285        return hashCode;
286    }
287
288
289    public String toString()
290    {
291        StringBuffer buffer = new StringBuffer();
292
293        if (values != null)
294        {
295            for (int index = 0; index < values.length; index++)
296            {
297                if (index > 0)
298                {
299                    buffer.append(',');
300                }
301                buffer.append(values[index]);
302            }
303        }
304
305        return buffer.append(':').toString();
306    }
307}
308