/*=============================================================================# # Copyright (c) 2009-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of either (per the licensee's choosing) # - the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html, or # - the GNU Lesser General Public License v2.1 or newer # which accompanies this distribution, and is available at # http://www.gnu.org/licenses/lgpl.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.rj.data.defaultImpl; import java.io.IOException; import java.io.ObjectInput; import de.walware.rj.data.RArray; import de.walware.rj.data.RCharacterStore; import de.walware.rj.data.RComplexStore; import de.walware.rj.data.RDataFrame; import de.walware.rj.data.RDataUtil; import de.walware.rj.data.RFactorStore; import de.walware.rj.data.RIntegerStore; import de.walware.rj.data.RJIO; import de.walware.rj.data.RLanguage; import de.walware.rj.data.RList; import de.walware.rj.data.RLogicalStore; import de.walware.rj.data.RNumericStore; import de.walware.rj.data.RObject; import de.walware.rj.data.RObjectFactory; import de.walware.rj.data.RRawStore; import de.walware.rj.data.RStore; import de.walware.rj.data.RVector; public class RObjectFactoryImpl implements RObjectFactory { public static final RObjectFactoryImpl INSTANCE = new RObjectFactoryImpl(); public static final RNumericStore NUM_STRUCT_DUMMY = new RNumericDataStruct(); public static final RComplexDataStruct CPLX_STRUCT_DUMMY = new RComplexDataStruct(); public static final RIntegerDataStruct INT_STRUCT_DUMMY = new RIntegerDataStruct(); public static final RLogicalDataStruct LOGI_STRUCT_DUMMY = new RLogicalDataStruct(); public static final RRawDataStruct RAW_STRUCT_DUMMY = new RRawDataStruct(); public static final RCharacterDataStruct CHR_STRUCT_DUMMY = new RCharacterDataStruct(); private final long storeLengthFixLong = AbstractRData.DEFAULT_LONG_DATA_SEGMENT_LENGTH; public RObjectFactoryImpl() { } /*-- 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 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 charcter 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> * The function works analog to the R function <code>raw(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<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(RDataUtil.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(RDataUtil.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(RDataUtil.computeLengthFromDim(dim)), dim); } public RArray<RCharacterStore> createCharArray(final String[] characters, final int[] dim) { return createArray(createCharData(characters), dim); } public RArray<RCharacterStore> createCharArray(final int[] dim) { return createArray(createCharData(RDataUtil.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 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 RStore<?>[] colDatas, final String[] colNames) { return createDataFrame(colDatas, colNames, null); } public RDataFrame createDataFrame(final RStore<?>[] colDatas, final String[] colNames, final String[] 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 String[] colNames, final String[] rowNames) { return new RDataFrameImpl(colVectors, RObject.CLASSNAME_DATAFRAME, colNames, rowNames); } public RList createList(final RObject[] components, final String[] names, final String classname) { return new RListImpl(components, classname, names); } @Override public RList createList(final RObject[] components, final String[] 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 RLogicalDataByteImpl(logiValues); } public RLogicalStore createLogiData(final long length) { return (length <= this.storeLengthFixLong) ? new RLogicalDataByteImpl((int) length) : new RLogicalDataByteFixLongImpl(length); } @Override public RIntegerStore createIntData(final int[] intValues) { return new RIntegerDataImpl(intValues); } public RIntegerStore createIntData(final long length) { return (length <= this.storeLengthFixLong) ? new RIntegerDataImpl((int) length) : new RIntegerDataFixLongImpl(length); } @Override public RNumericStore createNumData(final double[] numValues) { return new RNumericDataBImpl(numValues); } public RNumericStore createNumData(final long length) { return (length <= this.storeLengthFixLong) ? new RNumericDataBImpl((int) length) : new RNumericDataBFixLongImpl(length); } @Override public RComplexStore createCplxData(final double[] reValues, final double[] imValues) { return new RComplexDataBImpl(reValues, imValues, null); } public RComplexStore createCplxData(final long length) { return (length <= this.storeLengthFixLong) ? new RComplexDataBImpl((int) length) : new RComplexDataBFixLongImpl(length); } @Override public RCharacterStore createCharData(final String[] charValues) { return new RCharacterDataImpl(charValues); } public RCharacterStore createCharData(final long length) { return (length <= this.storeLengthFixLong) ? new RCharacterDataImpl((int) length) : new RCharacterDataFixLongImpl(length); } @Override public RRawStore createRawData(final byte[] rawValues) { return new RRawDataImpl(rawValues); } public RRawStore createRawData(final long length) { return (length <= this.storeLengthFixLong) ? new RRawDataImpl((int) length) : new RRawDataFixLongImpl(length); } @Override public RFactorStore createFactorData(final int[] codes, final String[] levels) { return new RFactorDataImpl(codes, false, levels); } public RFactorStore createFactorData(final int length, final String[] levels) { return new RFactorDataImpl(length, false, levels); } public RFactorStore createOrderedData(final int[] codes, final String[] levels) { return new RFactorDataImpl(codes, true, levels); } public RFactorStore createOrderedData(final int length, final String[] levels) { return new RFactorDataImpl(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 RNull.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 RListImpl(io, this, options) : new RListFixLongImpl(io, this, options); case RObject.TYPE_DATAFRAME: options = io.readInt(); return ((options & O_LENGTHGRADE_MASK) <= 3) ? new RDataFrameImpl(io, this, options) : new RListFixLongImpl(io, this, options); case RObject.TYPE_ENV: 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 RMissing.INSTANCE; case RObject.TYPE_PROMISE: return RPromise.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: case RObject.TYPE_PROMISE: return; case RObject.TYPE_VECTOR: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_ARRAY: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_LIST: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_DATAFRAME: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_ENV: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_LANGUAGE: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_FUNCTION: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_REFERENCE: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_S4OBJECT: ((ExternalizableRObject) robject).writeExternal(io, this); return; case RObject.TYPE_OTHER: ((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 RLogicalDataByteImpl(io, (int) length); case RStore.INTEGER: return new RIntegerDataImpl(io, (int) length); case RStore.NUMERIC: return new RNumericDataBImpl(io, (int) length); case RStore.COMPLEX: return new RComplexDataBImpl(io, (int) length); case RStore.CHARACTER: return new RCharacterDataImpl(io, (int) length); case RStore.RAW: return new RRawDataImpl(io, (int) length); case RStore.FACTOR: return new RFactorDataImpl(io, (int) length); default: throw new IOException("store type = " + storeType); } } else { switch (storeType) { case RStore.LOGICAL: return new RLogicalDataByteFixLongImpl(io, length); case RStore.INTEGER: return new RIntegerDataFixLongImpl(io, length); case RStore.NUMERIC: return new RNumericDataBFixLongImpl(io, length); case RStore.COMPLEX: return new RComplexDataBFixLongImpl(io, length); case RStore.CHARACTER: return new RCharacterDataFixLongImpl(io, length); case RStore.RAW: return new RRawDataFixLongImpl(io, length); case RStore.FACTOR: return new RFactorDataFixLongImpl(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 RFactorDataStruct(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 RListImpl(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 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 RCharacterDataImpl(io, (int) length) : new RCharacterDataFixLongImpl(io, length); } if (type == 0) { return null; } throw new IOException(); } @Override public void writeNames(final 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); } }