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.ArrayList; 28 import java.util.List; 29 import java.util.HashMap; 30 import java.util.Map; 31 32 import com.apple.internal.jobjc.generator.model.types.NType.NObject; 33 import com.apple.internal.jobjc.generator.model.types.NType.NPointer; 34 import com.apple.internal.jobjc.generator.model.types.NType.NPrimitive; 35 import com.apple.internal.jobjc.generator.model.types.NType.NVoid; 36 import com.apple.internal.jobjc.generator.model.types.NType.NStruct; 37 import com.apple.internal.jobjc.generator.model.types.NType.NField; 38 import com.apple.internal.jobjc.generator.utils.NTypeMerger; 39 import com.apple.internal.jobjc.generator.utils.QA; 40 import com.apple.internal.jobjc.generator.utils.Fp.Pair; 41 import com.apple.internal.jobjc.generator.utils.NTypeMerger.MergeFailed; 42 43 public class Type implements Comparable<Type>{ 44 public static Type VOID = Type.getType("void", NVoid.inst(), null); 45 public static Type VOID_PTR = Type.getType("void*", new NPointer(NVoid.inst()), null); 46 47 final public String name; 48 final public NType type32; 49 final public NType type64; 50 51 // HACK BS bug where some types have inconsistent definitions in the metadata, 52 // e.g. (l / i) in some places and just (l) (and thus (l / l)) in others. 53 // This is a mapping from the type name to a Type object with the correct definition. 54 private static final Map<String, Type> exceptions; 55 static { 56 exceptions = new HashMap<String, Type>(); 57 exceptions.put("OSStatus", getType("OSStatus", new NPrimitive('l'), new NPrimitive('i'))); // (l / i) vs. (l) 58 exceptions.put("CGFloat", getType("CGFloat", new NPrimitive('f'), new NPrimitive('d'))); // (f / d) vs. (f) 59 exceptions.put("NSRect", getType("NSRect", getNSRectType(), getCGRectType())); // ({{_NSPoint}{_NSSize}} / {{CGPoint}{CGSize}}) vs. ({{_NSPoint}{_NSSize}}) 60 exceptions.put("NSPoint", getType("NSPoint", getNSPointType(), getCGPointType())); // (_NSPoint / CGPoint) vs. (_NSPoint) 61 exceptions.put("NSSize", getType("NSSize", getNSSizeType(), getCGSizeType())); // (_NSSize / CGSize) vs. (_NSSize) 62 exceptions.put("NSInteger", getType("NSInteger", new NPrimitive('i'), new NPrimitive('q'))); // (i / q) vs. (i) 63 exceptions.put("NSPointArray", getType("NSPointArray", new NPointer(getNSPointType()), new NPointer(getCGPointType()))); // (^_NSPoint / ^CGPoint) vs. (^_NSPoint) 64 exceptions.put("NSMultibyteGlyphPacking", getType("NSMultibyteGlyphPacking", new NPrimitive('I'), new NPrimitive('Q'))); // (I / Q) vs. (I) 65 exceptions.put("CFTypeRef", getType("CFTypeRef", new NPointer(NVoid.inst()), new NPointer(NVoid.inst()))); // (^v, ^v) vs. (@, @) 66 } 67 68 public static Type getType(final String name, final NType t32, final NType t64){ 69 return TypeCache.inst().pingType(new Type(name, t32, t64)); 70 } 71 72 private Type(final String name, final NType t32, final NType t64) { 73 QA.nonNull(t32); 74 this.name = cleanName(name); 75 this.type32 = t32; 76 this.type64 = t64 == null || t32.equals(t64) ? t32 : t64; 77 } 78 79 private JType _getJType; 80 public JType getJType() { 81 return _getJType!=null ? _getJType : (_getJType = TypeToJType.inst().getJTypeFor(TypeCache.inst().pingType(this))); 82 } 83 84 private String _toString; 85 @Override public String toString() { 86 return _toString != null ? _toString : (_toString = name + " " + new Pair(type32, type64).toString()); 87 } 88 89 @Override public boolean equals(Object o){ 90 if(o==null || !(o instanceof Type)) return false; 91 Type t = (Type) o; 92 return QA.bothNullOrEquals(t.name, this.name) 93 && t.type32.equals(this.type32) 94 && t.type64.equals(this.type64); 95 } 96 97 @Override public int hashCode(){ 98 return (name == null ? 0 : name.hashCode()) 99 + type32.hashCode() + type64.hashCode(); 100 } 101 102 public int compareTo(Type o) { return toString().compareTo(o.toString()); } 103 104 public static Type merge(Type a, Type b) throws MergeFailed{ 105 if(a!=null && b==null) return a; 106 if(a==null && b!=null) return b; 107 if(QA.bothNullOrEquals(a, b)) return a; 108 if (exceptions.containsKey(a.name)) return exceptions.get(a.name); // HACK BS bug 109 if(a.name != null && b.name != null && !a.name.equals(b.name)){ 110 System.out.println("Merging:"); 111 System.out.println("\ta.....: " + a.toString()); 112 System.out.println("\tb.....: " + b.toString()); 113 } 114 final Type merged = new Type(NTypeMerger.inst().mergeName(a.name, b.name), 115 NTypeMerger.inst().merge(a.type32, b.type32), 116 NTypeMerger.inst().merge(a.type64, b.type64)); 117 if(a.name != null && b.name != null && !a.name.equals(b.name)){ 118 System.out.println("\tmerged: " + merged.toString()); 119 } 120 return merged; 121 } 122 123 // HACK BS bug where sometimes the name is declared as "id <A, B..." and sometimes it's "id<A,B..." 124 public static String cleanName(String name){ return name == null ? null : name.replaceAll("\\s+", ""); } 125 126 // HACK BS bug where NSRect has inconsistent definitions in the metadata 127 // Methods return NTypes created according to the correct definitions below: 128 // 129 // {_NSRect="origin"{_NSPoint="x"f"y"f}"size"{_NSSize="width"f"height"f}} *** 32-bit 130 // {CGRect="origin"{CGPoint="x"d"y"d}"size"{CGSize="width"d"height"d}} *** 64-bit 131 132 private static NType getCGRectType() { 133 List<NField> fields = new ArrayList<NField>(); 134 fields.add(new NField("origin", getCGPointType())); 135 fields.add(new NField("size", getCGSizeType())); 136 return new NStruct("CGRect", fields); 137 } 138 139 private static NType getNSRectType() { 140 List<NField> fields = new ArrayList<NField>(); 141 fields.add(new NField("origin", getNSPointType())); 142 fields.add(new NField("size", getNSSizeType())); 143 return new NStruct("_NSRect", fields); 144 } 145 146 private static NType getCGPointType() { 147 List<NField> fields = new ArrayList<NField>(); 148 fields.add(new NField("x", new NPrimitive('d'))); 149 fields.add(new NField("y", new NPrimitive('d'))); 150 return new NStruct("CGPoint", fields); 151 } 152 153 private static NType getNSPointType() { 154 List<NField> fields = new ArrayList<NField>(); 155 fields.add(new NField("x", new NPrimitive('f'))); 156 fields.add(new NField("y", new NPrimitive('f'))); 157 return new NStruct("_NSPoint", fields); 158 } 159 160 private static NType getCGSizeType() { 161 List<NField> fields = new ArrayList<NField>(); 162 fields.add(new NField("width", new NPrimitive('d'))); 163 fields.add(new NField("height", new NPrimitive('d'))); 164 return new NStruct("CGSize", fields); 165 } 166 167 private static NType getNSSizeType() { 168 List<NField> fields = new ArrayList<NField>(); 169 fields.add(new NField("width", new NPrimitive('f'))); 170 fields.add(new NField("height", new NPrimitive('f'))); 171 return new NStruct("_NSSize", fields); 172 } 173 }