/* * 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.ArrayList; import java.util.List; import java.util.HashMap; import java.util.Map; import com.apple.internal.jobjc.generator.model.types.NType.NObject; import com.apple.internal.jobjc.generator.model.types.NType.NPointer; import com.apple.internal.jobjc.generator.model.types.NType.NPrimitive; import com.apple.internal.jobjc.generator.model.types.NType.NVoid; import com.apple.internal.jobjc.generator.model.types.NType.NStruct; import com.apple.internal.jobjc.generator.model.types.NType.NField; import com.apple.internal.jobjc.generator.utils.NTypeMerger; import com.apple.internal.jobjc.generator.utils.QA; import com.apple.internal.jobjc.generator.utils.Fp.Pair; import com.apple.internal.jobjc.generator.utils.NTypeMerger.MergeFailed; public class Type implements Comparable<Type>{ public static Type VOID = Type.getType("void", NVoid.inst(), null); public static Type VOID_PTR = Type.getType("void*", new NPointer(NVoid.inst()), null); final public String name; final public NType type32; final public NType type64; // HACK BS bug where some types have inconsistent definitions in the metadata, // e.g. (l / i) in some places and just (l) (and thus (l / l)) in others. // This is a mapping from the type name to a Type object with the correct definition. private static final Map<String, Type> exceptions; static { exceptions = new HashMap<String, Type>(); exceptions.put("OSStatus", getType("OSStatus", new NPrimitive('l'), new NPrimitive('i'))); // (l / i) vs. (l) exceptions.put("CGFloat", getType("CGFloat", new NPrimitive('f'), new NPrimitive('d'))); // (f / d) vs. (f) exceptions.put("NSRect", getType("NSRect", getNSRectType(), getCGRectType())); // ({{_NSPoint}{_NSSize}} / {{CGPoint}{CGSize}}) vs. ({{_NSPoint}{_NSSize}}) exceptions.put("NSPoint", getType("NSPoint", getNSPointType(), getCGPointType())); // (_NSPoint / CGPoint) vs. (_NSPoint) exceptions.put("NSSize", getType("NSSize", getNSSizeType(), getCGSizeType())); // (_NSSize / CGSize) vs. (_NSSize) exceptions.put("NSInteger", getType("NSInteger", new NPrimitive('i'), new NPrimitive('q'))); // (i / q) vs. (i) exceptions.put("NSPointArray", getType("NSPointArray", new NPointer(getNSPointType()), new NPointer(getCGPointType()))); // (^_NSPoint / ^CGPoint) vs. (^_NSPoint) exceptions.put("NSMultibyteGlyphPacking", getType("NSMultibyteGlyphPacking", new NPrimitive('I'), new NPrimitive('Q'))); // (I / Q) vs. (I) exceptions.put("CFTypeRef", getType("CFTypeRef", new NPointer(NVoid.inst()), new NPointer(NVoid.inst()))); // (^v, ^v) vs. (@, @) } public static Type getType(final String name, final NType t32, final NType t64){ return TypeCache.inst().pingType(new Type(name, t32, t64)); } private Type(final String name, final NType t32, final NType t64) { QA.nonNull(t32); this.name = cleanName(name); this.type32 = t32; this.type64 = t64 == null || t32.equals(t64) ? t32 : t64; } private JType _getJType; public JType getJType() { return _getJType!=null ? _getJType : (_getJType = TypeToJType.inst().getJTypeFor(TypeCache.inst().pingType(this))); } private String _toString; @Override public String toString() { return _toString != null ? _toString : (_toString = name + " " + new Pair(type32, type64).toString()); } @Override public boolean equals(Object o){ if(o==null || !(o instanceof Type)) return false; Type t = (Type) o; return QA.bothNullOrEquals(t.name, this.name) && t.type32.equals(this.type32) && t.type64.equals(this.type64); } @Override public int hashCode(){ return (name == null ? 0 : name.hashCode()) + type32.hashCode() + type64.hashCode(); } public int compareTo(Type o) { return toString().compareTo(o.toString()); } public static Type merge(Type a, Type b) throws MergeFailed{ if(a!=null && b==null) return a; if(a==null && b!=null) return b; if(QA.bothNullOrEquals(a, b)) return a; if (exceptions.containsKey(a.name)) return exceptions.get(a.name); // HACK BS bug if(a.name != null && b.name != null && !a.name.equals(b.name)){ System.out.println("Merging:"); System.out.println("\ta.....: " + a.toString()); System.out.println("\tb.....: " + b.toString()); } final Type merged = new Type(NTypeMerger.inst().mergeName(a.name, b.name), NTypeMerger.inst().merge(a.type32, b.type32), NTypeMerger.inst().merge(a.type64, b.type64)); if(a.name != null && b.name != null && !a.name.equals(b.name)){ System.out.println("\tmerged: " + merged.toString()); } return merged; } // HACK BS bug where sometimes the name is declared as "id <A, B..." and sometimes it's "id<A,B..." public static String cleanName(String name){ return name == null ? null : name.replaceAll("\\s+", ""); } // HACK BS bug where NSRect has inconsistent definitions in the metadata // Methods return NTypes created according to the correct definitions below: // // {_NSRect="origin"{_NSPoint="x"f"y"f}"size"{_NSSize="width"f"height"f}} *** 32-bit // {CGRect="origin"{CGPoint="x"d"y"d}"size"{CGSize="width"d"height"d}} *** 64-bit private static NType getCGRectType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("origin", getCGPointType())); fields.add(new NField("size", getCGSizeType())); return new NStruct("CGRect", fields); } private static NType getNSRectType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("origin", getNSPointType())); fields.add(new NField("size", getNSSizeType())); return new NStruct("_NSRect", fields); } private static NType getCGPointType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("x", new NPrimitive('d'))); fields.add(new NField("y", new NPrimitive('d'))); return new NStruct("CGPoint", fields); } private static NType getNSPointType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("x", new NPrimitive('f'))); fields.add(new NField("y", new NPrimitive('f'))); return new NStruct("_NSPoint", fields); } private static NType getCGSizeType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("width", new NPrimitive('d'))); fields.add(new NField("height", new NPrimitive('d'))); return new NStruct("CGSize", fields); } private static NType getNSSizeType() { List<NField> fields = new ArrayList<NField>(); fields.add(new NField("width", new NPrimitive('f'))); fields.add(new NField("height", new NPrimitive('f'))); return new NStruct("_NSSize", fields); } }