Commit b99f762f authored by Travis E. Oliphant's avatar Travis E. Oliphant

Merged in py3k-buffer branch to main line. All objects now use the buffer protocol in PEP 3118.

parent 3de862df
......@@ -77,6 +77,7 @@
#include "rangeobject.h"
#include "stringobject.h"
#include "bufferobject.h"
#include "memoryobject.h"
#include "tupleobject.h"
#include "listobject.h"
#include "dictobject.h"
......
......@@ -475,6 +475,12 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
This is the equivalent of the Python statement: del o[key].
*/
/* old buffer API
FIXME: usage of these should all be replaced in Python itself
but for backwards compatibility we will implement them.
Their usage without a corresponding "unlock" mechansim
may create issues (but they would already be there). */
PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj,
const char **buffer,
Py_ssize_t *buffer_len);
......@@ -527,6 +533,110 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
an exception set.
*/
/* new buffer API */
#define PyObject_CheckBuffer(obj) \
(((obj)->ob_type->tp_as_buffer != NULL) && \
((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL))
/* Return 1 if the getbuffer function is available, otherwise
return 0 */
PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, PyBuffer *view,
int flags);
/* This is a C-API version of the getbuffer function call. It checks
to make sure object has the required function pointer and issues the
call. Returns -1 and raises an error on failure and returns 0 on
success
*/
PyAPI_FUNC(void) PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view);
/* C-API version of the releasebuffer function call. It
checks to make sure the object has the required function
pointer and issues the call. The obj must have the buffer
interface or this function will cause a segfault (i.e. it
is assumed to be called only after a corresponding
getbuffer which already verified the existence of the
tp_as_buffer pointer).
Returns 0 on success and -1 (with an error raised) on
failure. This function always succeeds (as a NO-OP) if
there is no releasebuffer function for the object so that
it can always be called when the consumer is done with the
buffer
*/
PyAPI_FUNC(void *) PyBuffer_GetPointer(PyBuffer *view, Py_ssize_t *indices);
/* Get the memory area pointed to by the indices for the buffer given.
Note that view->ndim is the assumed size of indices
*/
PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *);
/* Return the implied itemsize of the data-format area from a
struct-style description */
PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, PyBuffer *view,
Py_ssize_t len, char fort);
PyAPI_FUNC(int) PyBuffer_FromContiguous(PyBuffer *view, void *buf,
Py_ssize_t len, char fort);
/* Copy len bytes of data from the contiguous chunk of memory
pointed to by buf into the buffer exported by obj. Return
0 on success and return -1 and raise a PyBuffer_Error on
error (i.e. the object does not have a buffer interface or
it is not working).
If fortran is 'F', then if the object is multi-dimensional,
then the data will be copied into the array in
Fortran-style (first dimension varies the fastest). If
fortran is 'C', then the data will be copied into the array
in C-style (last dimension varies the fastest). If fortran
is 'A', then it does not matter and the copy will be made
in whatever way is more efficient.
*/
PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src);
/* Copy the data from the src buffer to the buffer of destination
*/
PyAPI_FUNC(int) PyBuffer_IsContiguous(PyBuffer *view, char fortran);
PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims,
Py_ssize_t *shape,
Py_ssize_t *strides,
int itemsize,
char fort);
/* Fill the strides array with byte-strides of a contiguous
(Fortran-style if fortran is 'F' or C-style otherwise)
array of the given shape with the given number of bytes
per element.
*/
PyAPI_FUNC(int) PyBuffer_FillInfo(PyBuffer *view, void *buf,
Py_ssize_t len, int readonly,
int flags);
/* Fills in a buffer-info structure correctly for an exporter
that can only share a contiguous chunk of memory of
"unsigned bytes" of the given length. Returns 0 on success
and -1 (with raising an error) on error.
*/
/* Iterators */
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);
......
......@@ -21,6 +21,7 @@ extern "C" {
/* Object layout */
typedef struct {
PyObject_VAR_HEAD
int ob_exports; /* how many buffer exports */
Py_ssize_t ob_alloc; /* How many bytes allocated */
char *ob_bytes;
} PyBytesObject;
......
/* Memory object interface */
#ifndef Py_MEMORYOBJECT_H
#define Py_MEMORYOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
PyObject_HEAD
PyObject *base;
PyBuffer view;
} PyMemoryViewObject;
PyAPI_DATA(PyTypeObject) PyMemoryView_Type;
#define PyMemory_Check(op) (Py_Type(op) == &PyMemoryView_Type)
#define PyMemoryView(op) (((PyMemoryViewObject *)(op))->view)
#define Py_END_OF_MEMORY (-1)
PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, int buffertype,
char fort);
/* Return a contiguous chunk of memory representing the buffer
from an object in a memory view object. If a copy is made then the
base object for the memory view will be a *new* bytes object.
Otherwise, the base-object will be the object itself and no
data-copying will be done.
The buffertype argument can be PyBUF_READ, PyBUF_WRITE,
PyBUF_UPDATEIFCOPY to determine whether the returned buffer
should be READONLY, WRITEABLE, or set to update the
original buffer if a copy must be made. If buffertype is
PyBUF_WRITE and the buffer is not contiguous an error will
be raised. In this circumstance, the user can use
PyBUF_UPDATEIFCOPY to ensure that a a writeable temporary
contiguous buffer is returned. The contents of this
contiguous buffer will be copied back into the original
object after the memoryview object is deleted as long as
the original object is writeable and allows setting its
memory to "readonly". If this is not allowed by the
original object, then a BufferError is raised.
If the object is multi-dimensional and if fortran is 'F',
the first dimension of the underlying array will vary the
fastest in the buffer. If fortran is 'C', then the last
dimension will vary the fastest (C-style contiguous). If
fortran is 'A', then it does not matter and you will get
whatever the object decides is more efficient.
A new reference is returned that must be DECREF'd when finished.
*/
PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base);
PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(PyBuffer *info);
/* create new if bufptr is NULL
will be a new bytesobject in base */
#ifdef __cplusplus
}
#endif
#endif /* !Py_MEMORYOBJECT_H */
......@@ -140,11 +140,59 @@ typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
/* ssize_t-based buffer interface */
typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
/* buffer interface */
typedef struct bufferinfo {
void *buf;
Py_ssize_t len;
Py_ssize_t itemsize;
int readonly;
int ndim;
char *format;
Py_ssize_t *shape;
Py_ssize_t *strides;
Py_ssize_t *suboffsets;
void *internal;
} PyBuffer;
typedef int (*getbufferproc)(PyObject *, PyBuffer *, int);
typedef void (*releasebufferproc)(PyObject *, PyBuffer *);
/* Flags for getting buffers */
#define PyBUF_SIMPLE 0
#define PyBUF_CHARACTER 1
#define PyBUF_WRITEABLE 0x0002
#define PyBUF_LOCKDATA 0x0004
#define PyBUF_FORMAT 0x0008
#define PyBUF_ND 0x0010
#define PyBUF_STRIDES (0x0020 | PyBUF_ND)
#define PyBUF_C_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
#define PyBUF_F_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
#define PyBUF_ANY_CONTIGUOUS (0x0100 | PyBUF_STRIDES)
#define PyBUF_INDIRECT (0x0200 | PyBUF_STRIDES)
#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITEABLE)
#define PyBUF_CONTIG_RO (PyBUF_ND)
#define PyBUF_CONTIG_LCK (PyBUF_ND | PyBUF_LOCKDATA)
#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITEABLE)
#define PyBUF_STRIDED_RO (PyBUF_STRIDES)
#define PyBUF_STRIDED_LCK (PyBUF_STRIDES | PyBUF_LOCKDATA)
#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITEABLE | PyBUF_FORMAT)
#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT)
#define PyBUF_RECORDS_LCK (PyBUF_STRIDES | PyBUF_LOCKDATA | PyBUF_FORMAT)
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITEABLE | PyBUF_FORMAT)
#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT)
#define PyBUF_FULL_LCK (PyBUF_INDIRECT | PyBUF_LOCKDATA | PyBUF_FORMAT)
#define PyBUF_READ 0x100
#define PyBUF_WRITE 0x200
#define PyBUF_SHADOW 0x400
/* End buffer interface */
typedef int (*objobjproc)(PyObject *, PyObject *);
typedef int (*visitproc)(PyObject *, void *);
......@@ -218,14 +266,13 @@ typedef struct {
objobjargproc mp_ass_subscript;
} PyMappingMethods;
typedef struct {
readbufferproc bf_getreadbuffer;
writebufferproc bf_getwritebuffer;
segcountproc bf_getsegcount;
charbufferproc bf_getcharbuffer;
getbufferproc bf_getbuffer;
releasebufferproc bf_releasebuffer;
inquiry bf_multisegment;
} PyBufferProcs;
typedef void (*freefunc)(void *);
typedef void (*destructor)(PyObject *);
typedef int (*printfunc)(PyObject *, FILE *, int);
......
......@@ -138,6 +138,7 @@ PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError;
PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError;
PyAPI_DATA(PyObject *) PyExc_ValueError;
PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError;
PyAPI_DATA(PyObject *) PyExc_BufferError;
#ifdef MS_WINDOWS
PyAPI_DATA(PyObject *) PyExc_WindowsError;
#endif
......
......@@ -300,6 +300,7 @@ OBJECT_OBJS= \
Objects/listobject.o \
Objects/longobject.o \
Objects/dictobject.o \
Objects/memoryobject.o \
Objects/methodobject.o \
Objects/moduleobject.o \
Objects/object.o \
......@@ -533,6 +534,7 @@ PYTHON_HEADERS= \
Include/iterobject.h \
Include/listobject.h \
Include/longobject.h \
Include/memoryobject.h \
Include/methodobject.h \
Include/modsupport.h \
Include/moduleobject.h \
......
......@@ -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)
{
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_getwritebuf(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_getsegcount(arrayobject *self, Py_ssize_t *lenp)
static void
array_buffer_relbuf(arrayobject *self, PyBuffer *view)
{
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)
{
CHECK_VALID(-1);
if (index != 0) {
PyErr_SetString(PyExc_SystemError,
"Accessing non-existent mmap segment");
return -1;
}
*ptr = self->data;
return self->size;
}
static Py_ssize_t
mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
{
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)
static int
mmap_buffer_getbuf(mmap_object *self, PyBuffer *view, int flags)
{
CHECK_VALID(-1);
if (lenp)
*lenp = self->size;
return 1;
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_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
static void
mmap_buffer_releasebuf(mmap_object *self, PyBuffer *view)
{
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);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1539,6 +1539,11 @@ SimpleExtendsException(PyExc_Exception, ReferenceError,
*/
SimpleExtendsException(PyExc_Exception, MemoryError, "Out of memory.");
/*
* BufferError extends Exception
*/
SimpleExtendsException(PyExc_Exception, BufferError, "Buffer error.");
/* Warning category docstrings */
......
This diff is collapsed.
......@@ -1171,44 +1171,10 @@ string_subscript(PyStringObject* self, PyObject* item)
}
}
static Py_ssize_t
string_buffer_getreadbuf(PyStringObject *self, Py_ssize_t index, const void **ptr)
{
if ( index != 0 ) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent string segment");
return -1;
}
*ptr = (void *)self->ob_sval;
return Py_Size(self);
}
static Py_ssize_t
string_buffer_getwritebuf(PyStringObject *self, Py_ssize_t index, const void **ptr)
{
PyErr_SetString(PyExc_TypeError,
"Cannot use string as modifiable buffer");
return -1;
}
static Py_ssize_t
string_buffer_getsegcount(PyStringObject *self, Py_ssize_t *lenp)
{
if ( lenp )
*lenp = Py_Size(self);
return 1;
}
static Py_ssize_t
string_buffer_getcharbuf(PyStringObject *self, Py_ssize_t index, const char **ptr)
static int
string_buffer_getbuffer(PyStringObject *self, PyBuffer *view, int flags)
{
if ( index != 0 ) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent string segment");
return -1;
}
*ptr = self->ob_sval;
return Py_Size(self);
return PyBuffer_FillInfo(view, (void *)self->ob_sval, Py_Size(self), 0, flags);
}
static PySequenceMethods string_as_sequence = {
......@@ -1229,14 +1195,11 @@ static PyMappingMethods string_as_mapping = {
};
static PyBufferProcs string_as_buffer = {
(readbufferproc)string_buffer_getreadbuf,
(writebufferproc)string_buffer_getwritebuf,
(segcountproc)string_buffer_getsegcount,
(charbufferproc)string_buffer_getcharbuf,
(getbufferproc)string_buffer_getbuffer,
NULL,
};
#define LEFTSTRIP 0
#define RIGHTSTRIP 1
#define BOTHSTRIP 2
......
......@@ -3251,10 +3251,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
basebase = base->tp_base;
if (basebase->tp_as_buffer == NULL)
basebase = NULL;
COPYBUF(bf_getreadbuffer);
COPYBUF(bf_getwritebuffer);
COPYBUF(bf_getsegcount);
COPYBUF(bf_getcharbuffer);
COPYBUF(bf_getbuffer);
COPYBUF(bf_releasebuffer);
}
basebase = base->tp_base;
......
......@@ -8108,57 +8108,26 @@ static PyMappingMethods unicode_as_mapping = {
(objobjargproc)0, /* mp_ass_subscript */
};
static Py_ssize_t
unicode_buffer_getreadbuf(PyUnicodeObject *self,
Py_ssize_t index,
const void **ptr)
{
if (index != 0) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent unicode segment");
return -1;
}
*ptr = (void *) self->str;
return PyUnicode_GET_DATA_SIZE(self);
}
static Py_ssize_t
unicode_buffer_getwritebuf(PyUnicodeObject *self, Py_ssize_t index,
const void **ptr)
{
PyErr_SetString(PyExc_TypeError,
"cannot use unicode as modifiable buffer");
return -1;
}
static int
unicode_buffer_getsegcount(PyUnicodeObject *self,
Py_ssize_t *lenp)
unicode_buffer_getbuffer(PyUnicodeObject *self, PyBuffer *view, int flags)
{
if (lenp)
*lenp = PyUnicode_GET_DATA_SIZE(self);
return 1;
}
static Py_ssize_t
unicode_buffer_getcharbuf(PyUnicodeObject *self,
Py_ssize_t index,
const void **ptr)
{
PyObject *str;
if (index != 0) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent unicode segment");
return -1;
if (flags & PyBUF_CHARACTER) {
PyObject *str;
str = _PyUnicode_AsDefaultEncodedString((PyObject *)self, NULL);
if (str == NULL) return -1;
return PyBuffer_FillInfo(view, (void *)PyString_AS_STRING(str),
PyString_GET_SIZE(str), 1, flags);
}
else {
return PyBuffer_FillInfo(view, (void *)self->str,
PyUnicode_GET_DATA_SIZE(self), 1, flags);
}
str = _PyUnicode_AsDefaultEncodedString((PyObject *)self, NULL);
if (str == NULL)
return -1;
*ptr = (void *) PyString_AS_STRING(str);
return PyString_GET_SIZE(str);
}
/* Helpers for PyUnicode_Format() */
static PyObject *
......@@ -8853,10 +8822,8 @@ PyObject *PyUnicode_Format(PyObject *format,
}
static PyBufferProcs unicode_as_buffer = {
(readbufferproc) unicode_buffer_getreadbuf,
(writebufferproc) unicode_buffer_getwritebuf,
(segcountproc) unicode_buffer_getsegcount,
(charbufferproc) unicode_buffer_getcharbuf,
(getbufferproc) unicode_buffer_getbuffer,
NULL,
};
static PyObject *
......
......@@ -1704,6 +1704,7 @@ _PyBuiltin_Init(void)
SETBUILTIN("basestring", &PyBaseString_Type);
SETBUILTIN("bool", &PyBool_Type);
SETBUILTIN("buffer", &PyBuffer_Type);
SETBUILTIN("memoryview", &PyMemoryView_Type);
SETBUILTIN("bytes", &PyBytes_Type);
SETBUILTIN("classmethod", &PyClassMethod_Type);
#ifndef WITHOUT_COMPLEX
......
......@@ -1179,21 +1179,31 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
void **p = va_arg(*p_va, void **);
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
int count;
int temp=-1;
PyBuffer view;
if (pb == NULL ||
pb->bf_getwritebuffer == NULL ||
pb->bf_getsegcount == NULL)
return converterr("read-write buffer", arg, msgbuf, bufsize);
if ((*pb->bf_getsegcount)(arg, NULL) != 1)
pb->bf_getbuffer == NULL ||
((temp = (*pb->bf_getbuffer)(arg, &view,
PyBUF_SIMPLE)) != 0) ||
view.readonly == 1) {
if (temp==0 && pb->bf_releasebuffer != NULL) {
(*pb->bf_releasebuffer)(arg, &view);
}
return converterr("single-segment read-write buffer",
arg, msgbuf, bufsize);
if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0)
}
if ((count = view.len) < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
*p = view.buf;
if (*format == '#') {
FETCH_SIZE;
STORE_SIZE(count);
format++;
}
if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(arg, &view);
break;
}
......@@ -1201,23 +1211,27 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
char **p = va_arg(*p_va, char **);
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
int count;
PyBuffer view;
if (*format++ != '#')
return converterr(
"invalid use of 't' format character",
arg, msgbuf, bufsize);
if (pb == NULL || pb->bf_getcharbuffer == NULL ||
pb->bf_getsegcount == NULL)
if (pb == NULL || pb->bf_getbuffer == NULL)
return converterr(
"string or read-only character buffer",
arg, msgbuf, bufsize);
if (pb->bf_getsegcount(arg, NULL) != 1)
return converterr(
"string or single-segment read-only buffer",
arg, msgbuf, bufsize);
if ((*pb->bf_getbuffer)(arg, &view, PyBUF_CHARACTER) != 0)
return converterr("string or single-segment read-only buffer",
arg, msgbuf, bufsize);
count = pb->bf_getcharbuffer(arg, 0, p);
count = view.len;
*p = view.buf;
/* XXX : shouldn't really release buffer, but it should be O.K.
*/
if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(arg, &view);
if (count < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
{
......@@ -1241,19 +1255,24 @@ convertbuffer(PyObject *arg, void **p, char **errmsg)
{
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
Py_ssize_t count;
PyBuffer view;
*errmsg = NULL;
*p = NULL;
if (pb == NULL ||
pb->bf_getreadbuffer == NULL ||
pb->bf_getsegcount == NULL) {
pb->bf_getbuffer == NULL) {
*errmsg = "string or read-only buffer";
return -1;
}
if ((*pb->bf_getsegcount)(arg, NULL) != 1) {
if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0) {
*errmsg = "string or single-segment read-only buffer";
return -1;
}
if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) {
*errmsg = "(unspecified)";
}
count = view.len;
*p = view.buf;
if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(arg, &view);
return count;
}
......
......@@ -358,12 +358,18 @@ w_object(PyObject *v, WFILE *p)
w_long(co->co_firstlineno, p);
w_object(co->co_lnotab, p);
}
else if (PyObject_CheckReadBuffer(v)) {
else if (PyObject_CheckBuffer(v)) {
/* Write unknown buffer-style objects as a string */
char *s;
PyBufferProcs *pb = v->ob_type->tp_as_buffer;
PyBuffer view;
if ((*pb->bf_getbuffer)(v, &view, PyBUF_SIMPLE) != 0) {
w_byte(TYPE_UNKNOWN, p);
p->error = 1;
}
w_byte(TYPE_STRING, p);
n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s);
n = view.len;
s = view.buf;
if (n > INT_MAX) {
p->depth--;
p->error = 1;
......@@ -371,6 +377,8 @@ w_object(PyObject *v, WFILE *p)
}
w_long((long)n, p);
w_string(s, (int)n, p);
if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(v, &view);
}
else {
w_byte(TYPE_UNKNOWN, p);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment