blob: 8761c42cc5d46c3580da0c68aed4dad77d8cd5be [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.data.impl;
import java.io.IOException;
import java.io.ObjectInput;
import org.eclipse.statet.jcommons.lang.NonNull;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.rj.data.RArray;
import org.eclipse.statet.rj.data.RCharacterStore;
import org.eclipse.statet.rj.data.RComplexStore;
import org.eclipse.statet.rj.data.RDataFrame;
import org.eclipse.statet.rj.data.RDataUtils;
import org.eclipse.statet.rj.data.RFactorStore;
import org.eclipse.statet.rj.data.RIntegerStore;
import org.eclipse.statet.rj.data.RJIO;
import org.eclipse.statet.rj.data.RLanguage;
import org.eclipse.statet.rj.data.RList;
import org.eclipse.statet.rj.data.RLogicalStore;
import org.eclipse.statet.rj.data.RNumericStore;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.RObjectFactory;
import org.eclipse.statet.rj.data.RRawStore;
import org.eclipse.statet.rj.data.RStore;
import org.eclipse.statet.rj.data.RVector;
@NonNullByDefault
public class DefaultRObjectFactory implements RObjectFactory {
public static final DefaultRObjectFactory INSTANCE= new DefaultRObjectFactory();
public static final RNumericStore NUM_STRUCT_DUMMY= new RNumericStructStore();
public static final RComplexStructStore CPLX_STRUCT_DUMMY= new RComplexStructStore();
public static final RIntegerStructStore INT_STRUCT_DUMMY= new RIntegerStructStore();
public static final RLogicalStructStore LOGI_STRUCT_DUMMY= new RLogicalStructStore();
public static final RRawStructStore RAW_STRUCT_DUMMY= new RRawStructStore();
public static final RCharacterStructStore CHR_STRUCT_DUMMY= new RCharacterStructStore();
private final long storeLengthFixLong= AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
public DefaultRObjectFactory() {
}
/*-- Vector --*/
/**
* Creates an R vector with the given R data store and R class name.
*
* @param data the data store
* @param classname the R class name
* @return the R vector
*/
public <TData extends RStore<?>> RVector<TData> createVector(final TData data, final String classname) {
return new RVectorImpl<>(data, classname);
}
/**
* Creates an R vector with the given R data store.
* <p>
* The vector has the default R class name for data type of the given store.</p>
*
* @param data the data store
* @return the R vector
*/
@Override
public <TData extends RStore<?>> RVector<TData> createVector(final TData data) {
return createVector(data, data.getBaseVectorRClassName());
}
/**
* Creates an R logical vector with values from a Java boolean array.
* <p>
* The vector has the default R class name 'logical'.</p>
* <p>
* Note that the R vector may use the array directly. For values
* see {@link RStore#setLogi(int, boolean)}.</p>
*
* @param logicals the logical values
* @return the R logical vector
*/
public RVector<RLogicalStore> createLogiVector(final boolean [] logicals) {
return createVector(createLogiData(logicals), RObject.CLASSNAME_LOGICAL);
}
/**
* Creates an R logical vector of the given length.
* <p>
* The vector has the default R class name 'logical'.</p>
* <p>
* The function works analog to the R function <code>logical(length)</code>;
* the vector is initialized with FALSE values.</p>
*
* @param length the length of the vector
* @return the R logical vector
*/
public RVector<RLogicalStore> createLogiVector(final int length) {
return createVector(createLogiData(length), RObject.CLASSNAME_LOGICAL);
}
/**
* Creates an R integer vector with values from a Java integer array.
* <p>
* The vector has the default R class name 'integer'.</p>
* <p>
* Note that the R vector may use the array directly. For values
* see {@link RStore#setInt(int, int)}.</p>
*
* @param integers the integer values
* @return the R integer vector
*/
public RVector<RIntegerStore> createIntVector(final int [] integers) {
return createVector(createIntData(integers), RObject.CLASSNAME_INTEGER);
}
/**
* Creates an R integer vector of the given length.
* <p>
* The vector has the default R class name 'integer'.</p>
* <p>
* The function works analog to the R function <code>integer(length)</code>;
* the vector is initialized with 0 values.</p>
*
* @param length the length of the vector
* @return the R integer vector
*/
public RVector<RIntegerStore> createIntVector(final int length) {
return createVector(createIntData(length), RObject.CLASSNAME_INTEGER);
}
/**
* Creates an R numeric vector with values from a Java double array.
* <p>
* The vector has the default R class name 'numeric'.</p>
* <p>
* Note that the R vector may use the array directly. For values
* see {@link RStore#setNum(int, double)}.</p>
*
* @param numerics the numerics values
* @return the R numeric vector
*/
public RVector<RNumericStore> createNumVector(final double [] numerics) {
return createVector(createNumData(numerics), RObject.CLASSNAME_NUMERIC);
}
/**
* Creates an R numeric vector of the given length.
* <p>
* The vector has the default R class name 'numeric'.</p>
* <p>
* The function works analog to the R function <code>numeric(length)</code>;
* the vector is initialized with 0.0 values.</p>
*
* @param length the length of the vector
* @return the R numeric vector
*/
public RVector<RNumericStore> createNumVector(final int length) {
return createVector(createNumData(length), RObject.CLASSNAME_NUMERIC);
}
/**
* Creates an R complex vector of the given length.
* <p>
* The vector has the default R class name 'complex'.</p>
* <p>
* The function works analog to the R function <code>complex(length)</code>;
* the vector is initialized with 0.0 values.</p>
*
* @param length the length of the vector
* @return the R complex vector
*/
public RVector<RComplexStore> createCplxVector(final int length) {
return createVector(createCplxData(length), RObject.CLASSNAME_COMPLEX);
}
/**
* Creates an R character vector with values from a Java String array.
* <p>
* The vector has the default R class name 'character'.</p>
* <p>
* Note that the R vector may use the array directly. For values
* see {@link RStore#setChar(int, String)}.</p>
*
* @param characters the characters values
* @return the R character vector
*/
public RVector<RCharacterStore> createCharVector(final @Nullable String [] characters) {
return createVector(createCharData(characters), RObject.CLASSNAME_CHARACTER);
}
/**
* Creates an R character vector of the given length.
* <p>
* The vector has the default R class name 'character'.</p>
* <p>
* The function works analog to the R function <code>character(length)</code>;
* the vector is initialized with "" (empty String) values.</p>
*
* @param length the length of the vector
* @return the R character vector
*/
public RVector<RCharacterStore> createCharVector(final int length) {
return createVector(createCharData(length), RObject.CLASSNAME_CHARACTER);
}
/**
* Creates an R raw vector of the specified length.
*
* <p>The vector has the default R class name 'raw'.</p>
*
* <p>Note that the R vector may use the array directly. For values
* see {@link RStore#setRaw(int, byte)}.</p>
*
* @param raws the raw/byte values of the vector
* @return the R raw vector
*/
public RVector<RRawStore> createRawVector(final byte[] raws) {
return createVector(createRawData(raws), RObject.CLASSNAME_RAW);
}
/**
* Creates an R raw vector of the specified length.
* <p>
* The vector has the default R class name 'raw'.</p>
* <p>
* The function works analog to the R function {@code raw(length)};
* the vector is initialized with {@code 00} values.</p>
*
* @param length the length of the vector
* @return the R raw vector
*/
public RVector<RRawStore> createRawVector(final int length) {
return createVector(createRawData(length), RObject.CLASSNAME_RAW);
}
/**
* Creates an R (unordered) factor vector with level codes from a Java integer array.
* <p>
* The vector has the default R class name 'factor'.</p>
* <p>
* Note that the R vector may use the array directly.</p>
*
* @param codes the coded levels
* @param levels the labels of the levels
* @return the R factor vector
*/
public RVector<RFactorStore> createFactorVector(final int [] codes, final String [] levels) {
return createVector(createFactorData(codes, levels), RObject.CLASSNAME_FACTOR);
}
/**
* Creates an R (unordered) factor vector of the specified length.
* <p>
* The vector has the default R class name 'factor'.</p>
*
* @param length the length of the vector
* @param levels the labels of the levels
* @return the R factor vector
*/
public RVector<RFactorStore> createFactorVector(final int length, final String [] levels) {
return createVector(createFactorData(length, levels), RObject.CLASSNAME_FACTOR);
}
/**
* Creates an R ordered factor vector with level codes from a Java integer array.
* <p>
* The vector has the default R class name 'ordered'.</p>
* <p>
* Note that the R vector may use the array directly.</p>
*
* @param codes the coded levels
* @param levels the labels of the levels
* @return the R factor vector
*/
public RVector<RFactorStore> createOrderedVector(final int [] codes, final String [] levels) {
return createVector(createOrderedData(codes, levels), RObject.CLASSNAME_ORDERED);
}
/**
* Creates an R ordered factor vector of the specified length.
* <p>
* The vector has the default R class name 'factor'.</p>
*
* @param length the length of the vector
* @param levels the labels of the levels
* @return the R factor vector
*/
public RVector<RFactorStore> createOrderedVector(final int length, final String [] levels) {
return createVector(createOrderedData(length, levels), RObject.CLASSNAME_ORDERED);
}
/*-- Array/Matrix --*/
public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim,
final String classname) {
return new RArrayImpl<>(data, classname, dim);
}
@Override
public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim) {
return createArray(data, dim, (dim.length == 2) ? RObject.CLASSNAME_MATRIX :RObject.CLASSNAME_ARRAY);
}
@Override
public <TData extends RStore<?>> RArray<TData> createMatrix(final TData data, final int dim1, final int dim2) {
return createArray(data, new int[] { dim1, dim2 }, RObject.CLASSNAME_MATRIX);
}
public RArray<RLogicalStore> createLogiArray(final boolean [] logicals, final int[] dim) {
return createArray(createLogiData(logicals), dim);
}
public RArray<RLogicalStore> createLogiArray(final int[] dim) {
return createArray(createLogiData(RDataUtils.computeLengthFromDim(dim)), dim);
}
public RArray<RIntegerStore> createIntArray(final int [] integers, final int[] dim) {
return createArray(createIntData(integers), dim);
}
public RArray<RIntegerStore> createIntArray(final int[] dim) {
return createArray(createIntData(RDataUtils.computeLengthFromDim(dim)), dim);
}
public RArray<RNumericStore> createNumArray(final double [] numerics, final int[] dim) {
return createArray(createNumData(numerics), dim);
}
public RArray<RNumericStore> createNumArray(final int[] dim) {
return createArray(createNumData(RDataUtils.computeLengthFromDim(dim)), dim);
}
public RArray<RCharacterStore> createCharArray(final @Nullable String [] characters, final int[] dim) {
return createArray(createCharData(characters), dim);
}
public RArray<RCharacterStore> createCharArray(final int[] dim) {
return createArray(createCharData(RDataUtils.computeLengthFromDim(dim)), dim);
}
public RArray<RLogicalStore> createLogiMatrix(final boolean [] logicals, final int dim1, final int dim2) {
return createMatrix(createLogiData(logicals), dim1, dim2);
}
public RArray<RLogicalStore> createLogiMatrix(final int dim1, final int dim2) {
return createMatrix(createLogiData(dim1*dim2), dim1, dim2);
}
public RArray<RIntegerStore> createIntMatrix(final int [] integers, final int dim1, final int dim2) {
return createMatrix(createIntData(integers), dim1, dim2);
}
public RArray<RIntegerStore> createIntMatrix(final int dim1, final int dim2) {
return createMatrix(createIntData(dim1*dim2), dim1, dim2);
}
public RArray<RNumericStore> createNumMatrix(final double [] numerics, final int dim1, final int dim2) {
return createMatrix(createNumData(numerics), dim1, dim2);
}
public RArray<RNumericStore> createNumMatrix(final int dim1, final int dim2) {
return createMatrix(createNumData(dim1*dim2), dim1, dim2);
}
public RArray<RCharacterStore> createCharMatrix(final @Nullable String [] characters, final int dim1, final int dim2) {
return createMatrix(createCharData(characters), dim1, dim2);
}
public RArray<RCharacterStore> createCharMatrix(final int dim1, final int dim2) {
return createMatrix(createCharData(dim1*dim2), dim1, dim2);
}
/*-- DataFrame --*/
public RDataFrame createDataFrame(final @NonNull RStore<?> [] colDatas,
final @NonNull String [] colNames) {
return createDataFrame(colDatas, colNames, null);
}
public RDataFrame createDataFrame(final @NonNull RStore<?> [] colDatas,
final @NonNull String [] colNames,
final String @Nullable[] rowNames) {
final RObject[] colVectors= new RObject[colDatas.length];
for (int i= 0; i < colVectors.length; i++) {
colVectors[i]= createVector(colDatas[i]);
}
return createDataFrame(colVectors, colNames, rowNames);
}
public RDataFrame createDataFrame(final RObject [] colVectors,
final @NonNull String [] colNames, final String @Nullable[] rowNames) {
return new RDataFrame32Impl(colVectors, RObject.CLASSNAME_DATAFRAME, colNames, rowNames);
}
public RList createList(final RObject [] components, final @Nullable String @Nullable[] names,
final String classname) {
return new RList32Impl(components, classname, names);
}
@Override
public RList createList(final RObject [] components, final @Nullable String @Nullable[] names) {
return createList(components, names, RObject.CLASSNAME_LIST);
}
/*-- Language --*/
@Override
public RLanguage createName(final String name) {
return new RLanguageImpl(RLanguage.NAME, name, RObject.CLASSNAME_NAME);
}
@Override
public RLanguage createExpression(final String expr) {
return new RLanguageImpl(RLanguage.EXPRESSION, expr, RObject.CLASSNAME_EXPRESSION);
}
/*-- Data/RStore --*/
@Override
public RLogicalStore createLogiData(final boolean [] logiValues) {
return new RLogicalByte32Store(logiValues);
}
public RLogicalStore createLogiData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RLogicalByte32Store((int)length) :
new RLogicalByteFix64Store(length);
}
@Override
public RIntegerStore createIntData(final int [] intValues) {
return new RInteger32Store(intValues);
}
public RIntegerStore createIntData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RInteger32Store((int)length) :
new RIntegerFix64Store(length);
}
@Override
public RNumericStore createNumData(final double [] numValues) {
return new RNumericB32Store(numValues);
}
public RNumericStore createNumData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RNumericB32Store((int)length) :
new RNumericBFix64Store(length);
}
@Override
public RComplexStore createCplxData(final double [] reValues, final double [] imValues) {
return new RComplexB32Store(reValues, imValues, (int[])null);
}
public RComplexStore createCplxData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RComplexB32Store((int)length) :
new RComplexBFix64Store(length);
}
@Override
public RCharacterStore createCharData(final @Nullable String [] charValues) {
return new RCharacter32Store(charValues);
}
public RCharacterStore createCharData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RCharacter32Store((int)length) :
new RCharacterFix64Store(length);
}
@Override
public RRawStore createRawData(final byte [] rawValues) {
return new RRaw32Store(rawValues);
}
public RRawStore createRawData(final long length) {
return (length <= this.storeLengthFixLong) ?
new RRaw32Store((int)length) :
new RRawFix64Store(length);
}
@Override
public RFactorStore createFactorData(final int [] codes, final String [] levels) {
return new RFactor32Store(codes, false, levels);
}
public RFactorStore createFactorData(final int length, final String [] levels) {
return new RFactor32Store(length, false, levels);
}
public RFactorStore createOrderedData(final int [] codes, final String [] levels) {
return new RFactor32Store(codes, true, levels);
}
public RFactorStore createOrderedData(final int length, final String [] levels) {
return new RFactor32Store(length, true, levels);
}
/*-- Streaming --*/
@Override
public RObject readObject(final RJIO io) throws IOException {
final byte type= io.readByte();
int options;
switch (type) {
case -1:
return null;
case RObject.TYPE_NULL:
return RNullImpl.INSTANCE;
case RObject.TYPE_VECTOR: {
return new RVectorImpl(io, this); }
case RObject.TYPE_ARRAY:
return new RArrayImpl(io, this);
case RObject.TYPE_LIST:
options= io.readInt();
return ((options & O_LENGTHGRADE_MASK) <= 3) ?
new RList32Impl(io, this, options) :
new RListFix64Impl(io, this, options);
case RObject.TYPE_DATAFRAME:
options= io.readInt();
return ((options & O_LENGTHGRADE_MASK) <= 3) ?
new RDataFrame32Impl(io, this, options) :
new RListFix64Impl(io, this, options);
case RObject.TYPE_ENVIRONMENT:
return new REnvironmentImpl(io, this);
case RObject.TYPE_LANGUAGE:
return new RLanguageImpl(io, this);
case RObject.TYPE_FUNCTION:
return new RFunctionImpl(io, this);
case RObject.TYPE_REFERENCE:
return new RReferenceImpl(io, this);
case RObject.TYPE_S4OBJECT:
return new RS4ObjectImpl(io, this);
case RObject.TYPE_OTHER:
return new ROtherImpl(io, this);
case RObject.TYPE_MISSING:
return RMissingImpl.INSTANCE;
case RObject.TYPE_PROMISE:
if ((io.flags & F_WITH_DBG) != 0) {
return new RPromiseImpl(io, this);
}
return RPromiseImpl.INSTANCE;
default:
throw new IOException("object type= " + type);
}
}
@Override
public void writeObject(final RObject robject, final RJIO io) throws IOException {
if (robject == null) {
io.writeByte(-1);
return;
}
final byte type= robject.getRObjectType();
io.writeByte(type);
switch (type) {
case RObject.TYPE_NULL:
case RObject.TYPE_MISSING:
return;
case RObject.TYPE_VECTOR:
case RObject.TYPE_ARRAY:
case RObject.TYPE_LIST:
case RObject.TYPE_DATAFRAME:
case RObject.TYPE_ENVIRONMENT:
case RObject.TYPE_LANGUAGE:
case RObject.TYPE_FUNCTION:
case RObject.TYPE_REFERENCE:
case RObject.TYPE_S4OBJECT:
case RObject.TYPE_OTHER:
case RObject.TYPE_PROMISE:
((ExternalizableRObject) robject).writeExternal(io, this);
return;
default:
throw new IOException("object type= " + type);
}
}
@Override
public RStore<?> readStore(final RJIO io, final long length) throws IOException {
if ((io.flags & F_ONLY_STRUCT) == 0) {
final byte storeType= io.readByte();
if (length <= Integer.MAX_VALUE) {
switch (storeType) {
case RStore.LOGICAL:
return new RLogicalByte32Store(io, (int)length);
case RStore.INTEGER:
return new RInteger32Store(io, (int)length);
case RStore.NUMERIC:
return new RNumericB32Store(io, (int)length);
case RStore.COMPLEX:
return new RComplexB32Store(io, (int)length);
case RStore.CHARACTER:
return new RCharacter32Store(io, (int)length);
case RStore.RAW:
return new RRaw32Store(io, (int)length);
case RStore.FACTOR:
return new RFactor32Store(io, (int)length);
default:
throw new IOException("store type= " + storeType);
}
}
else {
switch (storeType) {
case RStore.LOGICAL:
return new RLogicalByteFix64Store(io, length);
case RStore.INTEGER:
return new RIntegerFix64Store(io, length);
case RStore.NUMERIC:
return new RNumericBFix64Store(io, length);
case RStore.COMPLEX:
return new RComplexBFix64Store(io, length);
case RStore.CHARACTER:
return new RCharacterFix64Store(io, length);
case RStore.RAW:
return new RRawFix64Store(io, length);
case RStore.FACTOR:
return new RFactorFix64Store(io, length);
default:
throw new IOException("store type= " + storeType);
}
}
}
else {
final byte storeType= io.readByte();
switch (storeType) {
case RStore.LOGICAL:
return LOGI_STRUCT_DUMMY;
case RStore.INTEGER:
return INT_STRUCT_DUMMY;
case RStore.NUMERIC:
return NUM_STRUCT_DUMMY;
case RStore.COMPLEX:
return CPLX_STRUCT_DUMMY;
case RStore.CHARACTER:
return CHR_STRUCT_DUMMY;
case RStore.RAW:
return RAW_STRUCT_DUMMY;
case RStore.FACTOR:
return new RFactorStructStore(io.readBoolean(), io.readInt());
default:
throw new IOException("store type= " + storeType);
}
}
}
@Override
public void writeStore(final RStore<?> data, final RJIO io) throws IOException {
if ((io.flags & F_ONLY_STRUCT) == 0) {
io.writeByte(data.getStoreType());
((ExternalizableRStore) data).writeExternal(io);
}
else {
final byte storeType= data.getStoreType();
io.writeByte(storeType);
if (storeType == RStore.FACTOR) {
final RFactorStore factor= (RFactorStore) data;
io.writeBoolean(factor.isOrdered());
io.writeInt(factor.getLevelCount());
}
}
}
@Override
public RList readAttributeList(final RJIO io) throws IOException {
return new RList32Impl(io, this, io.readInt());
}
@Override
public void writeAttributeList(final RList list, final RJIO io) throws IOException {
((ExternalizableRObject) list).writeExternal(io, this);
}
protected final int[] readDim(final ObjectInput in) throws IOException {
final int length= in.readInt();
final int[] dim= new int[length];
for (int i= 0; i < length; i++) {
dim[i]= in.readInt();
}
return dim;
}
@Override
public @Nullable RStore<?> readNames(final RJIO io, final long length) throws IOException {
final byte type= io.readByte();
if (type == RStore.CHARACTER) {
return (length <= Integer.MAX_VALUE) ?
new RCharacter32Store(io, (int)length) :
new RCharacterFix64Store(io, length);
}
if (type == 0) {
return null;
}
throw new IOException();
}
@Override
public void writeNames(final @Nullable RStore<?> names, final RJIO io) throws IOException {
if (names != null) {
final byte type= names.getStoreType();
if (type == RStore.CHARACTER) {
io.writeByte(type);
((ExternalizableRStore) names).writeExternal(io);
return;
}
}
io.writeByte(0);
}
}