OSDN Git Service

Mechanical refactoring of dx into two parts.
[android-x86/dalvik.git] / dx / src / com / android / dx / dex / file / UniformListItem.java
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.dex.file;
18
19 import com.android.dx.util.AnnotatedOutput;
20 import com.android.dx.util.Hex;
21 import java.util.List;
22
23 /**
24  * Class that represents a contiguous list of uniform items. Each
25  * item in the list, in particular, must have the same write size and
26  * alignment.
27  *
28  * <p>This class inherits its alignment from its items, bumped up to
29  * {@code 4} if the items have a looser alignment requirement. If
30  * it is more than {@code 4}, then there will be a gap after the
31  * output list size (which is four bytes) and before the first item.</p>
32  *
33  * @param <T> type of element contained in an instance
34  */
35 public final class UniformListItem<T extends OffsettedItem>
36         extends OffsettedItem {
37     /** the size of the list header */
38     private static final int HEADER_SIZE = 4;
39
40     /** {@code non-null;} the item type */
41     private final ItemType itemType;
42
43     /** {@code non-null;} the contents */
44     private final List<T> items;
45
46     /**
47      * Constructs an instance. It is illegal to modify the given list once
48      * it is used to construct an instance of this class.
49      *
50      * @param itemType {@code non-null;} the type of the item
51      * @param items {@code non-null and non-empty;} list of items to represent
52      */
53     public UniformListItem(ItemType itemType, List<T> items) {
54         super(getAlignment(items), writeSize(items));
55
56         if (itemType == null) {
57             throw new NullPointerException("itemType == null");
58         }
59
60         this.items = items;
61         this.itemType = itemType;
62     }
63
64     /**
65      * Helper for {@link #UniformListItem}, which returns the alignment
66      * requirement implied by the given list. See the header comment for
67      * more details.
68      *
69      * @param items {@code non-null;} list of items being represented
70      * @return {@code >= 4;} the alignment requirement
71      */
72     private static int getAlignment(List<? extends OffsettedItem> items) {
73         try {
74             // Since they all must have the same alignment, any one will do.
75             return Math.max(HEADER_SIZE, items.get(0).getAlignment());
76         } catch (IndexOutOfBoundsException ex) {
77             // Translate the exception.
78             throw new IllegalArgumentException("items.size() == 0");
79         } catch (NullPointerException ex) {
80             // Translate the exception.
81             throw new NullPointerException("items == null");
82         }
83     }
84
85     /**
86      * Calculates the write size for the given list.
87      *
88      * @param items {@code non-null;} the list in question
89      * @return {@code >= 0;} the write size
90      */
91     private static int writeSize(List<? extends OffsettedItem> items) {
92         /*
93          * This class assumes all included items are the same size,
94          * an assumption which is verified in place0().
95          */
96         OffsettedItem first = items.get(0);
97         return (items.size() * first.writeSize()) + getAlignment(items);
98     }
99
100     /** {@inheritDoc} */
101     @Override
102     public ItemType itemType() {
103         return itemType;
104     }
105
106     /** {@inheritDoc} */
107     @Override
108     public String toString() {
109         StringBuffer sb = new StringBuffer(100);
110
111         sb.append(getClass().getName());
112         sb.append(items);
113
114         return sb.toString();
115     }
116
117     /** {@inheritDoc} */
118     @Override
119     public void addContents(DexFile file) {
120         for (OffsettedItem i : items) {
121             i.addContents(file);
122         }
123     }
124
125     /** {@inheritDoc} */
126     @Override
127     public final String toHuman() {
128         StringBuffer sb = new StringBuffer(100);
129         boolean first = true;
130
131         sb.append("{");
132
133         for (OffsettedItem i : items) {
134             if (first) {
135                 first = false;
136             } else {
137                 sb.append(", ");
138             }
139             sb.append(i.toHuman());
140         }
141
142         sb.append("}");
143         return sb.toString();
144     }
145
146     /**
147      * Gets the underlying list of items.
148      *
149      * @return {@code non-null;} the list
150      */
151     public final List<T> getItems() {
152         return items;
153     }
154
155     /** {@inheritDoc} */
156     @Override
157     protected void place0(Section addedTo, int offset) {
158         offset += headerSize();
159
160         boolean first = true;
161         int theSize = -1;
162         int theAlignment = -1;
163
164         for (OffsettedItem i : items) {
165             int size = i.writeSize();
166             if (first) {
167                 theSize = size;
168                 theAlignment = i.getAlignment();
169                 first = false;
170             } else {
171                 if (size != theSize) {
172                     throw new UnsupportedOperationException(
173                             "item size mismatch");
174                 }
175                 if (i.getAlignment() != theAlignment) {
176                     throw new UnsupportedOperationException(
177                             "item alignment mismatch");
178                 }
179             }
180
181             offset = i.place(addedTo, offset) + size;
182         }
183     }
184
185     /** {@inheritDoc} */
186     @Override
187     protected void writeTo0(DexFile file, AnnotatedOutput out) {
188         int size = items.size();
189
190         if (out.annotates()) {
191             out.annotate(0, offsetString() + " " + typeName());
192             out.annotate(4, "  size: " + Hex.u4(size));
193         }
194
195         out.writeInt(size);
196
197         for (OffsettedItem i : items) {
198             i.writeTo(file, out);
199         }
200     }
201
202     /**
203      * Get the size of the header of this list.
204      *
205      * @return {@code >= 0;} the header size
206      */
207     private int headerSize() {
208         /*
209          * Because of how this instance was set up, this is the same
210          * as the alignment.
211          */
212         return getAlignment();
213     }
214 }