diff --git a/src/Converters.cxx b/src/Converters.cxx index 602e3c9..1f1c681 100644 --- a/src/Converters.cxx +++ b/src/Converters.cxx @@ -1572,6 +1572,42 @@ bool CPyCppyy::VoidArrayConverter::ToMemory(PyObject* value, void* address, PyOb return true; } +namespace { + +// Copy a buffer to memory address with an array converter. +template +bool ToArrayFromBuffer(PyObject* owner, void* address, PyObject* ctxt, + const void * buf, Py_ssize_t buflen, + CPyCppyy::dims_t& shape, bool isFixed) +{ + if (buflen == 0) + return false; + + Py_ssize_t oldsz = 1; + for (Py_ssize_t idim = 0; idim < shape.ndim(); ++idim) { + if (shape[idim] == CPyCppyy::UNKNOWN_SIZE) { + oldsz = -1; + break; + } + oldsz *= shape[idim]; + } + if (shape.ndim() != CPyCppyy::UNKNOWN_SIZE && 0 < oldsz && oldsz < buflen) { + PyErr_SetString(PyExc_ValueError, "buffer too large for value"); + return false; + } + + if (isFixed) + memcpy(*(type**)address, buf, (0 < buflen ? buflen : 1)*sizeof(type)); + else { + *(type**)address = (type*)buf; + shape.ndim(1); + shape[0] = buflen; + SetLifeLine(ctxt, owner, (intptr_t)address); + } + return true; +} + +} //---------------------------------------------------------------------------- #define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code, suffix) \ @@ -1652,31 +1688,7 @@ bool CPyCppyy::name##ArrayConverter::ToMemory( \ if (fShape.ndim() <= 1 || fIsFixed) { \ void* buf = nullptr; \ Py_ssize_t buflen = Utility::GetBuffer(value, code, sizeof(type), buf);\ - if (buflen == 0) \ - return false; \ - \ - Py_ssize_t oldsz = 1; \ - for (Py_ssize_t idim = 0; idim < fShape.ndim(); ++idim) { \ - if (fShape[idim] == UNKNOWN_SIZE) { \ - oldsz = -1; \ - break; \ - } \ - oldsz *= fShape[idim]; \ - } \ - if (fShape.ndim() != UNKNOWN_SIZE && 0 < oldsz && oldsz < buflen) { \ - PyErr_SetString(PyExc_ValueError, "buffer too large for value"); \ - return false; \ - } \ - \ - if (fIsFixed) \ - memcpy(*(type**)address, buf, (0 < buflen ? buflen : 1)*sizeof(type));\ - else { \ - *(type**)address = (type*)buf; \ - fShape.ndim(1); \ - fShape[0] = buflen; \ - SetLifeLine(ctxt, value, (intptr_t)address); \ - } \ - \ + return ToArrayFromBuffer(value, address, ctxt, buf, buflen, fShape, fIsFixed);\ } else { /* multi-dim, non-flat array; assume structure matches */ \ void* buf = nullptr; /* TODO: GetBuffer() assumes flat? */ \ Py_ssize_t buflen = Utility::GetBuffer(value, code, sizeof(void*), buf);\ @@ -1775,6 +1787,18 @@ PyObject* CPyCppyy::CStringArrayConverter::FromMemory(void* address) return CreateLowLevelViewString(*(const char***)address, fShape); } +//---------------------------------------------------------------------------- +bool CPyCppyy::CStringArrayConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt) +{ +// As a special array converter, the CStringArrayConverter one can also copy strings in the array, +// and not only buffers. + Py_ssize_t len; + if (const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len)) { + return ToArrayFromBuffer(value, address, ctxt, cstr, len, fShape, fIsFixed); + } + return SCharArrayConverter::ToMemory(value, address, ctxt); +} + //---------------------------------------------------------------------------- PyObject* CPyCppyy::NonConstCStringArrayConverter::FromMemory(void* address) { diff --git a/src/DeclareConverters.h b/src/DeclareConverters.h index a0985a7..6062e6d 100644 --- a/src/DeclareConverters.h +++ b/src/DeclareConverters.h @@ -229,6 +229,7 @@ class CStringArrayConverter : public SCharArrayConverter { using SCharArrayConverter::SCharArrayConverter; virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject*, void*, PyObject* = nullptr); private: std::vector fBuffer;