mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Merged in py3k-buffer branch to main line. All objects now use the buffer protocol in PEP 3118.
This commit is contained in:
parent
3de862df45
commit
b99f762f10
22 changed files with 1732 additions and 688 deletions
|
@ -739,22 +739,33 @@ CharArray_set_raw(CDataObject *self, PyObject *value)
|
|||
{
|
||||
char *ptr;
|
||||
Py_ssize_t size;
|
||||
int rel = 0;
|
||||
PyBuffer view;
|
||||
|
||||
if (PyBuffer_Check(value)) {
|
||||
size = Py_Type(value)->tp_as_buffer->bf_getreadbuffer(value, 0, (void *)&ptr);
|
||||
if (size < 0)
|
||||
return -1;
|
||||
if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) < 0)
|
||||
return -1;
|
||||
size = view.len;
|
||||
ptr = view.buf;
|
||||
rel = 1;
|
||||
} else if (-1 == PyString_AsStringAndSize(value, &ptr, &size)) {
|
||||
return -1;
|
||||
}
|
||||
if (size > self->b_size) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"string too long");
|
||||
return -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(self->b_ptr, ptr, size);
|
||||
|
||||
if (rel)
|
||||
PyObject_ReleaseBuffer(value, &view);
|
||||
return 0;
|
||||
fail:
|
||||
if (rel)
|
||||
PyObject_ReleaseBuffer(value, &view);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -2072,29 +2083,15 @@ static PyMemberDef CData_members[] = {
|
|||
{ NULL },
|
||||
};
|
||||
|
||||
static Py_ssize_t CData_GetBuffer(PyObject *_self, Py_ssize_t seg, void **pptr)
|
||||
static int CData_GetBuffer(PyObject *_self, PyBuffer *view, int flags)
|
||||
{
|
||||
CDataObject *self = (CDataObject *)_self;
|
||||
if (seg != 0) {
|
||||
/* Hm. Must this set an exception? */
|
||||
return -1;
|
||||
}
|
||||
*pptr = self->b_ptr;
|
||||
return self->b_size;
|
||||
}
|
||||
|
||||
static Py_ssize_t CData_GetSegcount(PyObject *_self, Py_ssize_t *lenp)
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 1;
|
||||
return 1;
|
||||
return PyBuffer_FillInfo(view, self->b_ptr, self->b_size, 0, flags);
|
||||
}
|
||||
|
||||
static PyBufferProcs CData_as_buffer = {
|
||||
CData_GetBuffer,
|
||||
CData_GetBuffer,
|
||||
CData_GetSegcount,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1672,44 +1672,38 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
|
|||
Py_ssize_t size, bytes;
|
||||
int charsize;
|
||||
void* ptr;
|
||||
|
||||
#if defined(HAVE_UNICODE)
|
||||
if (PyUnicode_Check(string)) {
|
||||
/* unicode strings doesn't always support the buffer interface */
|
||||
ptr = (void*) PyUnicode_AS_DATA(string);
|
||||
bytes = PyUnicode_GET_DATA_SIZE(string);
|
||||
size = PyUnicode_GET_SIZE(string);
|
||||
charsize = sizeof(Py_UNICODE);
|
||||
|
||||
} else {
|
||||
#endif
|
||||
PyBuffer view;
|
||||
|
||||
/* get pointer to string buffer */
|
||||
view.len = -1;
|
||||
buffer = Py_Type(string)->tp_as_buffer;
|
||||
if (!buffer || !buffer->bf_getreadbuffer || !buffer->bf_getsegcount ||
|
||||
buffer->bf_getsegcount(string, NULL) != 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected string or buffer");
|
||||
return NULL;
|
||||
if (!buffer || !buffer->bf_getbuffer ||
|
||||
(*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) < 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected string or buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* determine buffer size */
|
||||
bytes = buffer->bf_getreadbuffer(string, 0, &ptr);
|
||||
bytes = view.len;
|
||||
ptr = view.buf;
|
||||
|
||||
/* Release the buffer immediately --- possibly dangerous
|
||||
but doing something else would require some re-factoring
|
||||
*/
|
||||
PyObject_ReleaseBuffer(string, &view);
|
||||
|
||||
if (bytes < 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "buffer has negative size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* determine character size */
|
||||
#if PY_VERSION_HEX >= 0x01060000
|
||||
size = PyObject_Size(string);
|
||||
#else
|
||||
size = PyObject_Length(string);
|
||||
#endif
|
||||
|
||||
if (PyString_Check(string) || bytes == size)
|
||||
charsize = 1;
|
||||
#if defined(HAVE_UNICODE)
|
||||
else if (bytes == (Py_ssize_t) (size * sizeof(Py_UNICODE)))
|
||||
else if (bytes == (Py_ssize_t) (size * sizeof(Py_UNICODE)))
|
||||
charsize = sizeof(Py_UNICODE);
|
||||
#endif
|
||||
else {
|
||||
|
@ -1717,13 +1711,13 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(HAVE_UNICODE)
|
||||
}
|
||||
#endif
|
||||
|
||||
*p_length = size;
|
||||
*p_charsize = charsize;
|
||||
|
||||
if (ptr == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Buffer is NULL");
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ struct arraydescr {
|
|||
int itemsize;
|
||||
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
|
||||
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
|
||||
const char *formats;
|
||||
};
|
||||
|
||||
typedef struct arrayobject {
|
||||
|
@ -34,10 +35,19 @@ typedef struct arrayobject {
|
|||
Py_ssize_t allocated;
|
||||
struct arraydescr *ob_descr;
|
||||
PyObject *weakreflist; /* List of weak references */
|
||||
int ob_exports; /* Number of exported buffers */
|
||||
} arrayobject;
|
||||
|
||||
static PyTypeObject Arraytype;
|
||||
|
||||
#ifdef Py_UNICODE_WIDE
|
||||
#define PyArr_UNI 'w'
|
||||
/*static const char *PyArr_UNISTR = "w"; */
|
||||
#else
|
||||
#define PyArr_UNI 'u'
|
||||
/*static const char *PyArr_UNISTR = "u"; */
|
||||
#endif
|
||||
|
||||
#define array_Check(op) PyObject_TypeCheck(op, &Arraytype)
|
||||
#define array_CheckExact(op) (Py_Type(op) == &Arraytype)
|
||||
|
||||
|
@ -59,6 +69,12 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (self->ob_exports > 0) {
|
||||
PyErr_SetString(PyExc_BufferError,
|
||||
"cannot resize an array that is exporting data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This over-allocates proportional to the array size, making room
|
||||
* for additional growth. The over-allocation is mild, but is
|
||||
* enough to give linear-time amortized behavior over a long
|
||||
|
@ -370,11 +386,12 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Description of types */
|
||||
static struct arraydescr descriptors[] = {
|
||||
{'b', sizeof(char), b_getitem, b_setitem},
|
||||
{'B', sizeof(char), BB_getitem, BB_setitem},
|
||||
{'u', sizeof(Py_UNICODE), u_getitem, u_setitem},
|
||||
{PyArr_UNI, sizeof(Py_UNICODE), u_getitem, u_setitem},
|
||||
{'h', sizeof(short), h_getitem, h_setitem},
|
||||
{'H', sizeof(short), HH_getitem, HH_setitem},
|
||||
{'i', sizeof(int), i_getitem, i_setitem},
|
||||
|
@ -424,6 +441,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr)
|
|||
op->ob_descr = descr;
|
||||
op->allocated = size;
|
||||
op->weakreflist = NULL;
|
||||
op->ob_exports = 0;
|
||||
return (PyObject *) op;
|
||||
}
|
||||
|
||||
|
@ -1403,10 +1421,10 @@ array_fromunicode(arrayobject *self, PyObject *args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n))
|
||||
return NULL;
|
||||
if (self->ob_descr->typecode != 'u') {
|
||||
if (self->ob_descr->typecode != PyArr_UNI) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"fromunicode() may only be called on "
|
||||
"type 'u' arrays");
|
||||
"unicode type arrays");
|
||||
return NULL;
|
||||
}
|
||||
if (n > 0) {
|
||||
|
@ -1431,7 +1449,7 @@ PyDoc_STRVAR(fromunicode_doc,
|
|||
"fromunicode(ustr)\n\
|
||||
\n\
|
||||
Extends this array with data from the unicode string ustr.\n\
|
||||
The array must be a type 'u' array; otherwise a ValueError\n\
|
||||
The array must be a unicode type array; otherwise a ValueError\n\
|
||||
is raised. Use array.fromstring(ustr.decode(...)) to\n\
|
||||
append Unicode data to an array of some other type.");
|
||||
|
||||
|
@ -1439,9 +1457,9 @@ append Unicode data to an array of some other type.");
|
|||
static PyObject *
|
||||
array_tounicode(arrayobject *self, PyObject *unused)
|
||||
{
|
||||
if (self->ob_descr->typecode != 'u') {
|
||||
if (self->ob_descr->typecode != PyArr_UNI) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"tounicode() may only be called on type 'u' arrays");
|
||||
"tounicode() may only be called on unicode type arrays");
|
||||
return NULL;
|
||||
}
|
||||
return PyUnicode_FromUnicode((Py_UNICODE *) self->ob_item, Py_Size(self));
|
||||
|
@ -1451,7 +1469,7 @@ PyDoc_STRVAR(tounicode_doc,
|
|||
"tounicode() -> unicode\n\
|
||||
\n\
|
||||
Convert the array to a unicode string. The array must be\n\
|
||||
a type 'u' array; otherwise a ValueError is raised. Use\n\
|
||||
a unicode type array; otherwise a ValueError is raised. Use\n\
|
||||
array.tostring().decode() to obtain a unicode string from\n\
|
||||
an array of some other type.");
|
||||
|
||||
|
@ -1542,7 +1560,7 @@ array_repr(arrayobject *a)
|
|||
if (len == 0) {
|
||||
return PyUnicode_FromFormat("array('%c')", typecode);
|
||||
}
|
||||
if (typecode == 'u')
|
||||
if (typecode == PyArr_UNI)
|
||||
v = array_tounicode(a, NULL);
|
||||
else
|
||||
v = array_tolist(a, NULL);
|
||||
|
@ -1720,40 +1738,56 @@ static PyMappingMethods array_as_mapping = {
|
|||
|
||||
static const void *emptybuf = "";
|
||||
|
||||
static Py_ssize_t
|
||||
array_buffer_getreadbuf(arrayobject *self, Py_ssize_t index, const void **ptr)
|
||||
|
||||
static int
|
||||
array_buffer_getbuf(arrayobject *self, PyBuffer *view, int flags)
|
||||
{
|
||||
if ( index != 0 ) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Accessing non-existent array segment");
|
||||
return -1;
|
||||
}
|
||||
*ptr = (void *)self->ob_item;
|
||||
if (*ptr == NULL)
|
||||
*ptr = emptybuf;
|
||||
return Py_Size(self)*self->ob_descr->itemsize;
|
||||
if ((flags & PyBUF_CHARACTER)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Cannot be a character buffer");
|
||||
return -1;
|
||||
}
|
||||
if ((flags & PyBUF_LOCKDATA)) {
|
||||
PyErr_SetString(PyExc_BufferError,
|
||||
"Cannot lock data");
|
||||
return -1;
|
||||
}
|
||||
if (view==NULL) goto finish;
|
||||
|
||||
view->buf = (void *)self->ob_item;
|
||||
if (view->buf == NULL)
|
||||
view->buf = (void *)emptybuf;
|
||||
view->len = (Py_Size(self)) * self->ob_descr->itemsize;
|
||||
view->readonly = 0;
|
||||
view->ndim = 1;
|
||||
view->itemsize = self->ob_descr->itemsize;
|
||||
view->suboffsets = NULL;
|
||||
view->shape = NULL;
|
||||
if ((flags & PyBUF_ND)==PyBUF_ND) {
|
||||
view->shape = &((Py_Size(self)));
|
||||
}
|
||||
view->strides = NULL;
|
||||
if ((flags & PyBUF_STRIDES)==PyBUF_STRIDES)
|
||||
view->strides = &(view->itemsize);
|
||||
view->format = NULL;
|
||||
view->internal = NULL;
|
||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
|
||||
view->internal = malloc(3);
|
||||
view->format = view->internal;
|
||||
view->format[0] = (char)(self->ob_descr->typecode);
|
||||
view->format[1] = '\0';
|
||||
}
|
||||
|
||||
finish:
|
||||
self->ob_exports++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
array_buffer_getwritebuf(arrayobject *self, Py_ssize_t index, const void **ptr)
|
||||
static void
|
||||
array_buffer_relbuf(arrayobject *self, PyBuffer *view)
|
||||
{
|
||||
if ( index != 0 ) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Accessing non-existent array segment");
|
||||
return -1;
|
||||
}
|
||||
*ptr = (void *)self->ob_item;
|
||||
if (*ptr == NULL)
|
||||
*ptr = emptybuf;
|
||||
return Py_Size(self)*self->ob_descr->itemsize;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
array_buffer_getsegcount(arrayobject *self, Py_ssize_t *lenp)
|
||||
{
|
||||
if ( lenp )
|
||||
*lenp = Py_Size(self)*self->ob_descr->itemsize;
|
||||
return 1;
|
||||
free(view->internal);
|
||||
self->ob_exports--;
|
||||
}
|
||||
|
||||
static PySequenceMethods array_as_sequence = {
|
||||
|
@ -1770,10 +1804,8 @@ static PySequenceMethods array_as_sequence = {
|
|||
};
|
||||
|
||||
static PyBufferProcs array_as_buffer = {
|
||||
(readbufferproc)array_buffer_getreadbuf,
|
||||
(writebufferproc)array_buffer_getwritebuf,
|
||||
(segcountproc)array_buffer_getsegcount,
|
||||
NULL,
|
||||
(getbufferproc)array_buffer_getbuf,
|
||||
(releasebufferproc)array_buffer_relbuf
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
|
@ -1792,7 +1824,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
if (!(initial == NULL || PyList_Check(initial)
|
||||
|| PyBytes_Check(initial)
|
||||
|| PyString_Check(initial) || PyTuple_Check(initial)
|
||||
|| (c == 'u' && PyUnicode_Check(initial)))) {
|
||||
|| (c == PyArr_UNI && PyUnicode_Check(initial)))) {
|
||||
it = PyObject_GetIter(initial);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
|
@ -1900,6 +1932,7 @@ is a single character. The following type codes are defined:\n\
|
|||
'H' unsigned integer 2 \n\
|
||||
'i' signed integer 2 \n\
|
||||
'I' unsigned integer 2 \n\
|
||||
'w' unicode character 4 \n\
|
||||
'l' signed integer 4 \n\
|
||||
'L' unsigned integer 4 \n\
|
||||
'f' floating point 4 \n\
|
||||
|
|
|
@ -75,6 +75,7 @@ typedef struct {
|
|||
char * data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
int exports;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
HANDLE map_handle;
|
||||
|
@ -119,6 +120,11 @@ mmap_object_dealloc(mmap_object *m_obj)
|
|||
static PyObject *
|
||||
mmap_close_method(mmap_object *self, PyObject *unused)
|
||||
{
|
||||
if (self->exports > 0) {
|
||||
PyErr_SetString(PyExc_BufferError, "cannot close "\
|
||||
"exported pointers exist");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
/* For each resource we maintain, we need to check
|
||||
the value is valid, and if so, free the resource
|
||||
|
@ -277,8 +283,13 @@ is_writeable(mmap_object *self)
|
|||
static int
|
||||
is_resizeable(mmap_object *self)
|
||||
{
|
||||
if (self->exports > 0) {
|
||||
PyErr_SetString(PyExc_BufferError,
|
||||
"mmap can't resize with extant buffers exported.");
|
||||
return 0;
|
||||
}
|
||||
if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
|
||||
return 1;
|
||||
return 1;
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"mmap can't resize a readonly or copy-on-write memory map.");
|
||||
return 0;
|
||||
|
@ -589,53 +600,21 @@ static struct PyMethodDef mmap_object_methods[] = {
|
|||
|
||||
/* Functions for treating an mmap'ed file as a buffer */
|
||||
|
||||
static Py_ssize_t
|
||||
mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
|
||||
static int
|
||||
mmap_buffer_getbuf(mmap_object *self, PyBuffer *view, int flags)
|
||||
{
|
||||
CHECK_VALID(-1);
|
||||
if (index != 0) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Accessing non-existent mmap segment");
|
||||
return -1;
|
||||
}
|
||||
*ptr = self->data;
|
||||
return self->size;
|
||||
if (PyBuffer_FillInfo(view, self->data, self->size,
|
||||
(self->access == ACCESS_READ), flags) < 0)
|
||||
return -1;
|
||||
self->exports++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
|
||||
static void
|
||||
mmap_buffer_releasebuf(mmap_object *self, PyBuffer *view)
|
||||
{
|
||||
CHECK_VALID(-1);
|
||||
if (index != 0) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Accessing non-existent mmap segment");
|
||||
return -1;
|
||||
}
|
||||
if (!is_writeable(self))
|
||||
return -1;
|
||||
*ptr = self->data;
|
||||
return self->size;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
|
||||
{
|
||||
CHECK_VALID(-1);
|
||||
if (lenp)
|
||||
*lenp = self->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
|
||||
{
|
||||
if (index != 0) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"accessing non-existent buffer segment");
|
||||
return -1;
|
||||
}
|
||||
*ptr = (const char *)self->data;
|
||||
return self->size;
|
||||
self->exports--;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -775,10 +754,8 @@ static PySequenceMethods mmap_as_sequence = {
|
|||
};
|
||||
|
||||
static PyBufferProcs mmap_as_buffer = {
|
||||
(readbufferproc)mmap_buffer_getreadbuf,
|
||||
(writebufferproc)mmap_buffer_getwritebuf,
|
||||
(segcountproc)mmap_buffer_getsegcount,
|
||||
(charbufferproc)mmap_buffer_getcharbuffer,
|
||||
(getbufferproc)mmap_buffer_getbuf,
|
||||
(releasebufferproc)mmap_buffer_releasebuf,
|
||||
};
|
||||
|
||||
static PyTypeObject mmap_object_type = {
|
||||
|
@ -900,6 +877,7 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
m_obj->data = NULL;
|
||||
m_obj->size = (size_t) map_size;
|
||||
m_obj->pos = (size_t) 0;
|
||||
m_obj->exports = 0;
|
||||
if (fd == -1) {
|
||||
m_obj->fd = -1;
|
||||
/* Assume the caller wants to map anonymous memory.
|
||||
|
@ -1069,6 +1047,7 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
/* set the initial position */
|
||||
m_obj->pos = (size_t) 0;
|
||||
|
||||
m_obj->exports = 0;
|
||||
/* set the tag name */
|
||||
if (tagname != NULL && *tagname != '\0') {
|
||||
m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue