Skip to content

Commit

Permalink
Auto perform buffer->ByteBuffer conv for args
Browse files Browse the repository at this point in the history
  • Loading branch information
jmao-denver committed Dec 11, 2023
1 parent db5c2f0 commit 9fe3362
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 18 deletions.
35 changes: 35 additions & 0 deletions src/main/c/jpy_conv.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,38 @@ int JPy_AsJString(JNIEnv* jenv, PyObject* arg, jstring* stringRef)
return 0;
}

int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer** pyBuffer, jobject* byteBufferRef)
{
jobject tmpByteBufferRef;

*pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer));
if (*pyBuffer == NULL) {
PyErr_NoMemory();
return -1;
}

if (PyObject_GetBuffer(pyObj, *pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) {
PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer.");
PyMem_Free(*pyBuffer);
return -1;
}

tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, (*pyBuffer)->buf, (*pyBuffer)->len);
if (tmpByteBufferRef == NULL) {
PyBuffer_Release(*pyBuffer);
PyMem_Free(*pyBuffer);
PyErr_NoMemory();
return -1;
}

*byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID);
if (*byteBufferRef == NULL) {
PyBuffer_Release(*pyBuffer);
PyMem_Free(*pyBuffer);
JPy_DELETE_LOCAL_REF(tmpByteBufferRef);
PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance.");
return -1;
}

return 0;
}
5 changes: 5 additions & 0 deletions src/main/c/jpy_conv.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ PyObject* JPy_FromJObjectWithType(JNIEnv* jenv, jobject objectRef, JPy_JType* ty
*/
int JPy_AsJString(JNIEnv* jenv, PyObject* pyObj, jstring* stringRef);

/**
* Convert Python buffer object to Java ByteBuffer (direct) which shares the underlying buffer in a read-only way..
*/
int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer **pyBuffer, jobject* byteBufferRef);

/**
* Convert any Python objects to Java object.
*
Expand Down
1 change: 0 additions & 1 deletion src/main/c/jpy_jobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,6 @@ int JType_InitSlots(JPy_JType* type)
PyTypeObject* typeObj;
jboolean isArray;
jboolean isPrimitiveArray;
jboolean isByteBuffer;

isArray = type->componentType != NULL;
isPrimitiveArray = isArray && type->componentType->isPrimitive;
Expand Down
48 changes: 48 additions & 0 deletions src/main/c/jpy_jtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void JType_InitMethodParamDescriptorFunctions(JPy_JType* type, JPy_JMethod* meth
int JType_ProcessField(JNIEnv* jenv, JPy_JType* declaringType, PyObject* fieldKey, const char* fieldName, jclass fieldClassRef, jboolean isStatic, jboolean isFinal, jfieldID fid);
void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data);
void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data);
void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data);
void JType_DisposeWritableBufferArg(JNIEnv* jenv, jvalue* value, void* data);


Expand Down Expand Up @@ -1652,6 +1653,31 @@ int JType_ConvertPyArgToJStringArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescr
return JPy_AsJString(jenv, pyArg, &value->l);
}

int JType_MatchPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg)
{
if (pyArg == Py_None) {
// Signal it is possible, but give low priority since we cannot perform any type checks on 'None'
return 1;
}

if (PyObject_CheckBuffer(pyArg) == 1) {
return 100;
}
return 0;
}

int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer)
{
Py_buffer *pyBuffer;
int ret;

ret = JPy_AsJByteBuffer(jenv, pyArg, &pyBuffer, &value->l);

disposer->data = pyBuffer;
disposer->DisposeArg = JType_DisposeReadOnlyByteBufferArg;

}

int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer)
{
disposer->data = NULL;
Expand Down Expand Up @@ -2368,6 +2394,25 @@ void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data)
}
}

void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data)
{
Py_buffer* pyBuffer;
jobject jByteBuffer;

pyBuffer = (Py_buffer*) data;
jByteBuffer = (jobject) value->l;

JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JType_DisposeReadOnlyByteBufferArg: pyBuffer=%p, jByteBuffer=%p\n", pyBuffer, jByteBuffer);

if (pyBuffer != NULL) {
PyBuffer_Release(pyBuffer);
PyMem_Del(pyBuffer);
}
if (jByteBuffer != NULL) {
JPy_DELETE_LOCAL_REF(jByteBuffer);
}
}

void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data)
{
Py_buffer* pyBuffer;
Expand Down Expand Up @@ -2451,6 +2496,9 @@ void JType_InitParamDescriptorFunctions(JPy_ParamDescriptor* paramDescriptor, jb
} else if (paramType == JPy_JString) {
paramDescriptor->MatchPyArg = JType_MatchPyArgAsJStringParam;
paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJStringArg;
} else if (paramType == JPy_JByteBuffer) {
paramDescriptor->MatchPyArg = JType_MatchPyArgAsJByteBufferParam;
paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJByteBufferArg;
//} else if (paramType == JPy_JMap) {
//} else if (paramType == JPy_JList) {
//} else if (paramType == JPy_JSet) {
Expand Down
25 changes: 8 additions & 17 deletions src/main/c/jpy_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ JPy_JType* JPy_JThrowable = NULL;
JPy_JType* JPy_JStackTraceElement = NULL;
JPy_JType* JPy_JByteBuffer = NULL;


// java.lang.Comparable
jclass JPy_Comparable_JClass = NULL;
jmethodID JPy_Comparable_CompareTo_MID = NULL;
Expand Down Expand Up @@ -235,6 +234,7 @@ jclass JPy_String_JClass = NULL;
jclass JPy_PyObject_JClass = NULL;
jclass JPy_PyDictWrapper_JClass = NULL;
jclass JPy_ByteBuffer_JClass = NULL;
jmethodID JPy_ByteBuffer_AsReadOnlyBuffer_MID = NULL;

jmethodID JPy_PyObject_GetPointer_MID = NULL;
jmethodID JPy_PyObject_UnwrapProxy_SMID = NULL;
Expand Down Expand Up @@ -684,34 +684,22 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args)
return NULL;
}

pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer));
if (pyBuffer == NULL) {
return PyErr_NoMemory();
}

if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) {
PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer.");
PyMem_Free(pyBuffer);
if (JPy_AsJByteBuffer(jenv, pyObj, &pyBuffer, &byteBufferRef) == -1) {
return NULL;
}

byteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len);
if (byteBufferRef == NULL) {
PyBuffer_Release(pyBuffer);
PyMem_Free(pyBuffer);
return PyErr_NoMemory();
}

newPyObj = JObj_New(jenv, byteBufferRef);
if (newPyObj == NULL) {
PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance.");
PyBuffer_Release(pyBuffer);
PyMem_Free(pyBuffer);
JPy_DELETE_LOCAL_REF(byteBufferRef);
return NULL;
}

byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj;
byteBufferWrapper->pyBuffer = pyBuffer;
return (PyObject *)byteBufferWrapper;

}

PyObject* JPy_byte_buffer(PyObject* self, PyObject* args)
Expand Down Expand Up @@ -987,6 +975,8 @@ int JPy_InitGlobalVars(JNIEnv* jenv)
DEFINE_CLASS(JPy_Throwable_JClass, "java/lang/Throwable");
DEFINE_CLASS(JPy_StackTraceElement_JClass, "java/lang/StackTraceElement");
DEFINE_CLASS(JPy_ByteBuffer_JClass, "java/nio/ByteBuffer");
DEFINE_METHOD(JPy_ByteBuffer_AsReadOnlyBuffer_MID, JPy_ByteBuffer_JClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");


// Non-Object types: Primitive types and void.
DEFINE_NON_OBJECT_TYPE(JPy_JBoolean, JPy_Boolean_JClass);
Expand Down Expand Up @@ -1115,6 +1105,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv)
JPy_Number_DoubleValue_MID = NULL;
JPy_PyObject_GetPointer_MID = NULL;
JPy_PyObject_UnwrapProxy_SMID = NULL;
JPy_ByteBuffer_AsReadOnlyBuffer_MID = NULL;

JPy_XDECREF(JPy_JBoolean);
JPy_XDECREF(JPy_JChar);
Expand Down
3 changes: 3 additions & 0 deletions src/main/c/jpy_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ extern jmethodID JPy_Number_DoubleValue_MID;
extern jclass JPy_String_JClass;
extern jclass JPy_Void_JClass;

extern jclass JPy_ByteBuffer_JClass;
extern jmethodID JPy_ByteBuffer_AsReadOnlyBuffer_MID;

extern jclass JPy_PyObject_JClass;
extern jmethodID JPy_PyObject_GetPointer_MID;
extern jmethodID JPy_PyObject_UnwrapProxy_SMID;
Expand Down

0 comments on commit 9fe3362

Please sign in to comment.