com.redhat.ceylon.compiler.java.Util Maven / Gradle / Ivy
package com.redhat.ceylon.compiler.java;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import ceylon.language.ArraySequence;
import ceylon.language.AssertionError;
import ceylon.language.Callable;
import ceylon.language.Finished;
import ceylon.language.Integer;
import ceylon.language.Iterable;
import ceylon.language.Iterator;
import ceylon.language.Null;
import ceylon.language.OverflowException;
import ceylon.language.Ranged;
import ceylon.language.Sequence;
import ceylon.language.Sequential;
import ceylon.language.Tuple;
import ceylon.language.empty_;
import ceylon.language.finished_;
import ceylon.language.sequence_;
import com.redhat.ceylon.compiler.java.language.AbstractArrayIterable;
import com.redhat.ceylon.compiler.java.language.ObjectArrayIterable;
import com.redhat.ceylon.compiler.java.metadata.Class;
import com.redhat.ceylon.compiler.java.metadata.Name;
import com.redhat.ceylon.compiler.java.metadata.TypeInfo;
import com.redhat.ceylon.compiler.java.runtime.metamodel.Metamodel;
import com.redhat.ceylon.compiler.java.runtime.model.TypeDescriptor;
import com.redhat.ceylon.model.cmr.ArtifactResult;
/**
* Helper class for generated Ceylon code that needs to call implementation logic.
*
* @author Stéphane Épardaud
*/
public class Util {
static {
// Make sure the rethrow class is loaded if ever we need to rethrow
// errors such as StackOverflowError, otherwise if we have to rethrow it
// we will not be able to load that class since we've ran out of stack
// see https://github.com/ceylon/ceylon.language/issues/311
ceylon.language.impl.rethrow_.class.toString();
}
private static final int INIT_ARRAY_SIZE = 10;
private static final Object[] NO_ELEMENTS = new Object[0];
public static String declClassName(String name) {
return name.replace("::", ".");
}
public static void loadModule(String name, String version,
ArtifactResult result, ClassLoader classLoader) {
Metamodel.loadModule(name, version, result, classLoader);
}
public static boolean isReified(java.lang.Object o, TypeDescriptor type) {
return Metamodel.isReified(o, type);
}
private static HashMap, Class> classCache
= new HashMap<>();
private static Class getClassAnnotationForIdentifiableOrBasic(
final java.lang.Class extends Object> klass) {
if (classCache.containsKey(klass)) {
return classCache.get(klass);
}
Class classAnnotation = klass.getAnnotation(Class.class);
if(classAnnotation != null) {
classCache.put(klass, classAnnotation);
return classAnnotation;
} else if (klass != null && klass != java.lang.Object.class) {
// else keep looking up
Class c = getClassAnnotationForIdentifiableOrBasic(klass.getSuperclass());
classCache.put(klass, c);
return c;
} else {
return null;
}
}
/**
* Returns true if the given object satisfies ceylon.language.Identifiable
*/
public static boolean isIdentifiable(java.lang.Object o) {
if(o == null)
return false;
return isIdentifiable(o.getClass());
}
public static boolean isIdentifiable(java.lang.Class> klazz) {
Class classAnnotation = getClassAnnotationForIdentifiableOrBasic(klazz);
// unless marked as NOT identifiable, every instance is Identifiable
return classAnnotation != null ? classAnnotation.identifiable() : true;
}
/**
* Returns true if the given object extends ceylon.language.Basic
*/
public static boolean isBasic(java.lang.Object o) {
if (o == null)
return false;
return isBasic(o.getClass());
}
public static boolean isBasic(java.lang.Class> klazz) {
Class classAnnotation = getClassAnnotationForIdentifiableOrBasic(klazz);
// unless marked as NOT identifiable, every instance is Basic
return classAnnotation != null ? classAnnotation.basic() : true;
}
//
// Java variadic conversions
/** Return the size of the given iterable if we know it can be computed
* efficiently (typically without iterating the iterable)
*/
private static int fastIterableSize(Iterable extends T, ?> iterable) {
if (iterable instanceof Sequential
|| iterable instanceof AbstractArrayIterable) {
return toInt(iterable.getSize());
}
return -1;
}
@SuppressWarnings("unchecked")
private static void fillArray(T[] array, int offset,
Iterable extends T, ?> iterable) {
Iterator> iterator = iterable.iterator();
Object o;
int index = offset;
while ((o = iterator.next()) != finished_.get_()) {
array[index] = (T) o;
index++;
}
}
/**
* Base class for a family of builders for Java native arrays.
*
* Encapsulation has been sacraficed for efficiency.
*
* @param an array type such as int[]
*/
public static abstract class ArrayBuilder {
private static final int MIN_CAPACITY = 5;
private static final int MAX_CAPACITY = java.lang.Integer.MAX_VALUE;
/** The number of elements in {@link #array}. This is always <= {@link #capacity} */
protected int size;
/** The length of {@link #array} */
protected int capacity;
/** The array */
protected A array;
ArrayBuilder(int initialSize) {
capacity = Math.max(initialSize, MIN_CAPACITY);
array = allocate(capacity);
size = 0;
}
/** Append all the elements in the given array */
final void appendArray(A elements) {
int increment = size(elements);
int newsize = this.size + increment;
ensure(newsize);
System.arraycopy(elements, 0, array, this.size, increment);
this.size = newsize;
}
/** Ensure the {@link #array} is as big, or bigger than the given capacity */
protected final void ensure(int requestedCapacity) {
if (this.capacity >= requestedCapacity) {
return;
}
int newcapacity = requestedCapacity+(requestedCapacity>>1);
if (newcapacity < MIN_CAPACITY) {
newcapacity = MIN_CAPACITY;
} else if (newcapacity > MAX_CAPACITY) {
newcapacity = requestedCapacity;
if (newcapacity > MAX_CAPACITY) {
throw new AssertionError("can't allocate array bigger than " + MAX_CAPACITY);
}
}
A newArray = allocate(newcapacity);
System.arraycopy(this.array, 0, newArray, 0, this.size);
this.capacity = newcapacity;
this.array = newArray;
}
/**
* Allocate and return an array of the given size
*/
protected abstract A allocate(int size);
/**
* The size of the given array
*/
protected abstract int size(A array);
/**
* Returns an array of exactly the right size to contain all the
* appended elements.
*/
A build() {
if (this.capacity == this.size) {
return array;
}
A result = allocate(this.size);
System.arraycopy(this.array, 0, result, 0, this.size);
return result;
}
}
/**
* An array builder whose result is an {@code Object[]}.
* @see ReflectingObjectArrayBuilder
*/
static final class ObjectArrayBuilder
extends ArrayBuilder
© 2015 - 2024 Weber Informatics LLC | Privacy Policy