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

Add jpy.byte_buffer() function #112

Merged
1 change: 0 additions & 1 deletion src/main/c/jpy_conv.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,3 @@ int JPy_AsJString(JNIEnv* jenv, PyObject* arg, jstring* stringRef)

return 0;
}

24 changes: 24 additions & 0 deletions src/main/c/jpy_jbyte_buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 JPY-CONSORTIUM Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "jpy_module.h"
#include "jpy_diag.h"
#include "jpy_jarray.h"
#include "jpy_jbyte_buffer.h"

/*
* This file for now is just a place-holder for future JPy_JByteBufferObj specific functions.
*/
44 changes: 44 additions & 0 deletions src/main/c/jpy_jbyte_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2023 JPY-CONSORTIUM Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JPY_JBYTE_BUFFER_H
#define JPY_JBYTE_BUFFER_H

#ifdef __cplusplus
extern "C" {
#endif

#include "jpy_compat.h"

/**
* The Java ByteBuffer representation in Python.
*
* IMPORTANT: JPy_JByteBufferObj must only differ from the JPy_JObj structure by the 'pyBuffer' member
* since we use the same basic type, name JPy_JType for it. DON'T ever change member positions!
* @see JPy_JObj
*/
typedef struct JPy_JByteBufferObj
{
PyObject_HEAD
jobject objectRef;
Py_buffer *pyBuffer;
}
JPy_JByteBufferObj;

#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* !JPY_JBYTE_BUFFER_H */
37 changes: 33 additions & 4 deletions src/main/c/jpy_jobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "jpy_module.h"
#include "jpy_diag.h"
#include "jpy_jarray.h"
#include "jpy_jbyte_buffer.h"
#include "jpy_jtype.h"
#include "jpy_jobj.h"
#include "jpy_jmethod.h"
Expand Down Expand Up @@ -63,9 +64,15 @@ PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef)
array = (JPy_JArray*) obj;
array->bufferExportCount = 0;
array->buf = NULL;
} else if (JByteBuffer_Check(type)) {
JPy_JByteBufferObj *byteBuffer;

byteBuffer = (JPy_JByteBufferObj *) obj;
byteBuffer->pyBuffer = NULL;
}

// we check the type translations dictionary for a callable for this java type name,

// we check the type translations dictionary for a callable for this java type name,
// and apply the returned callable to the wrapped object
callable = PyDict_GetItemString(JPy_Type_Translations, type->javaName);
if (callable != NULL) {
Expand Down Expand Up @@ -181,8 +188,14 @@ void JObj_dealloc(JPy_JObj* self)
if (array->buf != NULL) {
JArray_ReleaseJavaArrayElements(array, array->javaType);
}

}
} else if (JByteBuffer_Check(jtype)) {
JPy_JByteBufferObj *byteBuffer;
byteBuffer = (JPy_JByteBufferObj *) self;
if (byteBuffer->pyBuffer != NULL) {
PyBuffer_Release(byteBuffer->pyBuffer);
PyMem_Free(byteBuffer->pyBuffer);
}
}

jenv = JPy_GetJNIEnv();
if (jenv != NULL) {
Expand Down Expand Up @@ -727,7 +740,13 @@ int JType_InitSlots(JPy_JType* type)
//Py_SET_TYPE(type, &JType_Type);
//Py_SET_SIZE(type, sizeof (JPy_JType));

typeObj->tp_basicsize = isPrimitiveArray ? sizeof (JPy_JArray) : sizeof (JPy_JObj);
if (isPrimitiveArray) {
typeObj->tp_basicsize = sizeof(JPy_JArray);
} else if (JByteBuffer_Check(type)) {
typeObj->tp_basicsize = sizeof(JPy_JByteBufferObj);
} else {
typeObj->tp_basicsize = sizeof(JPy_JObj);
}
typeObj->tp_itemsize = 0;
typeObj->tp_base = type->superType != NULL ? JTYPE_AS_PYTYPE(type->superType) : &JType_Type;
//typeObj->tp_base = (PyTypeObject*) type->superType;
Expand Down Expand Up @@ -822,3 +841,13 @@ int JType_Check(PyObject* arg)
return PyType_Check(arg) && JPY_IS_JTYPE(arg);
}

int JByteBuffer_Check(JPy_JType* type) {
while (type != NULL) {
if (type == JPy_JByteBuffer || strcmp(type->javaName, "java.nio.ByteBuffer") == 0) {
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
JPy_DIAG_PRINT(JPy_DIAG_F_TYPE, "JByteBuffer_Check: java ByteBuffer or its sub-type (%s) found.\n", type->javaName);
return -1;
}
type = type->superType;
}
return 0;
}
2 changes: 2 additions & 0 deletions src/main/c/jpy_jobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ JPy_JObj;

int JObj_Check(PyObject* arg);

int JByteBuffer_Check(JPy_JType* type);

PyObject* JObj_New(JNIEnv* jenv, jobject objectRef);
PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef);

Expand Down
2 changes: 1 addition & 1 deletion src/main/c/jpy_jtype.c
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "jpy_jfield.h"
#include "jpy_jmethod.h"
#include "jpy_jobj.h"
#include "jpy_jbyte_buffer.h"
#include "jpy_conv.h"
#include "jpy_compat.h"

Expand Down Expand Up @@ -1659,7 +1660,6 @@ int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDes
return JType_CreateJavaPyObject(jenv, JPy_JPyObject, pyArg, &value->l);
}


int JType_MatchPyArgAsJPyObjectParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg)
{
// We can always turn a python object into a PyObject
Expand Down
99 changes: 98 additions & 1 deletion src/main/c/jpy_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "jpy_jobj.h"
#include "jpy_conv.h"
#include "jpy_compat.h"
#include "jpy_jbyte_buffer.h"


#include <stdlib.h>
Expand All @@ -38,6 +39,7 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args);
PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds);
PyObject* JPy_cast(PyObject* self, PyObject* args);
PyObject* JPy_array(PyObject* self, PyObject* args);
PyObject* JPy_byte_buffer(PyObject* self, PyObject* args);


static PyMethodDef JPy_Functions[] = {
Expand All @@ -63,6 +65,11 @@ static PyMethodDef JPy_Functions[] = {
"array(name, init) - Return a new Java array of given Java type (type name or type object) and initializer (array length or sequence). "
"Possible primitive types are 'boolean', 'byte', 'char', 'short', 'int', 'long', 'float', and 'double'."},

{"byte_buffer", JPy_byte_buffer, METH_VARARGS,
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
"byte_buffer(obj) - Return a new Java direct ByteBuffer sharing the same underlying, contiguous buffer of obj via its implemented Buffer Protocol. The resulting PYObject must live "
"longer than the Java object to ensure the underlying data remains valid. In most cases, this means that java functions called in this manner must not keep any references"
" to the ByteBuffer"},

{NULL, NULL, 0, NULL} /*Sentinel*/
};

Expand Down Expand Up @@ -126,7 +133,7 @@ JPy_JType* JPy_JPyObject = NULL;
JPy_JType* JPy_JPyModule = NULL;
JPy_JType* JPy_JThrowable = NULL;
JPy_JType* JPy_JStackTraceElement = NULL;

JPy_JType* JPy_JByteBuffer = NULL;

// java.lang.Comparable
jclass JPy_Comparable_JClass = NULL;
Expand Down Expand Up @@ -228,6 +235,8 @@ jclass JPy_Void_JClass = NULL;
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 @@ -660,6 +669,83 @@ PyObject* JPy_array(PyObject* self, PyObject* args)
JPy_FRAME(PyObject*, NULL, JPy_array_internal(jenv, self, args), 16)
}

PyObject* JType_CreateJavaByteBufferObj(JNIEnv* jenv, PyObject* pyObj)
{
jobject byteBufferRef, tmpByteBufferRef;
Py_buffer *pyBuffer;
PyObject *newPyObj;
JPy_JByteBufferObj* byteBuffer;

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

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

tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len);
if (tmpByteBufferRef == NULL) {
PyBuffer_Release(pyBuffer);
PyMem_Free(pyBuffer);
PyErr_NoMemory();
return NULL;
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
}

byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID);
if (byteBufferRef == NULL) {
PyBuffer_Release(pyBuffer);
PyMem_Free(pyBuffer);
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
JPy_DELETE_LOCAL_REF(tmpByteBufferRef);
PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only direct ByteBuffer instance.");
return NULL;
}
JPy_DELETE_LOCAL_REF(tmpByteBufferRef);

newPyObj = JObj_New(jenv, byteBufferRef);
if (newPyObj == NULL) {
PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a byteBuffer instance.");
PyBuffer_Release(pyBuffer);
PyMem_Free(pyBuffer);
JPy_DELETE_LOCAL_REF(byteBufferRef);
return NULL;
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
}
JPy_DELETE_LOCAL_REF(byteBufferRef);

byteBuffer = (JPy_JByteBufferObj *) newPyObj;
byteBuffer->pyBuffer = pyBuffer;
return (PyObject *)byteBuffer;
}

PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args)
{
jobject byteBufferRef;
PyObject* pyObj;
PyObject* newPyObj;
Py_buffer *pyBuffer;
JPy_JByteBufferObj* byteBuffer;

if (!PyArg_ParseTuple(args, "O:byte_buffer", &pyObj)) {
return NULL;
jmao-denver marked this conversation as resolved.
Show resolved Hide resolved
}

if (PyObject_CheckBuffer(pyObj) == 0) {
PyErr_SetString(PyExc_ValueError, "byte_buffer: argument 1 must be a Python object that supports the buffer protocol.");
return NULL;
}

return JType_CreateJavaByteBufferObj(jenv, pyObj);
}

PyObject* JPy_byte_buffer(PyObject* self, PyObject* args)
{
JPy_FRAME(PyObject*, NULL, JPy_byte_buffer_internal(jenv, self, args), 16)
}

JPy_JType* JPy_GetNonObjectJType(JNIEnv* jenv, jclass classRef)
{
jclass primClassRef;
Expand Down Expand Up @@ -927,6 +1013,9 @@ int JPy_InitGlobalVars(JNIEnv* jenv)
DEFINE_CLASS(JPy_String_JClass, "java/lang/String");
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 All @@ -953,6 +1042,8 @@ int JPy_InitGlobalVars(JNIEnv* jenv)
DEFINE_OBJECT_TYPE(JPy_JDoubleObj, JPy_Double_JClass);
// Other objects.
DEFINE_OBJECT_TYPE(JPy_JString, JPy_String_JClass);
DEFINE_OBJECT_TYPE(JPy_JByteBuffer, JPy_ByteBuffer_JClass);

DEFINE_OBJECT_TYPE(JPy_JThrowable, JPy_Throwable_JClass);
DEFINE_OBJECT_TYPE(JPy_JStackTraceElement, JPy_StackTraceElement_JClass);
DEFINE_METHOD(JPy_Throwable_getCause_MID, JPy_Throwable_JClass, "getCause", "()Ljava/lang/Throwable;");
Expand Down Expand Up @@ -994,6 +1085,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv)
(*jenv)->DeleteGlobalRef(jenv, JPy_Number_JClass);
(*jenv)->DeleteGlobalRef(jenv, JPy_Void_JClass);
(*jenv)->DeleteGlobalRef(jenv, JPy_String_JClass);
(*jenv)->DeleteGlobalRef(jenv, JPy_ByteBuffer_JClass);
}

JPy_Comparable_JClass = NULL;
Expand All @@ -1014,6 +1106,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv)
JPy_Number_JClass = NULL;
JPy_Void_JClass = NULL;
JPy_String_JClass = NULL;
JPy_ByteBuffer_JClass = NULL;

JPy_Object_ToString_MID = NULL;
JPy_Object_HashCode_MID = NULL;
Expand Down Expand Up @@ -1051,6 +1144,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 All @@ -1061,6 +1155,8 @@ void JPy_ClearGlobalVars(JNIEnv* jenv)
JPy_XDECREF(JPy_JFloat);
JPy_XDECREF(JPy_JDouble);
JPy_XDECREF(JPy_JVoid);
JPy_XDECREF(JPy_JString);
JPy_XDECREF(JPy_JByteBuffer);
JPy_XDECREF(JPy_JBooleanObj);
JPy_XDECREF(JPy_JCharacterObj);
JPy_XDECREF(JPy_JByteObj);
Expand All @@ -1082,6 +1178,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv)
JPy_JDouble = NULL;
JPy_JVoid = NULL;
JPy_JString = NULL;
JPy_JByteBuffer = NULL;
JPy_JBooleanObj = NULL;
JPy_JCharacterObj = NULL;
JPy_JByteObj = NULL;
Expand Down
4 changes: 4 additions & 0 deletions src/main/c/jpy_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ extern struct JPy_JType* JPy_JClass;
extern struct JPy_JType* JPy_JString;
extern struct JPy_JType* JPy_JPyObject;
extern struct JPy_JType* JPy_JPyModule;
extern struct JPy_JType* JPy_JByteBuffer;

// java.lang.Comparable
extern jclass JPy_Comparable_JClass;
Expand Down Expand Up @@ -250,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
Loading