Newer
Older
// Wrapper-helping odds and ends
//
// Copyright (C) 2009 Andreas Kloeckner
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#ifndef PYCUDA_WRAP_HELPERS_HEADER_SEEN
#define PYCUDA_WRAP_HELPERS_HEADER_SEEN
#include <pybind11/pybind11.h>
namespace py = pybind11;
#define PYTHON_ERROR(TYPE, REASON) \
{ \
PyErr_SetString(PyExc_##TYPE, REASON); \
throw boost::python::error_already_set(); \
}
#define ENUM_VALUE(NAME) \
value(#NAME, NAME)
#define DEF_SIMPLE_METHOD(NAME) \
def(#NAME, &cls::NAME)
#define DEF_SIMPLE_STATIC_METHOD(NAME) \
def_static(#NAME, &cls::NAME)
#define DEF_SIMPLE_METHOD_WITH_ARGS(NAME, ARGS) \
def(#NAME, &cls::NAME, boost::python::args ARGS)
#define DEF_SIMPLE_FUNCTION(NAME) \
#define DEF_SIMPLE_FUNCTION_WITH_ARGS(NAME, ARGS) \
m.def(#NAME, &NAME, py::args ARGS)
#define DEF_SIMPLE_RO_MEMBER(NAME) \
def_readonly(#NAME, &cls::m_##NAME)
#define DEF_SIMPLE_RW_MEMBER(NAME) \
def_readwrite(#NAME, &cls::m_##NAME)
// }}}
// {{{ COPY_PY_XXX
{ \
for (auto it: py_##NAME) \
NAME.push_back(py::cast<TYPE>(it)); \
#define COPY_PY_ARRAY(FUNC_NAME, TYPE, NAME, COUNTER) \
{ \
COUNTER = 0; \
for (auto it: py_##NAME) \
{ \
if (COUNTER == NAME.size()) \
throw error(FUNC_NAME, \
CL_INVALID_VALUE, "too many entries in " #NAME " argument"); \
NAME[COUNTER++] = py::cast<TYPE>(it); \
#define COPY_PY_COORD_TRIPLE(NAME) \
size_t NAME[3] = {0, 0, 0}; \
{ \
py::sequence py_seq_##NAME = py::cast<py::sequence>(py_##NAME); \
size_t my_len = len(py_seq_##NAME); \
if (my_len > 3) \
throw error("transfer", CL_INVALID_VALUE, #NAME "has too many components"); \
for (size_t i = 0; i < my_len; ++i) \
NAME[i] = py::cast<size_t>(py_seq_##NAME[i]); \
}
#define COPY_PY_PITCH_TUPLE(NAME) \
size_t NAME[2] = {0, 0}; \
if (py_##NAME.ptr() != Py_None) \
{ \
py::sequence py_seq_##NAME = py::cast<py::sequence>(py_##NAME); \
size_t my_len = len(py_seq_##NAME); \
if (my_len > 2) \
throw error("transfer", CL_INVALID_VALUE, #NAME "has too many components"); \
for (size_t i = 0; i < my_len; ++i) \
NAME[i] = py::cast<size_t>(py_seq_##NAME[i]); \
}
#define COPY_PY_REGION_TRIPLE(NAME) \
size_t NAME[3] = {1, 1, 1}; \
{ \
py::sequence py_seq_##NAME = py::cast<py::sequence>(py_##NAME); \
size_t my_len = len(py_seq_##NAME); \
if (my_len > 3) \
throw error("transfer", CL_INVALID_VALUE, #NAME "has too many components"); \
for (size_t i = 0; i < my_len; ++i) \
NAME[i] = py::cast<size_t>(py_seq_##NAME[i]); \
// }}}
#define PYOPENCL_PARSE_NUMPY_ARRAY_SPEC \
PyArray_Descr *tp_descr; \
if (PyArray_DescrConverter(dtype.ptr(), &tp_descr) != NPY_SUCCEED) \
throw py::error_already_set(); \
\
std::vector<npy_intp> shape; \
shape.push_back(py::cast<npy_intp>(py_shape)); \
} \
catch (py::cast_error &) \
{ \
\
NPY_ORDER order = PyArray_CORDER; \
PyArray_OrderConverter(py_order.ptr(), &order); \
\
int ary_flags = 0; \
if (order == PyArray_FORTRANORDER) \
ary_flags |= NPY_FARRAY; \
else if (order == PyArray_CORDER) \
ary_flags |= NPY_CARRAY; \
else \
throw std::runtime_error("unrecognized order specifier"); \
\
std::vector<npy_intp> strides; \
if (py_strides.ptr() != Py_None) \
{ \
COPY_PY_LIST(npy_intp, strides); \
}
#define PYOPENCL_RETURN_VECTOR(ITEMTYPE, NAME) \
{ \
py::list pyopencl_result; \
pyopencl_result.append(item); \
return pyopencl_result; \
}
namespace
{
template <typename T>
inline py::object handle_from_new_ptr(T *ptr)
return py::cast(ptr, py::return_value_policy::take_ownership);
}
template <typename T, typename ClType>
inline T *from_int_ptr(intptr_t obj_ref, bool retain)
{
ClType clobj = (ClType) obj_ref;
return new T(clobj, retain);
}
template <typename T>
inline intptr_t to_int_ptr(T const &obj)
{
return (intptr_t) obj.data();
}
}
#define PYOPENCL_EXPOSE_TO_FROM_INT_PTR(CL_TYPENAME) \
.def_static("from_int_ptr", from_int_ptr<cls, CL_TYPENAME>, \
py::arg("retain")=true, \
"(static method) Return a new Python object referencing the C-level " \
":c:type:`" #CL_TYPENAME "` object at the location pointed to " \
"by *int_ptr_value*. The relevant ``clRetain*`` function " \
"will be called if *retain* is True." \
"If the previous owner of the object will *not* release the reference, " \
"*retain* should be set to *False*, to effectively transfer ownership to " \
":mod:`pyopencl`." \
"\n\n.. versionadded:: 2013.2\n" \
"\n\n.. versionchanged:: 2016.1\n\n *retain* added.") \
.def_property_readonly("int_ptr", to_int_ptr<cls>, \
"Return an integer corresponding to the pointer value " \
"of the underlying :c:type:`" #CL_TYPENAME "`. " \
"Use :meth:`from_int_ptr` to turn back into a Python object." \
"\n\n.. versionadded:: 2013.2\n") \
#endif