Skip to content
135 changes: 133 additions & 2 deletions include/dlpack/dlpack.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2017 by Contributors
* Copyright (c) 2017 - by Contributors
* \file dlpack.h
* \brief The common header of DLPack.
*/
Expand Down Expand Up @@ -326,7 +326,7 @@ typedef struct DLManagedTensor {
*
* \note This is the current standard DLPack exchange data structure.
*/
struct DLManagedTensorVersioned {
typedef struct DLManagedTensorVersioned {
/*!
* \brief The API and ABI version of the current managed Tensor
*/
Expand Down Expand Up @@ -360,6 +360,137 @@ struct DLManagedTensorVersioned {
uint64_t flags;
/*! \brief DLTensor which is being memory managed */
DLTensor dl_tensor;
} DLManagedTensorVersioned;

//--------------------------------------------------------------------
// DLPack C functions for speed exchange
//--------------------------------------------------------------------
/*!
* \brief A generic C-style allocator that exposes allocation of a Tensor/Array.
*
* This information can then be used to set allocators of a callee to run allocations.
* This function can be exposed by the framework through the DLPackExchangeAPI.
*
* This particular function does not assume a Python environment; as a result,
* the error handling mechanism is different from Python-related functions.
*
* \param prototype The prototype DLTensor to offer details about the device and shape.
* Other field information will be ignored during allocation.
* \param out The output DLManagedTensorVersioned.
* \param error_ctx The context to set the error.
* \param SetError The function to set the error.
* \return 0 on success, -1 on failure.
* The callee should call SetError(error_ctx, kind, message) to set the error kind and message.
* \note Error propagation via SetError.
*
* \sa DLPackExchangeAPI
*/
typedef int (*DLPackTensorAllocator)( //
DLTensor* prototype, DLManagedTensorVersioned** out, void* error_ctx, //
void (*SetError)(void* error_ctx, const char* kind, const char* message) //
);

/*!
* \brief Exports a PyObject* Tensor/NDArray to a DLManagedTensorVersioned.
*
* This function is a C-style function pointer to quickly convert a PyObject* Tensor/NDArray
* to a DLManagedTensorVersioned without going through the Python Interpreter.
*
* It also provides an option to query the current context stream of the device provided
* by the tensor.
*
* This function is exposed by the framework through the DLPackExchangeAPI.
*
* This information can then be picked up by importers and libraries to run the speed conversion.
* This function should not throw any exceptions; if it fails, it should return -1 and
* set the error message via PyErr_SetXXX.
*
* \param py_object The Python object to convert; this should be PyObject*.
* We use void* to avoid dependency on Python.h.
* \param out The output DLManagedTensorVersioned.
* \param optional_out_env_stream Outputs the current context stream of the device provided
* by the tensor; it can be NULL, in which case the stream will not be queried.
* \return 0 on success, -1 on failure. PyError should be set if -1 is returned.
* \note We use void* to avoid dependency on Python.h, so this specific type is
* not dependent on Python.h and can be copied to dlpack.h.
*
* \sa DLPackExchangeAPI
*/
typedef int (*DLPackFromPyObject)( //
void* py_object, //
DLManagedTensorVersioned** out, //
void** optional_out_env_stream //
);

/*!
* \brief Imports a DLManagedTensorVersioned to a PyObject* Tensor/NDArray.
*
* This function is a C-style function pointer to quickly convert a DLManagedTensorVersioned
* to a PyObject* without going through the Python Interpreter.
*
* This function is exposed by the framework through the DLPackExchangeAPI.
*
* \param tensor The DLManagedTensorVersioned to convert.
* \param out_py_object The output Python object.
* \return 0 on success, -1 on failure. PyError should be set if -1 is returned.
* \note We use void* to avoid dependency on Python.h, so this specific type is
* not dependent on Python.h and can be copied to dlpack.h.
*
* \sa DLPackExchangeAPI
*/
typedef int (*DLPackToPyObject)(DLManagedTensorVersioned* tensor, void** out_py_object);

/*!
* \brief Framework-specific function pointers table for DLPack exchange.
*
* Array/Tensor librarie should statically create and initialize this structure
* then return a pointer to DLPackExchangeAPI as an int value in Tensor/Array.
* The DLPackExchangeAPI* should stay alive throughout the lifetime of process.
*
* One simple way to do so is to create a static instance of DLPackExchangeAPI
* within the framework and return a pointer to it, the following code
* shows an example to do so in c++. It should also be reasonably easy
* to do so in other languages.
*
* \code
* struct MyDLPackExchangeAPI : public DLPackExchangeAPI {
* MyDLPackExchangeAPI() {
* version.major = DLPACK_MAJOR_VERSION;
* version.minor = DLPACK_MINOR_VERSION;
* tensor_allocator = MyDLPackTensorAllocator;
* dlpack_from_py_object = MyDLPackFromPyObject;
* dlpack_to_py_object = MyDLPackToPyObject
* }
*
* const DLPackExchangeAPI* Global() {
* static MyDLPackExchangeAPI inst;
* return &inst;
* }
* };
* \endcode
*
* mypackage.Tensor.__c_dlpack_exchange_api__ = MyPackageDLPackExchangeAPI
*/
struct DLPackExchangeAPI {
/*!
* \brief The current DLPack version.
*/
DLPackVersion version;
/*!
* \brief Framework-specific function pointer for DLPackTensorAllocator
* \sa DLPackTensorAllocator
*/
DLPackTensorAllocator tensor_allocator;
/*!
* \brief Framework-specific function pointer for DLPackFromPyObject
* \sa DLPackFromPyObject
*/
DLPackFromPyObject dlpack_from_py_object;
/*!
* \brief Framework-specific function pointer for DLPackToPyObject
* \sa DLPackToPyObject
*/
DLPackToPyObject dlpack_to_py_object;
};

#ifdef __cplusplus
Expand Down