Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/cpython/unicodeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ static inline int Py_UNICODE_ISALNUM(Py_UCS4 ch) {
|| Py_UNICODE_ISNUMERIC(ch));
}

PyAPI_FUNC(int) PyUnicode_GetBuffer(PyObject *unicode, Py_buffer *view, int kind);

/* === Misc functions ===================================================== */

Expand Down
20 changes: 20 additions & 0 deletions Modules/_testcapi/unicode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,25 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
#undef CHECK_FORMAT_0
}

static PyObject *
unicode_get_buffer(PyObject *module, PyObject *args)
{
PyObject *unicode;
int kind;

if (!PyArg_ParseTuple(args, "Oi:unicode_get_buffer", &unicode, &kind)) {
return NULL;
}

Py_buffer view;

if (PyUnicode_GetBuffer(unicode, &view, kind) < 0) {
return NULL;
}

return PyMemoryView_FromBuffer(&view);
}

static PyMethodDef TestMethods[] = {
{"codec_incrementalencoder", codec_incrementalencoder, METH_VARARGS},
{"codec_incrementaldecoder", codec_incrementaldecoder, METH_VARARGS},
Expand Down Expand Up @@ -2093,6 +2112,7 @@ static PyMethodDef TestMethods[] = {
{"unicode_contains", unicode_contains, METH_VARARGS},
{"unicode_isidentifier", unicode_isidentifier, METH_O},
{"unicode_copycharacters", unicode_copycharacters, METH_VARARGS},
{"unicode_get_buffer", unicode_get_buffer, METH_VARARGS},
{NULL},
};

Expand Down
75 changes: 74 additions & 1 deletion Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -14705,6 +14705,79 @@ _PyUnicode_ExactDealloc(PyObject *op)
unicode_dealloc(op);
}

int PyUnicode_GetBuffer(PyObject *unicode, Py_buffer *view, int kind)
{
int itemsize;
view->obj = NULL;
void *data = PyUnicode_DATA(unicode);
bool needs_dealloc = 0;

if (kind == PyUnicode_KIND(unicode)) {
switch (PyUnicode_KIND(unicode)) {
case PyUnicode_1BYTE_KIND:
itemsize = 1;
break;
case PyUnicode_2BYTE_KIND:
itemsize = 2;
break;
case PyUnicode_4BYTE_KIND:
itemsize = 4;
break;
default:
PyErr_BadInternalCall();
return -1;
}
} else if (kind == PyUnicode_4BYTE_KIND) {
needs_dealloc = 1;
itemsize = 4;
data = PyUnicode_AsUCS4Copy(unicode);
if (data == NULL) {
return -1;
}
} else {
PyErr_SetString(PyExc_ValueError,
"str contents cannot encode to requested kind");
return -1;
}

Py_ssize_t length = PyUnicode_GET_LENGTH(unicode) * itemsize;

int res = PyBuffer_FillInfo(
view,
unicode,
data,
length,
1,
0
);

if (res < 0) {
if (needs_dealloc) {
PyMem_Free(data);
}
return res;
}

view->itemsize = itemsize;
view->internal = (void *) needs_dealloc;

return 0;
}

static void unicode_release_buffer(PyObject *unicode, Py_buffer *view)
{
bool needs_dealloc = (bool) view->internal;
if (needs_dealloc) {
PyMem_Free(view->buf);
}
}


static PyBufferProcs unicode_as_buffer = {
// .bf_getbuffer = unicode_get_buffer,
.bf_releasebuffer = unicode_release_buffer,
};

PyDoc_STRVAR(unicode_doc,
"str(object='') -> str\n\
str(bytes_or_buffer[, encoding[, errors]]) -> str\n\
Expand Down Expand Up @@ -14739,7 +14812,7 @@ PyTypeObject PyUnicode_Type = {
(reprfunc) unicode_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
&unicode_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_UNICODE_SUBCLASS |
_Py_TPFLAGS_MATCH_SELF, /* tp_flags */
Expand Down