null if none */
REXP attr;
/** content of the xpression - its object type is dependent of {@link #Xt} */
Object cont;
/** cached binary length; valid only if positive */
long cachedBinaryLength=-1;
/** construct a new, empty (NULL) expression w/o attribute */
public REXP() { Xt=0; attr=null; cont=null; }
/** construct a new xpression of type t and content o, but no attribute
@param t xpression type (XT_...)
@param o content */
public REXP(int t, Object o) {
Xt=t; cont=o; attr=null;
}
/** construct a new xpression of type t, content o and attribute at
@param t xpression type
@param o content
@param at attribute */
public REXP(int t, Object o, REXP at) {
Xt=t; cont=o; attr=at;
}
/** construct a new xpression of type XT_ARRAY_DOUBLE and content val
@param val array of doubles to store in the REXP */
public REXP(double[] val) {
this(XT_ARRAY_DOUBLE,val);
}
/** construct a new xpression of type XT_ARRAY_INT and content val
@param val array of integers to store in the REXP */
public REXP(int[] val) {
this(XT_ARRAY_INT,val);
}
/** construct a new xpression of type XT_ARRAY_INT and content val
@param val array of integers to store in the REXP */
public REXP(String[] val) {
this(XT_ARRAY_STR,val);
}
/** get attribute of the REXP. In R every object can have attached attribute xpression. Some more complex structures such as classes are built that way.
@return attribute xpression or null if there is none associated */
public REXP getAttribute() {
return attr;
}
/** get raw content. Use as... methods to retrieve contents of known type.
@return content of the REXP */
public Object getContent() {
return cont;
}
/** get xpression type (see XT_.. constants) of the content. It defines the type of the content object.
@return xpression type */
public int getType() {
return Xt;
}
/** parses byte buffer for binary representation of xpressions - read one xpression slot (descends recursively for aggregated xpressions such as lists, vectors etc.)
@param x xpression object to store the parsed xpression in
@param buf buffer containing the binary representation
@param o offset in the buffer to start at
@return position just behind the parsed xpression. Can be use for successive calls to {@link #parseREXP} if more than one expression is stored in the binary array. */
public static int parseREXP(REXP x, byte[] buf, int o) {
int xl=Rtalk.getLen(buf,o);
boolean hasAtt=((buf[o]&128)!=0);
boolean isLong=((buf[o]&64)!=0);
int xt=(int)(buf[o]&63);
//System.out.println("parseREXP: type="+xt+", len="+xl+", hasAtt="+hasAtt+", isLong="+isLong);
if (isLong) o+=4;
o+=4;
int eox=o+xl;
x.Xt=xt; x.attr=null;
if (hasAtt) o=parseREXP(x.attr=new REXP(),buf,o);
if (xt==XT_NULL) {
x.cont=null; return o;
};
if (xt==XT_DOUBLE) {
long lr=Rtalk.getLong(buf,o);
x.cont=new Double(Double.longBitsToDouble(lr));
o+=8;
if (o!=eox) {
System.out.println("Warning: double SEXP size mismatch\n");
o=eox;
};
return o;
}
if (xt==XT_ARRAY_DOUBLE) {
int as=(eox-o)/8,i=0;
double[] d=new double[as];
while (oPlease note that currently only XT_[ARRAY_]INT, XT_[ARRAY_]DOUBLE and XT_[ARRAY_]STR are supported! All other types will be stored as SEXP of the length 0 without any contents.
@param buf buffer to store the REXP binary into
@param off offset of the first byte where to store the REXP
@return the offset of the first byte behind the stored REXP */
public int getBinaryRepresentation(byte[] buf, int off) {
int myl=getBinaryLength();
boolean isLarge=(myl>0xfffff0);
Rtalk.setHdr(Xt,myl-(isLarge?8:4),buf,off);
off+=(isLarge?8:4);
switch (Xt) {
case XT_INT: Rtalk.setInt(asInt(),buf,off); break;
case XT_DOUBLE: Rtalk.setLong(Double.doubleToLongBits(asDouble()),buf,off); break;
case XT_ARRAY_INT:
if (cont!=null) {
int ia[]=(int[])cont;
int i=0, io=off;
while(inull if the REXP is no string */
public String asString() {
return (Xt==XT_STR)?(String)cont:null;
}
/** get content of the REXP as int (if it is one)
@return int content or 0 if the REXP is no integer */
public int asInt() {
if (Xt==XT_ARRAY_INT) {
int i[]=(int[])cont;
if (i!=null && i.length>0) return i[0];
}
return (Xt==XT_INT)?((Integer)cont).intValue():0;
}
/** get content of the REXP as double (if it is one)
@return double content or 0.0 if the REXP is no double */
public double asDouble() {
if (Xt==XT_ARRAY_DOUBLE) {
double d[]=(double[])cont;
if (d!=null && d.length>0) return d[0];
}
return (Xt==XT_DOUBLE)?((Double)cont).doubleValue():0.0;
}
/** get content of the REXP as {@link Vector} (if it is one)
@return Vector content or null if the REXP is no Vector */
public Vector asVector() {
return (Xt==XT_VECTOR)?(Vector)cont:null;
}
/** get content of the REXP as {@link RFactor} (if it is one)
@return {@link RFactor} content or null if the REXP is no factor */
public RFactor asFactor() {
return (Xt==XT_FACTOR)?(RFactor)cont:null;
}
/** get content of the REXP as {@link RList} (if it is one)
@return {@link RList} content or null if the REXP is no list */
public RList asList() {
return (Xt==XT_LIST)?(RList)cont:null;
}
/** get content of the REXP as {@link RBool} (if it is one)
@return {@link RBool} content or null if the REXP is no logical value */
public RBool asBool() {
return (Xt==XT_BOOL)?(RBool)cont:null;
}
/** get content of the REXP as an array of doubles. Array of integers, single double and single integer are automatically converted into such an array if necessary.
@return double[] content or null if the REXP is not a array of doubles or integers */
public double[] asDoubleArray() {
if (Xt==XT_ARRAY_DOUBLE) return (double[])cont;
if (Xt==XT_DOUBLE) {
double[] d=new double[1]; d[0]=asDouble(); return d;
}
if (Xt==XT_INT) {
double[] d=new double[1]; d[0]=((Integer)cont).doubleValue(); return d;
}
if (Xt==XT_ARRAY_INT) {
int[] i=asIntArray();
if (i==null) return null;
double[] d=new double[i.length];
int j=0;
while (jnull if the REXP is not a array of integers */
public int[] asIntArray() {
if (Xt==XT_ARRAY_INT) return (int[])cont;
if (Xt==XT_INT) {
int[] i=new int[1]; i[0]=asInt(); return i;
}
return null;
}
/** returns the content of the REXP as a matrix of doubles (2D-array: m[rows][cols]). This is the same form as used by popular math packages for Java, such as JAMA. This means that following leads to desired results:
Matrix m=new Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").asDoubleMatrix());
@return 2D array of doubles in the form double[rows][cols] or null if the contents is no 2-dimensional matrix of doubles */
public double[][] asDoubleMatrix() {
if (Xt!=XT_ARRAY_DOUBLE || attr==null || attr.Xt!=XT_LIST) return null;
REXP dim=attr.asList().getHead();
if (dim==null || dim.Xt!=XT_ARRAY_INT) return null; // we need dimension attr
int[] ds=dim.asIntArray();
if (ds==null || ds.length!=2) return null; // matrix must be 2-dimensional
int m=ds[0], n=ds[1];
double[][] r=new double[m][n];
double[] ct=asDoubleArray();
if (ct==null) return null;
// R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4)
// we need to copy everything, since we create 2d array from 1d array
int i=0,k=0;
while (i