View Javadoc
1   /*
2    * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  package com.apple.internal.jobjc.generator.model.types;
26  
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import com.apple.internal.jobjc.generator.Utils;
34  import com.apple.internal.jobjc.generator.model.coders.PrimitiveCoderDescriptor;
35  import com.apple.internal.jobjc.generator.utils.Fp;
36  import com.apple.internal.jobjc.generator.utils.NTypePrinter;
37  import com.apple.internal.jobjc.generator.utils.QA;
38  import com.apple.jobjc.JObjCRuntime.Width;
39  
40  /**
41   * NType (Native Type) bridges the type and type64 attributes in BridgeSupport.
42   *
43   * For example:
44   *
45   * <pre>
46   *   type="c"                 // BridgeSupport attribute
47   *   (NPrimitive type: 'c')   // Java object (in sexp form here, for readability)
48   *
49   *   type="^v"
50   *   (NPointer subject: (NVoid))
51   *
52   *   type="{foo_t="a"c"b"b8"c"[32^v]}"
53   *   (NStruct
54   *     name: "foo_t"
55   *     fields:
56   *       (List<NField>
57   *         0: (NField name:"a" type: (NPrimitive type: 'c'))
58   *         1: (NField name:"b" type: (NBitfield size: 8))
59   *         2: (NField name:"c" type:
60   *              (NArray size: 32
61   *                      type: (NPointer subject: (NVoid))))))
62   * </pre>
63   */
64  public abstract class NType implements Comparable<NType>{
65      public final Map<Width, Integer> sizeof;
66  
67      public NType(Map<Width, Integer> sizeof) {
68          this.sizeof = sizeof;
69      }
70  
71      public NType(){
72          this(new HashMap<Width, Integer>());
73      }
74  
75      public NType(int sz32, int sz64){
76          this();
77          this.sizeof.put(Width.W32, sz32);
78          this.sizeof.put(Width.W64, sz32);
79      }
80  
81      public int sizeof32(){ return sizeof.get(Width.W32); }
82      public int sizeof64(){ return sizeof.get(Width.W64); }
83  
84      protected abstract boolean equals2(NType nt);
85  
86      private String _toString;
87      @Override public String toString(){ return _toString != null ? _toString : (_toString = NTypePrinter.inst().print(this)); }
88      @Override public boolean equals(Object o) {
89          return o!=null && (o==this || (getClass().isInstance(o)
90                  && this.sizeof.equals(((NType) o).sizeof)
91                  && equals2((NType) o)));
92      }
93      public int compareTo(NType o){ return toString().compareTo(o.toString()); }
94  
95      // ** NType subclasses
96      // -------------------
97  
98      public static class NBitfield extends NType{
99          public final int length;
100 
101         public NBitfield(int length){
102             super(-1, -1);
103             this.length = length;
104         }
105 
106         @Override protected boolean equals2(NType nt) { return ((NBitfield) nt).length == length; }
107         @Override public int hashCode() { return Integer.valueOf(length).hashCode(); }
108     }
109 
110     public static class NPrimitive extends NType{
111         public static Collection<Character> CODES = Arrays.asList(
112                 'B', 'c', 'C', 's', 'S', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd');
113 
114         public final char type;
115 
116         protected NPrimitive(char c){
117             super(PrimitiveCoderDescriptor.createCoderDescriptorFor(c).getCoder().sizeof(Width.W32),
118                     PrimitiveCoderDescriptor.createCoderDescriptorFor(c).getCoder().sizeof(Width.W64));
119             type = c;
120         }
121         private static final Map<Character, NPrimitive> cache = new HashMap<Character, NPrimitive>();
122         public static final NPrimitive inst(final char c){
123             if(!cache.containsKey(c)) cache.put(c, new NPrimitive(c));
124             return cache.get(c);
125         }
126 
127         @Override protected boolean equals2(NType nt) { return ((NPrimitive)nt).type == type; }
128         @Override public int hashCode() { return Character.valueOf(type).hashCode(); }
129     }
130 
131     public static class NVoid extends NType{
132         protected NVoid(){ super(); }
133         private final static NVoid INST = new NVoid();
134         public static NVoid inst() { return INST; }
135 
136         @Override protected boolean equals2(NType nt) { return true; }
137     }
138 
139     public static class NPointer extends NType{
140         public final NType subject;
141 
142         public NPointer(NType subject){
143             super(4, 8);
144             QA.nonNull(subject);
145             this.subject = subject;
146         }
147 
148         @Override protected boolean equals2(NType nt) { return ((NPointer)nt).subject.equals(subject); }
149         @Override public int hashCode() { return subject.hashCode(); }
150     }
151 
152     public static class NObject extends NType{
153         protected NObject(){ super(4, 8); }
154         private final static NObject INST = new NObject();
155         public static NObject inst() { return INST; }
156 
157         @Override protected boolean equals2(NType nt) { return true; }
158     }
159 
160     public static class NClass extends NType{
161         protected NClass(){ super(4, 8); }
162         private final static NClass INST = new NClass();
163         public static NClass inst() { return INST; }
164 
165         @Override protected boolean equals2(NType nt) { return true; }
166     }
167 
168     public static class NSelector extends NType{
169         protected NSelector(){ super(4, 8); }
170         private final static NSelector INST = new NSelector();
171         public static NSelector inst() { return INST; }
172 
173         @Override protected boolean equals2(NType nt) { return true;}
174     }
175 
176     public static class NField{
177         public final Map<Width,Integer> offset;
178         public final String name;
179         public final NType type;
180 
181         public NField(String name, NType type, Map<Width,Integer> offset) {
182             QA.nonNull(name, type, offset);
183             this.name = name;
184             this.type = type;
185             this.offset = offset;
186         }
187 
188         public NField(String name, NType type) {
189             this(name, type, new HashMap());
190         }
191 
192         public int offset32(){ return offset.get(Width.W32); }
193         public int offset64(){ return offset.get(Width.W64); }
194 
195         @Override public int hashCode() { return name.hashCode() + type.hashCode(); }
196         @Override public boolean equals(Object o) {
197             return o!=null && (o==this ||
198                     (o instanceof NField
199                             && this.offset.equals(((NField) o).offset)
200                             && ((NField) o).name.equals(this.name)
201                             && ((NField) o).type.equals(this.type)));
202         }
203     }
204 
205     public static class NStruct extends NType{
206         public final String name;
207         public final List<NField> fields;
208 
209         public NStruct(String name, List<NField> fields, Map<Width,Integer> sizeof){
210             super(sizeof);
211             QA.nonNull(name, fields);
212             this.name = name;
213             this.fields = fields;
214         }
215 
216         public NStruct(String name, List<NField> fields){
217             super();
218             QA.nonNull(name, fields);
219             this.name = name;
220             this.fields = fields;
221         }
222 
223         @Override protected boolean equals2(NType nt) {
224             return ((NStruct)nt).name.equals(name) && ((NStruct)nt).fields.equals(fields);
225         }
226 
227         @Override public int hashCode() { return name.hashCode() + fields.hashCode(); }
228     }
229 
230     // A Union is like a Struct, but the offset of every field is 0.
231     public static class NUnion extends NStruct{
232         public NUnion(String concreteName, List<NField> fields){
233             super(concreteName, fields);
234             assert Fp.all(hasZeroOffsets, fields) : Utils.joinWComma(fields);
235         }
236 
237         public NUnion(String name, List<NField> fields, Map<Width,Integer> sizeof) {
238             super(name, fields, sizeof);
239             assert Fp.all(hasZeroOffsets, fields) : Utils.joinWComma(fields);
240         }
241 
242         public static final Fp.Map1<NField,Boolean> hasZeroOffsets = new Fp.Map1<NField,Boolean>(){
243             public Boolean apply(NField a) {
244                 for(int i : a.offset.values())
245                     if(i != 0)
246                         return false;
247                 return true;
248             }};
249         public static final Fp.Map1<NField,NField> zeroOffsets = new Fp.Map1<NField,NField>(){
250             public NField apply(NField a) {
251                 Map<Width,Integer> off = new HashMap();
252                 for(Width w : a.offset.keySet())
253                     off.put(w, 0);
254                 return new NField(a.name, a.type, off);
255             }};
256     }
257 
258     public static class NArray extends NType{
259         public final int length;
260         public final NType type;
261 
262         public NArray(int length, NType type){
263             QA.nonNull(type);
264             this.length = length;
265             this.type = type;
266         }
267 
268         @Override protected boolean equals2(NType nt) { return ((NArray)nt).length == length && ((NArray)nt).type.equals(type); }
269         @Override public int hashCode(){ return Long.valueOf(length).hashCode() + type.hashCode(); }
270     }
271 
272     // Seems to be used for callbacks
273     public static class NUnknown extends NType{
274         protected NUnknown(){ super(); }
275         private final static NUnknown INST = new NUnknown();
276         public static NUnknown inst() { return INST; }
277 
278         @Override protected boolean equals2(NType nt) { return true;}
279     }
280 }