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 }