/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.apple.internal.jobjc.generator.model.types;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.apple.internal.jobjc.generator.Utils;
import com.apple.internal.jobjc.generator.model.coders.PrimitiveCoderDescriptor;
import com.apple.internal.jobjc.generator.utils.Fp;
import com.apple.internal.jobjc.generator.utils.NTypePrinter;
import com.apple.internal.jobjc.generator.utils.QA;
import com.apple.jobjc.JObjCRuntime.Width;
/**
* NType (Native Type) bridges the type and type64 attributes in BridgeSupport.
*
* For example:
*
* <pre>
* type="c" // BridgeSupport attribute
* (NPrimitive type: 'c') // Java object (in sexp form here, for readability)
*
* type="^v"
* (NPointer subject: (NVoid))
*
* type="{foo_t="a"c"b"b8"c"[32^v]}"
* (NStruct
* name: "foo_t"
* fields:
* (List<NField>
* 0: (NField name:"a" type: (NPrimitive type: 'c'))
* 1: (NField name:"b" type: (NBitfield size: 8))
* 2: (NField name:"c" type:
* (NArray size: 32
* type: (NPointer subject: (NVoid))))))
* </pre>
*/
public abstract class NType implements Comparable<NType>{
public final Map<Width, Integer> sizeof;
public NType(Map<Width, Integer> sizeof) {
this.sizeof = sizeof;
}
public NType(){
this(new HashMap<Width, Integer>());
}
public NType(int sz32, int sz64){
this();
this.sizeof.put(Width.W32, sz32);
this.sizeof.put(Width.W64, sz32);
}
public int sizeof32(){ return sizeof.get(Width.W32); }
public int sizeof64(){ return sizeof.get(Width.W64); }
protected abstract boolean equals2(NType nt);
private String _toString;
@Override public String toString(){ return _toString != null ? _toString : (_toString = NTypePrinter.inst().print(this)); }
@Override public boolean equals(Object o) {
return o!=null && (o==this || (getClass().isInstance(o)
&& this.sizeof.equals(((NType) o).sizeof)
&& equals2((NType) o)));
}
public int compareTo(NType o){ return toString().compareTo(o.toString()); }
// ** NType subclasses
// -------------------
public static class NBitfield extends NType{
public final int length;
public NBitfield(int length){
super(-1, -1);
this.length = length;
}
@Override protected boolean equals2(NType nt) { return ((NBitfield) nt).length == length; }
@Override public int hashCode() { return Integer.valueOf(length).hashCode(); }
}
public static class NPrimitive extends NType{
public static Collection<Character> CODES = Arrays.asList(
'B', 'c', 'C', 's', 'S', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd');
public final char type;
protected NPrimitive(char c){
super(PrimitiveCoderDescriptor.createCoderDescriptorFor(c).getCoder().sizeof(Width.W32),
PrimitiveCoderDescriptor.createCoderDescriptorFor(c).getCoder().sizeof(Width.W64));
type = c;
}
private static final Map<Character, NPrimitive> cache = new HashMap<Character, NPrimitive>();
public static final NPrimitive inst(final char c){
if(!cache.containsKey(c)) cache.put(c, new NPrimitive(c));
return cache.get(c);
}
@Override protected boolean equals2(NType nt) { return ((NPrimitive)nt).type == type; }
@Override public int hashCode() { return Character.valueOf(type).hashCode(); }
}
public static class NVoid extends NType{
protected NVoid(){ super(); }
private final static NVoid INST = new NVoid();
public static NVoid inst() { return INST; }
@Override protected boolean equals2(NType nt) { return true; }
}
public static class NPointer extends NType{
public final NType subject;
public NPointer(NType subject){
super(4, 8);
QA.nonNull(subject);
this.subject = subject;
}
@Override protected boolean equals2(NType nt) { return ((NPointer)nt).subject.equals(subject); }
@Override public int hashCode() { return subject.hashCode(); }
}
public static class NObject extends NType{
protected NObject(){ super(4, 8); }
private final static NObject INST = new NObject();
public static NObject inst() { return INST; }
@Override protected boolean equals2(NType nt) { return true; }
}
public static class NClass extends NType{
protected NClass(){ super(4, 8); }
private final static NClass INST = new NClass();
public static NClass inst() { return INST; }
@Override protected boolean equals2(NType nt) { return true; }
}
public static class NSelector extends NType{
protected NSelector(){ super(4, 8); }
private final static NSelector INST = new NSelector();
public static NSelector inst() { return INST; }
@Override protected boolean equals2(NType nt) { return true;}
}
public static class NField{
public final Map<Width,Integer> offset;
public final String name;
public final NType type;
public NField(String name, NType type, Map<Width,Integer> offset) {
QA.nonNull(name, type, offset);
this.name = name;
this.type = type;
this.offset = offset;
}
public NField(String name, NType type) {
this(name, type, new HashMap());
}
public int offset32(){ return offset.get(Width.W32); }
public int offset64(){ return offset.get(Width.W64); }
@Override public int hashCode() { return name.hashCode() + type.hashCode(); }
@Override public boolean equals(Object o) {
return o!=null && (o==this ||
(o instanceof NField
&& this.offset.equals(((NField) o).offset)
&& ((NField) o).name.equals(this.name)
&& ((NField) o).type.equals(this.type)));
}
}
public static class NStruct extends NType{
public final String name;
public final List<NField> fields;
public NStruct(String name, List<NField> fields, Map<Width,Integer> sizeof){
super(sizeof);
QA.nonNull(name, fields);
this.name = name;
this.fields = fields;
}
public NStruct(String name, List<NField> fields){
super();
QA.nonNull(name, fields);
this.name = name;
this.fields = fields;
}
@Override protected boolean equals2(NType nt) {
return ((NStruct)nt).name.equals(name) && ((NStruct)nt).fields.equals(fields);
}
@Override public int hashCode() { return name.hashCode() + fields.hashCode(); }
}
// A Union is like a Struct, but the offset of every field is 0.
public static class NUnion extends NStruct{
public NUnion(String concreteName, List<NField> fields){
super(concreteName, fields);
assert Fp.all(hasZeroOffsets, fields) : Utils.joinWComma(fields);
}
public NUnion(String name, List<NField> fields, Map<Width,Integer> sizeof) {
super(name, fields, sizeof);
assert Fp.all(hasZeroOffsets, fields) : Utils.joinWComma(fields);
}
public static final Fp.Map1<NField,Boolean> hasZeroOffsets = new Fp.Map1<NField,Boolean>(){
public Boolean apply(NField a) {
for(int i : a.offset.values())
if(i != 0)
return false;
return true;
}};
public static final Fp.Map1<NField,NField> zeroOffsets = new Fp.Map1<NField,NField>(){
public NField apply(NField a) {
Map<Width,Integer> off = new HashMap();
for(Width w : a.offset.keySet())
off.put(w, 0);
return new NField(a.name, a.type, off);
}};
}
public static class NArray extends NType{
public final int length;
public final NType type;
public NArray(int length, NType type){
QA.nonNull(type);
this.length = length;
this.type = type;
}
@Override protected boolean equals2(NType nt) { return ((NArray)nt).length == length && ((NArray)nt).type.equals(type); }
@Override public int hashCode(){ return Long.valueOf(length).hashCode() + type.hashCode(); }
}
// Seems to be used for callbacks
public static class NUnknown extends NType{
protected NUnknown(){ super(); }
private final static NUnknown INST = new NUnknown();
public static NUnknown inst() { return INST; }
@Override protected boolean equals2(NType nt) { return true;}
}
}