Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multidimensional safe arrays, part 2 #37

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 38 additions & 36 deletions native/safearray.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace safearray {

static NativeType toNative( JNIEnv* env, JavaType javaArray ) {

const int length = env->GetArrayLength(javaArray);
const size_t length = env->GetArrayLength(javaArray);

// allocate SAFEARRAY
SAFEARRAYBOUND bounds;
Expand All @@ -46,11 +46,11 @@ namespace safearray {
SAFEARRAY* psa = SafeArrayCreate(itemType,1,&bounds);


XDUCER::JavaType* pSrc = JARRAY::lock(env,static_cast<JARRAY::ARRAY>(javaArray));
const XDUCER::JavaType* pSrc = JARRAY::lock(env,static_cast<JARRAY::ARRAY>(javaArray));
XDUCER::NativeType* pDst;
SafeArrayAccessData( psa, reinterpret_cast<void**>(&pDst) );

for( int i=0; i<length; i++ )
for( size_t i=0; i<length; i++ )
pDst[i] = XDUCER::toNative(env,pSrc[i]);

JARRAY::unlock(env,static_cast<JARRAY::ARRAY>(javaArray),pSrc);
Expand Down Expand Up @@ -88,8 +88,8 @@ namespace safearray {
JNIEnv* env;
NativeType psa;
JavaType javaArray;
int dim;
int* dimSizes;
size_t dim;
size_t* dimSizes;
typename XDUCER::NativeType* pSrc;

public:
Expand All @@ -101,7 +101,7 @@ namespace safearray {
, pSrc(NULL)
{
dim = SafeArrayGetDim(psa);
dimSizes = new int[dim];
dimSizes = new size_t[dim];
fillDimSizes(psa, dim, dimSizes);
SafeArrayAccessData( psa, reinterpret_cast<void**>(&pSrc) );
}
Expand All @@ -112,42 +112,43 @@ namespace safearray {
}

JavaType getJava() {
return toJavaRec(pSrc, dim - 1);
return toJavaRec(pSrc, dim, 0, 1);
}

private:

JavaType toJavaRec(typename XDUCER::NativeType* &pSrc, int curDim) {
if (curDim == 0) {
JARRAY::ARRAY a = JARRAY::newArray(env, dimSizes[curDim]);
JavaType toJavaRec(typename XDUCER::NativeType* &pSrc, size_t curDim, size_t offset, size_t delta) {
if (curDim == 1) {
JARRAY::ARRAY a = JARRAY::newArray(env, dimSizes[curDim - 1]);
XDUCER::JavaType* const pDst = JARRAY::lock(env, a);

for( int i=0; i < dimSizes[curDim]; i++ ) {
pDst[i] = XDUCER::toJava(env, *(pSrc++));
for( size_t i=0; i < dimSizes[0]; i++ ) {
pDst[i] = XDUCER::toJava(env, *(pSrc + offset + i*delta));
}
JARRAY::unlock(env, a, pDst);
return a;
}
else {
jobjectArray a = array::Array<jobject>::newArray(env, dimSizes[curDim]);
jobject* const pDst = array::Array<jobject>::lock(env, a);
jobjectArray a = array::ArrayND::newArray(env, dimSizes[curDim - 1], curDim);
jobject* const pDst = array::ArrayND::lock(env, a);

for( int i = 0; i < dimSizes[curDim]; i++ ) {
pDst[i] = toJavaRec(pSrc, curDim - 1);
size_t newDelta = delta * dimSizes[curDim - 1];
for( size_t i = 0; i < dimSizes[curDim - 1]; i++ ) {
pDst[i] = toJavaRec(pSrc, curDim - 1, offset + i*delta, newDelta);
}
array::Array<jobject>::unlock(env, a, pDst);
array::ArrayND::unlock(env, a, pDst);
return a;
}

}

static void fillDimSizes(NativeType psa, int dim, int *dimSizes) {
for (int i = 1; i <= dim; ++i) {
static void fillDimSizes(NativeType psa, size_t dim, size_t *dimSizes) {
for (size_t i = 1; i <= dim; ++i) {
long lbound,ubound;
SafeArrayGetLBound(psa,i,&lbound);
SafeArrayGetUBound(psa,i,&ubound);
// sometimes SafeArrayGetUBound returns -1 with S_OK. I haven't figured out what that means
dimSizes[i-1] = max(0,ubound-lbound+1); // the range of index is [lbound,ubound]
dimSizes[dim-i] = max(0,ubound-lbound+1); // the range of index is [lbound,ubound]
}
}

Expand Down Expand Up @@ -190,7 +191,7 @@ namespace safearray {
private:
JNIEnv* env;
JavaType javaArray;
int dim;
size_t dim;
SAFEARRAYBOUND* bounds;
SAFEARRAY* psa;
typename XDUCER::NativeType* pDst;
Expand All @@ -217,35 +218,37 @@ namespace safearray {
}

SAFEARRAY* getNative() {
toNativeRec(javaArray, dim - 1);
toNativeRec(javaArray, dim - 1, 0, 1);
return psa;
}

private:
void toNativeRec(JavaType _array, int curDim) {
void toNativeRec(JavaType _array, size_t curDim, size_t offset, size_t delta) {

if (curDim == 0) {
XDUCER::JavaType* pSrc = JARRAY::lock(env,static_cast<JARRAY::ARRAY>(_array));
const XDUCER::JavaType* pSrc = JARRAY::lock(env,static_cast<JARRAY::ARRAY>(_array));

for(size_t i = 0; i < bounds[curDim].cElements; i++)
*(pDst++) = XDUCER::toNative(env, pSrc[i]);
for(size_t i = 0; i < bounds[dim - 1].cElements; i++)
*(pDst + offset + i*delta) = XDUCER::toNative(env, pSrc[i]);

JARRAY::unlock(env,static_cast<JARRAY::ARRAY>(_array), pSrc);

}
else {
JavaType* pSrc = array::Array<JavaType>::lock(env, static_cast<JARRAY::ARRAY>(_array));
const JavaType* pSrc = array::Array<JavaType>::lock(env, static_cast<JARRAY::ARRAY>(_array));

size_t newDelta = delta * bounds[dim - curDim - 1].cElements;

for(size_t i = 0; i < bounds[curDim].cElements; i++)
toNativeRec(pSrc[i], curDim - 1);
for(size_t i = 0; i < bounds[dim - curDim - 1].cElements; i++)
toNativeRec(pSrc[i], curDim - 1, offset + i*delta, newDelta);

array::Array<JavaType>::unlock(env,static_cast<JARRAY::ARRAY>(_array), pSrc);
}
}

// gets dimensions of java multi index array
static int getArrayDimension(JNIEnv* env, jobject a ) {
int dim = 0;
static size_t getArrayDimension(JNIEnv* env, jobject a ) {
size_t dim = 0;
while(env->IsInstanceOf(a, objectArray)) {
dim++;

Expand All @@ -258,18 +261,17 @@ namespace safearray {
return dim;
}

// fills SAFEARRAYBOUND structure base on java array
static void fillBounds(JNIEnv* env, jobject a, int n, SAFEARRAYBOUND* bounds) {
int i = n - 1;
static void fillBounds(JNIEnv* env, jobject a, size_t n, SAFEARRAYBOUND* bounds) {
size_t i = 0;
while(true) {
bounds[i].lLbound = 0;
bounds[i].cElements = env->GetArrayLength(static_cast<jobjectArray>(a));

if (i <= 0)
if (i >= n - 1)
break;

a = env->GetObjectArrayElement(static_cast<jobjectArray>(a), 0);
i--;
i++;
}
}

Expand Down
12 changes: 10 additions & 2 deletions native/xducer2.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@ namespace xducer {
typedef jobject JavaType;

static inline NativeType toNative( JNIEnv* env, JavaType value ) {
std::auto_ptr<VARIANT> v(convertToVariant(env,value)); // need to be deleted after copy as return value
return *v;
if (value == NULL) {
VARIANT v;
VariantInit(&v);
VariantCopy(&v, &vtMissing);
return v;
}
else {
std::auto_ptr<VARIANT> v(convertToVariant(env,value)); // need to be deleted after copy as return value
return *v;
}
}

static inline JavaType toJava( JNIEnv* env, NativeType value ) {
Expand Down
119 changes: 77 additions & 42 deletions test/src/test/java/VariantTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

import java.math.BigInteger;
import java.math.BigDecimal;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

/**
Expand Down Expand Up @@ -78,84 +76,121 @@ public void testCurrency() throws Exception {
}

public void testEmptyArray() throws Exception {
ITestObject t = ClassFactory.createTestObject();
Object[] a = {};
Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);
assertTrue(Arrays.deepEquals(a, b));
testArray2(new Object[]{});
}

public void testEmpty2DArray() throws Exception {
ITestObject t = ClassFactory.createTestObject();
Object[][] a = {{},{},{}};
Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);
assertTrue(Arrays.deepEquals(a, b));
testArray2(new Object[][]{{}, {}, {}});
}

/**
* Tests the currency type conversion.
*/
public void testArray() throws Exception {
ITestObject t = ClassFactory.createTestObject();
Object[] a = {"a1", "a2", "a3"};
Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);
assertTrue(Arrays.deepEquals(a, b));
testArray2(new Object[]{"a1", "a2", "a3"});
}

public void test2DArrays() throws Exception {
ITestObject t = ClassFactory.createTestObject();

Object[][] a = {
testArray2(new Object[][] {
{"a11","a12"},
{"a21","a22"},
{"a31","a32"}
};

Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);

assertTrue(Arrays.deepEquals(a, b));

});
}

public void test3DArrays() throws Exception {
ITestObject t = ClassFactory.createTestObject();
Object[][][] a = {
testArray2(new Object[][][] {
{{"a111", "a112"},
{"a121", "a122"}},
{{"a211", "a212"},
{"a221", "a222"}},
{{"a311", "a312"},
{"a321", "a322"}}
};

Object b = t.testVariant(Variant.getMissing(), a);
assertTrue(b instanceof Object[]);
assertTrue(Arrays.deepEquals(a, (Object[])b));
});
}

public void testDoubleArrays() throws Exception {
ITestObject t = ClassFactory.createTestObject();
testArray2(new Object[][]{
{1.1, 1.2},
{2.1, 2.2},
{3.1, 3.2}
});
}

Object[][] a = {
public void testPrimitiveArrays() throws Exception {
testArray2(new double[][] {
{1.1,1.2},
{2.1,2.2},
{3.1,3.2}
});
}

public void test2DArrayWithsubArray() throws Exception {
Object[][] a = {
{"a11", "a12", "a13", "a14", "a15"},
{"a21", "a22", "a23", "a24", "a25"}
};

Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);
assertTrue(Arrays.deepEquals(a, b));
a[1][4] = new Object[][] {
{"s11", "s12"},
{"s21", "s22"},
{"s31", "s32"},
{"s41", "s42"},
{"s51", "s52"}
};

testArray2(a);
}

public void testPrimitiveArrays() throws Exception {
ITestObject t = ClassFactory.createTestObject();
public void testNullArrays() throws Exception {
testArray2(new Object[]{"a1", "a2", null, "a4", "a15"});
}

double[][] a = {
{1.1,1.2},
{2.1,2.2},
{3.1,3.2}
public void testVeryBigDimArray() throws Exception {
Object[][] a1 = new Object[][]{
{"a11", "a12"},
{"a21", "a22"}
};

Object[] b = (Object[]) t.testVariant(Variant.getMissing(), a);
assertTrue(Arrays.deepEquals(a, b));
testArray2(a1);

Object[][][][][][][][][][][][] a2 = new Object[][][][][][][][][][][][]{{{{{{{{{{{{"a1"}}}}}}}}}}}};
testArray2(a2);
}

private void testArray2(Object[] orig) {
//Object[] a = (Object[])deepCopy(orig);

Object[] r = getAsReturnValue(orig);
assertTrue(Arrays.deepEquals(orig, r));

Object[] r2 = getAsReturnValue(r);
assertTrue(Arrays.deepEquals(orig, r2));


//a = (Object[])deepCopy(orig);
r = getAsRefValue(orig);
assertTrue(Arrays.deepEquals(orig, r));

r2 = getAsRefValue(r);
assertTrue(Arrays.deepEquals(orig, r2));
}


private Object[] getAsReturnValue(Object[] a) {
ITestObject t = ClassFactory.createTestObject();

Object[] c = (Object[])t.testVariant(Variant.getMissing(), a); // return copy of a, test return value conversion
return c;
}

private Object[] getAsRefValue(Object[] a) {
ITestObject t = ClassFactory.createTestObject();

Variant bv = Variant.getMissing();

t.testVariant(a, bv); // copy a -> b, test internal conversion
return bv.convertTo(Object[].class);
}


Expand Down