/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2011.
*/
package x10.rtt;
import x10.core.Any;
import x10.serialization.X10JavaDeserializer;
import x10.serialization.X10JavaSerializable;
import x10.serialization.X10JavaSerializer;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
public final class ParameterizedType<T> implements Type<T>, X10JavaSerializable {
private static final long serialVersionUID = 1L;
public RuntimeType<T> rawType;
public Type<?>[] actualTypeArguments;
RuntimeType<T> getRawType() {
return rawType;
}
Type<?>[] getActualTypeArguments() {
return actualTypeArguments;
}
private ParameterizedType(RuntimeType<T> rawType, Type<?>... actualTypeArguments) {
this.rawType = rawType;
this.actualTypeArguments = actualTypeArguments;
}
private static final boolean useCache = true;
private static final ConcurrentHashMap<RuntimeType<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>> typeCache1 = new ConcurrentHashMap<RuntimeType<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>>();
public static <T> ParameterizedType/*<T>*/ make(RuntimeType<T> rawType, Type<?> actualTypeArgument0) {
if (useCache && rawType != null && actualTypeArgument0 != null
// N.B. guard from NPE with recursive type. see XTENLANG_423.W[U], which extends Z[W[U]], causes NPE for hashCode.
&& (!(actualTypeArgument0 instanceof ParameterizedType) || ((ParameterizedType<?>) actualTypeArgument0).rawType != null)
) {
ConcurrentHashMap<Type<?>, ParameterizedType<?>> typeCache10 = typeCache1.get(rawType);
if (typeCache10 == null) {
ConcurrentHashMap<Type<?>, ParameterizedType<?>> typeCache10_;
typeCache10_ = new ConcurrentHashMap<Type<?>, ParameterizedType<?>>();
typeCache10 = typeCache1.putIfAbsent(rawType, typeCache10_);
if (typeCache10 == null) typeCache10 = typeCache10_;
}
ParameterizedType type = typeCache10.get(actualTypeArgument0);
if (type == null) {
ParameterizedType type_;
type_ = new ParameterizedType<T>(rawType, actualTypeArgument0);
type = typeCache10.putIfAbsent(actualTypeArgument0, type_);
if (type == null) type = type_;
}
return type;
} else {
return new ParameterizedType<T>(rawType, actualTypeArgument0);
}
}
private static final ConcurrentHashMap<RuntimeType<?>, ConcurrentHashMap<Type<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>>> typeCache2 =
new ConcurrentHashMap<RuntimeType<?>, ConcurrentHashMap<Type<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>>>();
public static <T> ParameterizedType/*<T>*/ make(RuntimeType<T> rawType, Type<?> actualTypeArgument0, Type<?> actualTypeArgument1) {
if (useCache && rawType != null && actualTypeArgument0 != null && actualTypeArgument1 != null
// N.B. guard from NPE with recursive type. see XTENLANG_423.W[U], which extends Z[W[U]], causes NPE for hashCode.
&& (!(actualTypeArgument0 instanceof ParameterizedType) || ((ParameterizedType<?>) actualTypeArgument0).rawType != null)
&& (!(actualTypeArgument1 instanceof ParameterizedType) || ((ParameterizedType<?>) actualTypeArgument1).rawType != null)
) {
ConcurrentHashMap<Type<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>> typeCache20 = typeCache2.get(rawType);
if (typeCache20 == null) {
ConcurrentHashMap<Type<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>> typeCache20_;
typeCache20_ = new ConcurrentHashMap<Type<?>, ConcurrentHashMap<Type<?>, ParameterizedType<?>>>();
typeCache20 = typeCache2.putIfAbsent(rawType, typeCache20_);
if (typeCache20 == null) typeCache20 = typeCache20_;
}
ConcurrentHashMap<Type<?>, ParameterizedType<?>> typeCache21 = typeCache20.get(actualTypeArgument0);
if (typeCache21 == null) {
ConcurrentHashMap<Type<?>, ParameterizedType<?>> typeCache21_;
typeCache21_ = new ConcurrentHashMap<Type<?>, ParameterizedType<?>>();
typeCache21 = typeCache20.putIfAbsent(actualTypeArgument0, typeCache21_);
if (typeCache21 == null) typeCache21 = typeCache21_;
}
ParameterizedType type = typeCache21.get(actualTypeArgument1);
if (type == null) {
ParameterizedType type_;
type_ = new ParameterizedType<T>(rawType, actualTypeArgument0, actualTypeArgument1);
type = typeCache21.putIfAbsent(actualTypeArgument1, type_);
if (type == null) type = type_;
}
return type;
} else {
return new ParameterizedType<T>(rawType, actualTypeArgument0, actualTypeArgument1);
}
}
public static <T> ParameterizedType/*<T>*/ make(RuntimeType<T> rawType, Type<?>... actualTypeArguments) {
return new ParameterizedType<T>(rawType, actualTypeArguments);
}
// Constructor just for allocation
public ParameterizedType() {
}
public final boolean isAssignableTo(Type<?> superType) {
if (this == superType) return true;
if (superType == Types.ANY) return true;
if (!superType.getJavaClass().isAssignableFrom(rawType.getJavaClass())) {
return false;
}
if (superType instanceof ParameterizedType) {
ParameterizedType<?> pt = (ParameterizedType<?>) superType;
if (pt.getRawType().isAssignableFrom(pt.actualTypeArguments, rawType, actualTypeArguments)) {
return true;
}
}
else if (superType instanceof RuntimeType) {
if (((RuntimeType<?>) superType).isAssignableFrom(null, rawType, actualTypeArguments)) {
return true;
}
}
return false;
}
public boolean hasZero() {
return rawType.hasZero();
}
public boolean isref() {
return rawType.isref();
}
public final boolean isInstance(Object o) {
return rawType.isInstance(o, actualTypeArguments);
}
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ParameterizedType<?>) {
ParameterizedType<?> t = (ParameterizedType<?>) o;
if (!rawType.equals(t.rawType)) {
return false;
}
Type<?>[] t_actualTypeArguments = t.actualTypeArguments;
if (actualTypeArguments.length != t_actualTypeArguments.length) {
return false;
}
for (int i = 0; i < actualTypeArguments.length; i++) {
if (!actualTypeArguments[i].equals(t_actualTypeArguments[i])) {
return false;
}
}
return true;
}
return false;
}
@Override
public final int hashCode() {
return rawType.hashCode();
}
public final int arrayLength(Object array) {
return rawType.arrayLength(array);
}
public final T getArray(Object array, int i) {
return rawType.getArray(array, i);
}
public final Class<?> getJavaClass() {
return rawType.getJavaClass();
}
public final Object makeArray(int dim0) {
return rawType.makeArray(dim0);
}
public final Object makeArray(int dim0, int dim1) {
return rawType.makeArray(dim0, dim1);
}
public final Object makeArray(int dim0, int dim1, int dim2) {
return rawType.makeArray(dim0, dim1, dim2);
}
public final Object makeArray(int dim0, int dim1, int dim2, int dim3) {
return rawType.makeArray(dim0, dim1, dim2, dim3);
}
public final Object makeArray(int... dims) {
return rawType.makeArray(dims);
}
public final void setArray(Object array, int i, T v) {
rawType.setArray(array, i, v);
}
@Override
public final String toString() {
return typeName();
}
// Note: this method does not resolve UnresolvedType at runtime
public final String typeName() {
return typeName(null);
}
private static final String printType(Type<?> t, Object o) {
if (t instanceof UnresolvedType) {
int index = ((UnresolvedType) t).getIndex();
if (index >= 0) {
t = ((Any) o).$getParam(index);
} else {
t = ((Any) o).$getRTT();
}
}
if (t instanceof ParameterizedType) {
return ((ParameterizedType<?>) t).typeName(o);
} else {
return t.typeName();
}
}
public final String typeName(Object o) {
if (rawType instanceof FunType) {
return typeNameForFun(o);
} else if (rawType instanceof VoidFunType) {
return typeNameForVoidFun(o);
} else {
return typeNameForOthers(o);
}
}
// called from Static{Void}FunType.typeName(Object)
public final String typeNameForFun(Object o) {
StringBuilder sb = new StringBuilder();
sb.append("(");
int i;
for (i = 0; i < actualTypeArguments.length - 1; i++) {
if (i != 0) sb.append(",");
sb.append(printType(actualTypeArguments[i], o));
}
sb.append(")=>");
sb.append(printType(actualTypeArguments[i], o));
return sb.toString();
}
public final String typeNameForVoidFun(Object o) {
StringBuilder sb = new StringBuilder();
sb.append("(");
if (actualTypeArguments != null && actualTypeArguments.length > 0) {
for (int i = 0; i < actualTypeArguments.length; i++) {
if (i != 0) sb.append(",");
sb.append(printType(actualTypeArguments[i], o));
}
}
sb.append(")=>void");
return sb.toString();
}
public final String typeNameForOthers(Object o) {
StringBuilder sb = new StringBuilder();
sb.append(rawType.typeName());
sb.append("[");
for (int i = 0; i < actualTypeArguments.length; i ++) {
if (i != 0) sb.append(",");
sb.append(printType(actualTypeArguments[i], o));
}
sb.append("]");
return sb.toString();
}
public void $_serialize(X10JavaSerializer serializer) throws IOException {
serializer.write(rawType);
serializer.write(actualTypeArguments);
}
public static X10JavaSerializable $_deserializer(X10JavaDeserializer deserializer) throws IOException {
ParameterizedType pt = new ParameterizedType();
deserializer.record_reference(pt);
return $_deserialize_body(pt, deserializer);
}
public static X10JavaSerializable $_deserialize_body(ParameterizedType pt, X10JavaDeserializer deserializer) throws IOException {
RuntimeType rawType = (RuntimeType) deserializer.readRef();
pt.rawType = rawType;
int length = deserializer.readInt();
Type[] actualTypeArguments = new Type[length];
deserializer.readArray(actualTypeArguments);
pt.actualTypeArguments = actualTypeArguments;
return pt;
}
}