mirror of
https://github.com/python/cpython.git
synced 2025-09-24 17:33:29 +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
|
@ -77,6 +77,7 @@
|
||||||
#include "rangeobject.h"
|
#include "rangeobject.h"
|
||||||
#include "stringobject.h"
|
#include "stringobject.h"
|
||||||
#include "bufferobject.h"
|
#include "bufferobject.h"
|
||||||
|
#include "memoryobject.h"
|
||||||
#include "tupleobject.h"
|
#include "tupleobject.h"
|
||||||
#include "listobject.h"
|
#include "listobject.h"
|
||||||
#include "dictobject.h"
|
#include "dictobject.h"
|
||||||
|
|
|
@ -475,6 +475,12 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
This is the equivalent of the Python statement: del o[key].
|
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,
|
PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj,
|
||||||
const char **buffer,
|
const char **buffer,
|
||||||
Py_ssize_t *buffer_len);
|
Py_ssize_t *buffer_len);
|
||||||
|
@ -527,6 +533,110 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
an exception set.
|
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 */
|
/* Iterators */
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);
|
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern "C" {
|
||||||
/* Object layout */
|
/* Object layout */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_VAR_HEAD
|
PyObject_VAR_HEAD
|
||||||
|
int ob_exports; /* how many buffer exports */
|
||||||
Py_ssize_t ob_alloc; /* How many bytes allocated */
|
Py_ssize_t ob_alloc; /* How many bytes allocated */
|
||||||
char *ob_bytes;
|
char *ob_bytes;
|
||||||
} PyBytesObject;
|
} PyBytesObject;
|
||||||
|
|
67
Include/memoryobject.h
Normal file
67
Include/memoryobject.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
/* 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(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
|
||||||
typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
|
typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
|
||||||
|
|
||||||
/* ssize_t-based buffer interface */
|
|
||||||
typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
|
/* buffer interface */
|
||||||
typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
|
typedef struct bufferinfo {
|
||||||
typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
|
void *buf;
|
||||||
typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
|
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 (*objobjproc)(PyObject *, PyObject *);
|
||||||
typedef int (*visitproc)(PyObject *, void *);
|
typedef int (*visitproc)(PyObject *, void *);
|
||||||
|
@ -218,13 +266,12 @@ typedef struct {
|
||||||
objobjargproc mp_ass_subscript;
|
objobjargproc mp_ass_subscript;
|
||||||
} PyMappingMethods;
|
} PyMappingMethods;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
readbufferproc bf_getreadbuffer;
|
|
||||||
writebufferproc bf_getwritebuffer;
|
|
||||||
segcountproc bf_getsegcount;
|
|
||||||
charbufferproc bf_getcharbuffer;
|
|
||||||
} PyBufferProcs;
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
getbufferproc bf_getbuffer;
|
||||||
|
releasebufferproc bf_releasebuffer;
|
||||||
|
inquiry bf_multisegment;
|
||||||
|
} PyBufferProcs;
|
||||||
|
|
||||||
typedef void (*freefunc)(void *);
|
typedef void (*freefunc)(void *);
|
||||||
typedef void (*destructor)(PyObject *);
|
typedef void (*destructor)(PyObject *);
|
||||||
|
|
|
@ -138,6 +138,7 @@ PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError;
|
||||||
PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError;
|
PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError;
|
||||||
PyAPI_DATA(PyObject *) PyExc_ValueError;
|
PyAPI_DATA(PyObject *) PyExc_ValueError;
|
||||||
PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError;
|
PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError;
|
||||||
|
PyAPI_DATA(PyObject *) PyExc_BufferError;
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
PyAPI_DATA(PyObject *) PyExc_WindowsError;
|
PyAPI_DATA(PyObject *) PyExc_WindowsError;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -300,6 +300,7 @@ OBJECT_OBJS= \
|
||||||
Objects/listobject.o \
|
Objects/listobject.o \
|
||||||
Objects/longobject.o \
|
Objects/longobject.o \
|
||||||
Objects/dictobject.o \
|
Objects/dictobject.o \
|
||||||
|
Objects/memoryobject.o \
|
||||||
Objects/methodobject.o \
|
Objects/methodobject.o \
|
||||||
Objects/moduleobject.o \
|
Objects/moduleobject.o \
|
||||||
Objects/object.o \
|
Objects/object.o \
|
||||||
|
@ -533,6 +534,7 @@ PYTHON_HEADERS= \
|
||||||
Include/iterobject.h \
|
Include/iterobject.h \
|
||||||
Include/listobject.h \
|
Include/listobject.h \
|
||||||
Include/longobject.h \
|
Include/longobject.h \
|
||||||
|
Include/memoryobject.h \
|
||||||
Include/methodobject.h \
|
Include/methodobject.h \
|
||||||
Include/modsupport.h \
|
Include/modsupport.h \
|
||||||
Include/moduleobject.h \
|
Include/moduleobject.h \
|
||||||
|
|
|
@ -739,22 +739,33 @@ CharArray_set_raw(CDataObject *self, PyObject *value)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
|
int rel = 0;
|
||||||
|
PyBuffer view;
|
||||||
|
|
||||||
if (PyBuffer_Check(value)) {
|
if (PyBuffer_Check(value)) {
|
||||||
size = Py_Type(value)->tp_as_buffer->bf_getreadbuffer(value, 0, (void *)&ptr);
|
if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) < 0)
|
||||||
if (size < 0)
|
return -1;
|
||||||
return -1;
|
size = view.len;
|
||||||
|
ptr = view.buf;
|
||||||
|
rel = 1;
|
||||||
} else if (-1 == PyString_AsStringAndSize(value, &ptr, &size)) {
|
} else if (-1 == PyString_AsStringAndSize(value, &ptr, &size)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (size > self->b_size) {
|
if (size > self->b_size) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"string too long");
|
"string too long");
|
||||||
return -1;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(self->b_ptr, ptr, size);
|
memcpy(self->b_ptr, ptr, size);
|
||||||
|
|
||||||
|
if (rel)
|
||||||
|
PyObject_ReleaseBuffer(value, &view);
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
if (rel)
|
||||||
|
PyObject_ReleaseBuffer(value, &view);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -2072,29 +2083,15 @@ static PyMemberDef CData_members[] = {
|
||||||
{ NULL },
|
{ 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;
|
CDataObject *self = (CDataObject *)_self;
|
||||||
if (seg != 0) {
|
return PyBuffer_FillInfo(view, self->b_ptr, self->b_size, 0, flags);
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyBufferProcs CData_as_buffer = {
|
static PyBufferProcs CData_as_buffer = {
|
||||||
CData_GetBuffer,
|
CData_GetBuffer,
|
||||||
CData_GetBuffer,
|
NULL,
|
||||||
CData_GetSegcount,
|
|
||||||
NULL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1672,44 +1672,38 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
|
||||||
Py_ssize_t size, bytes;
|
Py_ssize_t size, bytes;
|
||||||
int charsize;
|
int charsize;
|
||||||
void* ptr;
|
void* ptr;
|
||||||
|
PyBuffer view;
|
||||||
#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
|
|
||||||
|
|
||||||
/* get pointer to string buffer */
|
/* get pointer to string buffer */
|
||||||
|
view.len = -1;
|
||||||
buffer = Py_Type(string)->tp_as_buffer;
|
buffer = Py_Type(string)->tp_as_buffer;
|
||||||
if (!buffer || !buffer->bf_getreadbuffer || !buffer->bf_getsegcount ||
|
if (!buffer || !buffer->bf_getbuffer ||
|
||||||
buffer->bf_getsegcount(string, NULL) != 1) {
|
(*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) < 0) {
|
||||||
PyErr_SetString(PyExc_TypeError, "expected string or buffer");
|
PyErr_SetString(PyExc_TypeError, "expected string or buffer");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine buffer size */
|
/* 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) {
|
if (bytes < 0) {
|
||||||
PyErr_SetString(PyExc_TypeError, "buffer has negative size");
|
PyErr_SetString(PyExc_TypeError, "buffer has negative size");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine character size */
|
/* determine character size */
|
||||||
#if PY_VERSION_HEX >= 0x01060000
|
|
||||||
size = PyObject_Size(string);
|
size = PyObject_Size(string);
|
||||||
#else
|
|
||||||
size = PyObject_Length(string);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (PyString_Check(string) || bytes == size)
|
if (PyString_Check(string) || bytes == size)
|
||||||
charsize = 1;
|
charsize = 1;
|
||||||
#if defined(HAVE_UNICODE)
|
#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);
|
charsize = sizeof(Py_UNICODE);
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
|
@ -1717,13 +1711,13 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_UNICODE)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*p_length = size;
|
*p_length = size;
|
||||||
*p_charsize = charsize;
|
*p_charsize = charsize;
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"Buffer is NULL");
|
||||||
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct arraydescr {
|
||||||
int itemsize;
|
int itemsize;
|
||||||
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
|
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
|
||||||
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
|
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
|
||||||
|
const char *formats;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct arrayobject {
|
typedef struct arrayobject {
|
||||||
|
@ -34,10 +35,19 @@ typedef struct arrayobject {
|
||||||
Py_ssize_t allocated;
|
Py_ssize_t allocated;
|
||||||
struct arraydescr *ob_descr;
|
struct arraydescr *ob_descr;
|
||||||
PyObject *weakreflist; /* List of weak references */
|
PyObject *weakreflist; /* List of weak references */
|
||||||
|
int ob_exports; /* Number of exported buffers */
|
||||||
} arrayobject;
|
} arrayobject;
|
||||||
|
|
||||||
static PyTypeObject Arraytype;
|
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_Check(op) PyObject_TypeCheck(op, &Arraytype)
|
||||||
#define array_CheckExact(op) (Py_Type(op) == &Arraytype)
|
#define array_CheckExact(op) (Py_Type(op) == &Arraytype)
|
||||||
|
|
||||||
|
@ -59,6 +69,12 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
|
||||||
return 0;
|
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
|
/* This over-allocates proportional to the array size, making room
|
||||||
* for additional growth. The over-allocation is mild, but is
|
* for additional growth. The over-allocation is mild, but is
|
||||||
* enough to give linear-time amortized behavior over a long
|
* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Description of types */
|
/* Description of types */
|
||||||
static struct arraydescr descriptors[] = {
|
static struct arraydescr descriptors[] = {
|
||||||
{'b', sizeof(char), b_getitem, b_setitem},
|
{'b', sizeof(char), b_getitem, b_setitem},
|
||||||
{'B', sizeof(char), BB_getitem, BB_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), h_getitem, h_setitem},
|
||||||
{'H', sizeof(short), HH_getitem, HH_setitem},
|
{'H', sizeof(short), HH_getitem, HH_setitem},
|
||||||
{'i', sizeof(int), i_getitem, i_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->ob_descr = descr;
|
||||||
op->allocated = size;
|
op->allocated = size;
|
||||||
op->weakreflist = NULL;
|
op->weakreflist = NULL;
|
||||||
|
op->ob_exports = 0;
|
||||||
return (PyObject *) op;
|
return (PyObject *) op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1403,10 +1421,10 @@ array_fromunicode(arrayobject *self, PyObject *args)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n))
|
if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (self->ob_descr->typecode != 'u') {
|
if (self->ob_descr->typecode != PyArr_UNI) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"fromunicode() may only be called on "
|
"fromunicode() may only be called on "
|
||||||
"type 'u' arrays");
|
"unicode type arrays");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
|
@ -1431,7 +1449,7 @@ PyDoc_STRVAR(fromunicode_doc,
|
||||||
"fromunicode(ustr)\n\
|
"fromunicode(ustr)\n\
|
||||||
\n\
|
\n\
|
||||||
Extends this array with data from the unicode string ustr.\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\
|
is raised. Use array.fromstring(ustr.decode(...)) to\n\
|
||||||
append Unicode data to an array of some other type.");
|
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 *
|
static PyObject *
|
||||||
array_tounicode(arrayobject *self, PyObject *unused)
|
array_tounicode(arrayobject *self, PyObject *unused)
|
||||||
{
|
{
|
||||||
if (self->ob_descr->typecode != 'u') {
|
if (self->ob_descr->typecode != PyArr_UNI) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
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 NULL;
|
||||||
}
|
}
|
||||||
return PyUnicode_FromUnicode((Py_UNICODE *) self->ob_item, Py_Size(self));
|
return PyUnicode_FromUnicode((Py_UNICODE *) self->ob_item, Py_Size(self));
|
||||||
|
@ -1451,7 +1469,7 @@ PyDoc_STRVAR(tounicode_doc,
|
||||||
"tounicode() -> unicode\n\
|
"tounicode() -> unicode\n\
|
||||||
\n\
|
\n\
|
||||||
Convert the array to a unicode string. The array must be\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\
|
array.tostring().decode() to obtain a unicode string from\n\
|
||||||
an array of some other type.");
|
an array of some other type.");
|
||||||
|
|
||||||
|
@ -1542,7 +1560,7 @@ array_repr(arrayobject *a)
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return PyUnicode_FromFormat("array('%c')", typecode);
|
return PyUnicode_FromFormat("array('%c')", typecode);
|
||||||
}
|
}
|
||||||
if (typecode == 'u')
|
if (typecode == PyArr_UNI)
|
||||||
v = array_tounicode(a, NULL);
|
v = array_tounicode(a, NULL);
|
||||||
else
|
else
|
||||||
v = array_tolist(a, NULL);
|
v = array_tolist(a, NULL);
|
||||||
|
@ -1720,40 +1738,56 @@ static PyMappingMethods array_as_mapping = {
|
||||||
|
|
||||||
static const void *emptybuf = "";
|
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 ) {
|
if ((flags & PyBUF_CHARACTER)) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Accessing non-existent array segment");
|
"Cannot be a character buffer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*ptr = (void *)self->ob_item;
|
if ((flags & PyBUF_LOCKDATA)) {
|
||||||
if (*ptr == NULL)
|
PyErr_SetString(PyExc_BufferError,
|
||||||
*ptr = emptybuf;
|
"Cannot lock data");
|
||||||
return Py_Size(self)*self->ob_descr->itemsize;
|
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
|
static void
|
||||||
array_buffer_getwritebuf(arrayobject *self, Py_ssize_t index, const void **ptr)
|
array_buffer_relbuf(arrayobject *self, PyBuffer *view)
|
||||||
{
|
{
|
||||||
if ( index != 0 ) {
|
free(view->internal);
|
||||||
PyErr_SetString(PyExc_SystemError,
|
self->ob_exports--;
|
||||||
"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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods array_as_sequence = {
|
static PySequenceMethods array_as_sequence = {
|
||||||
|
@ -1770,10 +1804,8 @@ static PySequenceMethods array_as_sequence = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyBufferProcs array_as_buffer = {
|
static PyBufferProcs array_as_buffer = {
|
||||||
(readbufferproc)array_buffer_getreadbuf,
|
(getbufferproc)array_buffer_getbuf,
|
||||||
(writebufferproc)array_buffer_getwritebuf,
|
(releasebufferproc)array_buffer_relbuf
|
||||||
(segcountproc)array_buffer_getsegcount,
|
|
||||||
NULL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1792,7 +1824,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
if (!(initial == NULL || PyList_Check(initial)
|
if (!(initial == NULL || PyList_Check(initial)
|
||||||
|| PyBytes_Check(initial)
|
|| PyBytes_Check(initial)
|
||||||
|| PyString_Check(initial) || PyTuple_Check(initial)
|
|| PyString_Check(initial) || PyTuple_Check(initial)
|
||||||
|| (c == 'u' && PyUnicode_Check(initial)))) {
|
|| (c == PyArr_UNI && PyUnicode_Check(initial)))) {
|
||||||
it = PyObject_GetIter(initial);
|
it = PyObject_GetIter(initial);
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1900,6 +1932,7 @@ is a single character. The following type codes are defined:\n\
|
||||||
'H' unsigned integer 2 \n\
|
'H' unsigned integer 2 \n\
|
||||||
'i' signed integer 2 \n\
|
'i' signed integer 2 \n\
|
||||||
'I' unsigned integer 2 \n\
|
'I' unsigned integer 2 \n\
|
||||||
|
'w' unicode character 4 \n\
|
||||||
'l' signed integer 4 \n\
|
'l' signed integer 4 \n\
|
||||||
'L' unsigned integer 4 \n\
|
'L' unsigned integer 4 \n\
|
||||||
'f' floating point 4 \n\
|
'f' floating point 4 \n\
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct {
|
||||||
char * data;
|
char * data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
int exports;
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
HANDLE map_handle;
|
HANDLE map_handle;
|
||||||
|
@ -119,6 +120,11 @@ mmap_object_dealloc(mmap_object *m_obj)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
mmap_close_method(mmap_object *self, PyObject *unused)
|
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
|
#ifdef MS_WINDOWS
|
||||||
/* For each resource we maintain, we need to check
|
/* For each resource we maintain, we need to check
|
||||||
the value is valid, and if so, free the resource
|
the value is valid, and if so, free the resource
|
||||||
|
@ -277,8 +283,13 @@ is_writeable(mmap_object *self)
|
||||||
static int
|
static int
|
||||||
is_resizeable(mmap_object *self)
|
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))
|
if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
|
||||||
return 1;
|
return 1;
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"mmap can't resize a readonly or copy-on-write memory map.");
|
"mmap can't resize a readonly or copy-on-write memory map.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -589,53 +600,21 @@ static struct PyMethodDef mmap_object_methods[] = {
|
||||||
|
|
||||||
/* Functions for treating an mmap'ed file as a buffer */
|
/* Functions for treating an mmap'ed file as a buffer */
|
||||||
|
|
||||||
static Py_ssize_t
|
static int
|
||||||
mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
|
mmap_buffer_getbuf(mmap_object *self, PyBuffer *view, int flags)
|
||||||
{
|
{
|
||||||
CHECK_VALID(-1);
|
CHECK_VALID(-1);
|
||||||
if (index != 0) {
|
if (PyBuffer_FillInfo(view, self->data, self->size,
|
||||||
PyErr_SetString(PyExc_SystemError,
|
(self->access == ACCESS_READ), flags) < 0)
|
||||||
"Accessing non-existent mmap segment");
|
return -1;
|
||||||
return -1;
|
self->exports++;
|
||||||
}
|
return 0;
|
||||||
*ptr = self->data;
|
|
||||||
return self->size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
static void
|
||||||
mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
|
mmap_buffer_releasebuf(mmap_object *self, PyBuffer *view)
|
||||||
{
|
{
|
||||||
CHECK_VALID(-1);
|
self->exports--;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -775,10 +754,8 @@ static PySequenceMethods mmap_as_sequence = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyBufferProcs mmap_as_buffer = {
|
static PyBufferProcs mmap_as_buffer = {
|
||||||
(readbufferproc)mmap_buffer_getreadbuf,
|
(getbufferproc)mmap_buffer_getbuf,
|
||||||
(writebufferproc)mmap_buffer_getwritebuf,
|
(releasebufferproc)mmap_buffer_releasebuf,
|
||||||
(segcountproc)mmap_buffer_getsegcount,
|
|
||||||
(charbufferproc)mmap_buffer_getcharbuffer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject mmap_object_type = {
|
static PyTypeObject mmap_object_type = {
|
||||||
|
@ -900,6 +877,7 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||||
m_obj->data = NULL;
|
m_obj->data = NULL;
|
||||||
m_obj->size = (size_t) map_size;
|
m_obj->size = (size_t) map_size;
|
||||||
m_obj->pos = (size_t) 0;
|
m_obj->pos = (size_t) 0;
|
||||||
|
m_obj->exports = 0;
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
m_obj->fd = -1;
|
m_obj->fd = -1;
|
||||||
/* Assume the caller wants to map anonymous memory.
|
/* 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 */
|
/* set the initial position */
|
||||||
m_obj->pos = (size_t) 0;
|
m_obj->pos = (size_t) 0;
|
||||||
|
|
||||||
|
m_obj->exports = 0;
|
||||||
/* set the tag name */
|
/* set the tag name */
|
||||||
if (tagname != NULL && *tagname != '\0') {
|
if (tagname != NULL && *tagname != '\0') {
|
||||||
m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
|
m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
|
||||||
|
|
|
@ -215,50 +215,50 @@ PyObject_DelItemString(PyObject *o, char *key)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We release the buffer right after use of this function which could
|
||||||
|
cause issues later on. Don't use these functions in new code.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
PyObject_AsCharBuffer(PyObject *obj,
|
PyObject_AsCharBuffer(PyObject *obj,
|
||||||
const char **buffer,
|
const char **buffer,
|
||||||
Py_ssize_t *buffer_len)
|
Py_ssize_t *buffer_len)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb;
|
PyBufferProcs *pb;
|
||||||
char *pp;
|
PyBuffer view;
|
||||||
Py_ssize_t len;
|
|
||||||
|
|
||||||
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
||||||
null_error();
|
null_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pb = obj->ob_type->tp_as_buffer;
|
pb = obj->ob_type->tp_as_buffer;
|
||||||
if (pb == NULL ||
|
if (pb == NULL || pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getcharbuffer == NULL ||
|
|
||||||
pb->bf_getsegcount == NULL) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"expected a character buffer object");
|
"expected an object with the buffer interface");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((*pb->bf_getsegcount)(obj,NULL) != 1) {
|
if ((*pb->bf_getbuffer)(obj, &view, PyBUF_CHARACTER)) return -1;
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"expected a single-segment buffer object");
|
*buffer = view.buf;
|
||||||
return -1;
|
*buffer_len = view.len;
|
||||||
}
|
if (pb->bf_releasebuffer != NULL)
|
||||||
len = (*pb->bf_getcharbuffer)(obj, 0, &pp);
|
(*pb->bf_releasebuffer)(obj, &view);
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
*buffer = pp;
|
|
||||||
*buffer_len = len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PyObject_CheckReadBuffer(PyObject *obj)
|
PyObject_CheckReadBuffer(PyObject *obj)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
|
||||||
|
|
||||||
if (pb == NULL ||
|
if (pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL)
|
||||||
pb->bf_getsegcount == NULL ||
|
return 0;
|
||||||
(*pb->bf_getsegcount)(obj, NULL) != 1)
|
if ((*pb->bf_getbuffer)(obj, NULL, PyBUF_SIMPLE) == -1) {
|
||||||
return 0;
|
PyErr_Clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (*pb->bf_releasebuffer != NULL)
|
||||||
|
(*pb->bf_releasebuffer)(obj, NULL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,8 +267,7 @@ int PyObject_AsReadBuffer(PyObject *obj,
|
||||||
Py_ssize_t *buffer_len)
|
Py_ssize_t *buffer_len)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb;
|
PyBufferProcs *pb;
|
||||||
void *pp;
|
PyBuffer view;
|
||||||
Py_ssize_t len;
|
|
||||||
|
|
||||||
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
||||||
null_error();
|
null_error();
|
||||||
|
@ -276,22 +275,18 @@ int PyObject_AsReadBuffer(PyObject *obj,
|
||||||
}
|
}
|
||||||
pb = obj->ob_type->tp_as_buffer;
|
pb = obj->ob_type->tp_as_buffer;
|
||||||
if (pb == NULL ||
|
if (pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getsegcount == NULL) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"expected a readable buffer object");
|
"expected an object with a buffer interface");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1;
|
||||||
"expected a single-segment buffer object");
|
|
||||||
return -1;
|
*buffer = view.buf;
|
||||||
}
|
*buffer_len = view.len;
|
||||||
len = (*pb->bf_getreadbuffer)(obj, 0, &pp);
|
if (pb->bf_releasebuffer != NULL)
|
||||||
if (len < 0)
|
(*pb->bf_releasebuffer)(obj, &view);
|
||||||
return -1;
|
|
||||||
*buffer = pp;
|
|
||||||
*buffer_len = len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,8 +295,7 @@ int PyObject_AsWriteBuffer(PyObject *obj,
|
||||||
Py_ssize_t *buffer_len)
|
Py_ssize_t *buffer_len)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb;
|
PyBufferProcs *pb;
|
||||||
void*pp;
|
PyBuffer view;
|
||||||
Py_ssize_t len;
|
|
||||||
|
|
||||||
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
|
||||||
null_error();
|
null_error();
|
||||||
|
@ -309,25 +303,384 @@ int PyObject_AsWriteBuffer(PyObject *obj,
|
||||||
}
|
}
|
||||||
pb = obj->ob_type->tp_as_buffer;
|
pb = obj->ob_type->tp_as_buffer;
|
||||||
if (pb == NULL ||
|
if (pb == NULL ||
|
||||||
pb->bf_getwritebuffer == NULL ||
|
pb->bf_getbuffer == NULL ||
|
||||||
pb->bf_getsegcount == NULL) {
|
((*pb->bf_getbuffer)(obj, &view, PyBUF_WRITEABLE) != 0)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"expected a writeable buffer object");
|
"expected an object with a writeable buffer interface");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
*buffer = view.buf;
|
||||||
"expected a single-segment buffer object");
|
*buffer_len = view.len;
|
||||||
return -1;
|
if (pb->bf_releasebuffer != NULL)
|
||||||
}
|
(*pb->bf_releasebuffer)(obj, &view);
|
||||||
len = (*pb->bf_getwritebuffer)(obj,0,&pp);
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
*buffer = pp;
|
|
||||||
*buffer_len = len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Buffer C-API for Python 3.0 */
|
||||||
|
|
||||||
|
int
|
||||||
|
PyObject_GetBuffer(PyObject *obj, PyBuffer *view, int flags)
|
||||||
|
{
|
||||||
|
if (!PyObject_CheckBuffer(obj)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"object does not have the buffer interface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view)
|
||||||
|
{
|
||||||
|
if (obj->ob_type->tp_as_buffer != NULL &&
|
||||||
|
obj->ob_type->tp_as_buffer->bf_releasebuffer != NULL) {
|
||||||
|
(*(obj->ob_type->tp_as_buffer->bf_releasebuffer))(obj, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_IsFortranContiguous(PyBuffer *view)
|
||||||
|
{
|
||||||
|
Py_ssize_t sd, dim;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (view->ndim == 0) return 1;
|
||||||
|
if (view->strides == NULL) return (view->ndim == 1);
|
||||||
|
|
||||||
|
sd = view->itemsize;
|
||||||
|
if (view->ndim == 1) return (view->shape[0] == 1 ||
|
||||||
|
sd == view->strides[0]);
|
||||||
|
for (i=0; i<view->ndim; i++) {
|
||||||
|
dim = view->shape[i];
|
||||||
|
if (dim == 0) return 1;
|
||||||
|
if (view->strides[i] != sd) return 0;
|
||||||
|
sd *= dim;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_IsCContiguous(PyBuffer *view)
|
||||||
|
{
|
||||||
|
Py_ssize_t sd, dim;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (view->ndim == 0) return 1;
|
||||||
|
if (view->strides == NULL) return 1;
|
||||||
|
|
||||||
|
sd = view->itemsize;
|
||||||
|
if (view->ndim == 1) return (view->shape[0] == 1 ||
|
||||||
|
sd == view->strides[0]);
|
||||||
|
for (i=view->ndim-1; i>=0; i--) {
|
||||||
|
dim = view->shape[i];
|
||||||
|
if (dim == 0) return 1;
|
||||||
|
if (view->strides[i] != sd) return 0;
|
||||||
|
sd *= dim;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyBuffer_IsContiguous(PyBuffer *view, char fort)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (view->suboffsets != NULL) return 0;
|
||||||
|
|
||||||
|
if (fort == 'C')
|
||||||
|
return _IsCContiguous(view);
|
||||||
|
else if (fort == 'F')
|
||||||
|
return _IsFortranContiguous(view);
|
||||||
|
else if (fort == 'A')
|
||||||
|
return (_IsCContiguous(view) || _IsFortranContiguous(view));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
PyBuffer_GetPointer(PyBuffer *view, Py_ssize_t *indices)
|
||||||
|
{
|
||||||
|
char* pointer;
|
||||||
|
int i;
|
||||||
|
pointer = (char *)view->buf;
|
||||||
|
for (i = 0; i < view->ndim; i++) {
|
||||||
|
pointer += view->strides[i]*indices[i];
|
||||||
|
if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
|
||||||
|
pointer = *((char**)pointer) + view->suboffsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (void*)pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k=0; k<nd; k++) {
|
||||||
|
if (index[k] < shape[k]-1) {
|
||||||
|
index[k]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index[k] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k=nd-1; k>=0; k--) {
|
||||||
|
if (index[k] < shape[k]-1) {
|
||||||
|
index[k]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index[k] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* view is not checked for consistency in either of these. It is
|
||||||
|
assumed that the size of the buffer is view->len in
|
||||||
|
view->len / view->itemsize elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
PyBuffer_ToContiguous(void *buf, PyBuffer *view, Py_ssize_t len, char fort)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
void (*addone)(int, Py_ssize_t *, Py_ssize_t *);
|
||||||
|
Py_ssize_t *indices, elements;
|
||||||
|
char *dest, *ptr;
|
||||||
|
|
||||||
|
if (len > view->len) {
|
||||||
|
len = view->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyBuffer_IsContiguous(view, fort)) {
|
||||||
|
/* simplest copy is all that is needed */
|
||||||
|
memcpy(buf, view->buf, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise a more elaborate scheme is needed */
|
||||||
|
|
||||||
|
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
|
||||||
|
if (indices == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (k=0; k<view->ndim;k++) {
|
||||||
|
indices[k] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort == 'F') {
|
||||||
|
addone = _add_one_to_index_F;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addone = _add_one_to_index_C;
|
||||||
|
}
|
||||||
|
dest = buf;
|
||||||
|
/* XXX : This is not going to be the fastest code in the world
|
||||||
|
several optimizations are possible.
|
||||||
|
*/
|
||||||
|
elements = len / view->itemsize;
|
||||||
|
while (elements--) {
|
||||||
|
addone(view->ndim, indices, view->shape);
|
||||||
|
ptr = PyBuffer_GetPointer(view, indices);
|
||||||
|
memcpy(dest, ptr, view->itemsize);
|
||||||
|
dest += view->itemsize;
|
||||||
|
}
|
||||||
|
PyMem_Free(indices);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyBuffer_FromContiguous(PyBuffer *view, void *buf, Py_ssize_t len, char fort)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
void (*addone)(int, Py_ssize_t *, Py_ssize_t *);
|
||||||
|
Py_ssize_t *indices, elements;
|
||||||
|
char *src, *ptr;
|
||||||
|
|
||||||
|
if (len > view->len) {
|
||||||
|
len = view->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyBuffer_IsContiguous(view, fort)) {
|
||||||
|
/* simplest copy is all that is needed */
|
||||||
|
memcpy(view->buf, buf, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise a more elaborate scheme is needed */
|
||||||
|
|
||||||
|
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
|
||||||
|
if (indices == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (k=0; k<view->ndim;k++) {
|
||||||
|
indices[k] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort == 'F') {
|
||||||
|
addone = _add_one_to_index_F;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addone = _add_one_to_index_C;
|
||||||
|
}
|
||||||
|
src = buf;
|
||||||
|
/* XXX : This is not going to be the fastest code in the world
|
||||||
|
several optimizations are possible.
|
||||||
|
*/
|
||||||
|
elements = len / view->itemsize;
|
||||||
|
while (elements--) {
|
||||||
|
addone(view->ndim, indices, view->shape);
|
||||||
|
ptr = PyBuffer_GetPointer(view, indices);
|
||||||
|
memcpy(ptr, src, view->itemsize);
|
||||||
|
src += view->itemsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMem_Free(indices);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyObject_CopyData(PyObject *dest, PyObject *src)
|
||||||
|
{
|
||||||
|
PyBuffer view_dest, view_src;
|
||||||
|
int k;
|
||||||
|
Py_ssize_t *indices, elements;
|
||||||
|
char *dptr, *sptr;
|
||||||
|
|
||||||
|
if (!PyObject_CheckBuffer(dest) ||
|
||||||
|
!PyObject_CheckBuffer(src)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"both destination and source must have the "\
|
||||||
|
"buffer interface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1;
|
||||||
|
if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) {
|
||||||
|
PyObject_ReleaseBuffer(dest, &view_dest);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view_dest.len < view_src.len) {
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"destination is too small to receive data from source");
|
||||||
|
PyObject_ReleaseBuffer(dest, &view_dest);
|
||||||
|
PyObject_ReleaseBuffer(src, &view_src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((PyBuffer_IsContiguous(&view_dest, 'C') &&
|
||||||
|
PyBuffer_IsContiguous(&view_src, 'C')) ||
|
||||||
|
(PyBuffer_IsContiguous(&view_dest, 'F') &&
|
||||||
|
PyBuffer_IsContiguous(&view_src, 'F'))) {
|
||||||
|
/* simplest copy is all that is needed */
|
||||||
|
memcpy(view_dest.buf, view_src.buf, view_src.len);
|
||||||
|
PyObject_ReleaseBuffer(dest, &view_dest);
|
||||||
|
PyObject_ReleaseBuffer(src, &view_src);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise a more elaborate copy scheme is needed */
|
||||||
|
|
||||||
|
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim);
|
||||||
|
if (indices == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
PyObject_ReleaseBuffer(dest, &view_dest);
|
||||||
|
PyObject_ReleaseBuffer(src, &view_src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (k=0; k<view_src.ndim;k++) {
|
||||||
|
indices[k] = 0;
|
||||||
|
}
|
||||||
|
elements = 1;
|
||||||
|
for (k=0; k<view_src.ndim; k++) {
|
||||||
|
elements *= view_src.shape[k];
|
||||||
|
}
|
||||||
|
while (elements--) {
|
||||||
|
_add_one_to_index_C(view_src.ndim, indices, view_src.shape);
|
||||||
|
dptr = PyBuffer_GetPointer(&view_dest, indices);
|
||||||
|
sptr = PyBuffer_GetPointer(&view_src, indices);
|
||||||
|
memcpy(dptr, sptr, view_src.itemsize);
|
||||||
|
}
|
||||||
|
PyMem_Free(indices);
|
||||||
|
PyObject_ReleaseBuffer(dest, &view_dest);
|
||||||
|
PyObject_ReleaseBuffer(src, &view_src);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape,
|
||||||
|
Py_ssize_t *strides, int itemsize,
|
||||||
|
char fort)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
Py_ssize_t sd;
|
||||||
|
|
||||||
|
sd = itemsize;
|
||||||
|
if (fort == 'F') {
|
||||||
|
for (k=0; k<nd; k++) {
|
||||||
|
strides[k] = sd;
|
||||||
|
sd *= shape[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (k=nd-1; k>=0; k--) {
|
||||||
|
strides[k] = sd;
|
||||||
|
sd *= shape[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyBuffer_FillInfo(PyBuffer *view, void *buf, Py_ssize_t len,
|
||||||
|
int readonly, int flags)
|
||||||
|
{
|
||||||
|
if (view == NULL) return 0;
|
||||||
|
if (((flags & PyBUF_LOCKDATA) == PyBUF_LOCKDATA) &&
|
||||||
|
readonly != -1) {
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"Cannot make this object read-only.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) &&
|
||||||
|
readonly == 1) {
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"Object is not writeable.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
view->buf = buf;
|
||||||
|
view->len = len;
|
||||||
|
view->readonly = readonly;
|
||||||
|
view->itemsize = 1;
|
||||||
|
view->format = NULL;
|
||||||
|
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||||
|
view->format = "B";
|
||||||
|
view->ndim = 1;
|
||||||
|
view->shape = NULL;
|
||||||
|
if ((flags & PyBUF_ND) == PyBUF_ND)
|
||||||
|
view->shape = &(view->len);
|
||||||
|
view->strides = NULL;
|
||||||
|
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
|
||||||
|
view->strides = &(view->itemsize);
|
||||||
|
view->suboffsets = NULL;
|
||||||
|
view->internal = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Operations on numbers */
|
/* Operations on numbers */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -15,80 +15,58 @@ typedef struct {
|
||||||
} PyBufferObject;
|
} PyBufferObject;
|
||||||
|
|
||||||
|
|
||||||
enum buffer_t {
|
|
||||||
READ_BUFFER,
|
|
||||||
WRITE_BUFFER,
|
|
||||||
CHAR_BUFFER,
|
|
||||||
ANY_BUFFER
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
|
get_buf(PyBufferObject *self, PyBuffer *view, int flags)
|
||||||
enum buffer_t buffer_type)
|
|
||||||
{
|
{
|
||||||
if (self->b_base == NULL) {
|
if (self->b_base == NULL) {
|
||||||
assert (ptr != NULL);
|
view->buf = self->b_ptr;
|
||||||
*ptr = self->b_ptr;
|
view->len = self->b_size;
|
||||||
*size = self->b_size;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_ssize_t count, offset;
|
Py_ssize_t count, offset;
|
||||||
readbufferproc proc = 0;
|
|
||||||
PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
|
PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
|
||||||
if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
|
if ((*bp->bf_getbuffer)(self->b_base, view, flags) < 0) return 0;
|
||||||
PyErr_SetString(PyExc_TypeError,
|
count = view->len;
|
||||||
"single-segment buffer object expected");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((buffer_type == READ_BUFFER) ||
|
|
||||||
((buffer_type == ANY_BUFFER) && self->b_readonly))
|
|
||||||
proc = bp->bf_getreadbuffer;
|
|
||||||
else if ((buffer_type == WRITE_BUFFER) ||
|
|
||||||
(buffer_type == ANY_BUFFER))
|
|
||||||
proc = (readbufferproc)bp->bf_getwritebuffer;
|
|
||||||
else if (buffer_type == CHAR_BUFFER) {
|
|
||||||
proc = (readbufferproc)bp->bf_getcharbuffer;
|
|
||||||
}
|
|
||||||
if (!proc) {
|
|
||||||
char *buffer_type_name;
|
|
||||||
switch (buffer_type) {
|
|
||||||
case READ_BUFFER:
|
|
||||||
buffer_type_name = "read";
|
|
||||||
break;
|
|
||||||
case WRITE_BUFFER:
|
|
||||||
buffer_type_name = "write";
|
|
||||||
break;
|
|
||||||
case CHAR_BUFFER:
|
|
||||||
buffer_type_name = "char";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
buffer_type_name = "no";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%s buffer type not available",
|
|
||||||
buffer_type_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
|
|
||||||
return 0;
|
|
||||||
/* apply constraints to the start/end */
|
/* apply constraints to the start/end */
|
||||||
if (self->b_offset > count)
|
if (self->b_offset > count)
|
||||||
offset = count;
|
offset = count;
|
||||||
else
|
else
|
||||||
offset = self->b_offset;
|
offset = self->b_offset;
|
||||||
*(char **)ptr = *(char **)ptr + offset;
|
view->buf = (char*)view->buf + offset;
|
||||||
if (self->b_size == Py_END_OF_BUFFER)
|
if (self->b_size == Py_END_OF_BUFFER)
|
||||||
*size = count;
|
view->len = count;
|
||||||
else
|
else
|
||||||
*size = self->b_size;
|
view->len = self->b_size;
|
||||||
if (offset + *size > count)
|
if (offset + view->len > count)
|
||||||
*size = count - offset;
|
view->len = count - offset;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
buffer_getbuf(PyBufferObject *self, PyBuffer *view, int flags)
|
||||||
|
{
|
||||||
|
if (view == NULL) return 0;
|
||||||
|
if (!get_buf(self, view, flags))
|
||||||
|
return -1;
|
||||||
|
return PyBuffer_FillInfo(view, view->buf, view->len, self->b_readonly, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_releasebuf(PyBufferObject *self, PyBuffer *view)
|
||||||
|
{
|
||||||
|
/* No-op if there is no self->b_base */
|
||||||
|
if (self->b_base != NULL) {
|
||||||
|
PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
|
||||||
|
if (bp->bf_releasebuffer != NULL) {
|
||||||
|
(*bp->bf_releasebuffer)(self->b_base, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
|
buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
|
||||||
int readonly)
|
int readonly)
|
||||||
|
@ -152,10 +130,8 @@ PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
||||||
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
||||||
|
|
||||||
if ( pb == NULL ||
|
if ( pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getsegcount == NULL )
|
PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +144,7 @@ PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
||||||
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
||||||
|
|
||||||
if ( pb == NULL ||
|
if ( pb == NULL ||
|
||||||
pb->bf_getwritebuffer == NULL ||
|
pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getsegcount == NULL )
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -252,12 +226,12 @@ buffer_dealloc(PyBufferObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_bufx(PyObject *obj, void **ptr, Py_ssize_t *size)
|
get_bufx(PyObject *obj, PyBuffer *view, int flags)
|
||||||
{
|
{
|
||||||
PyBufferProcs *bp;
|
PyBufferProcs *bp;
|
||||||
|
|
||||||
if (PyBuffer_Check(obj)) {
|
if (PyBuffer_Check(obj)) {
|
||||||
if (!get_buf((PyBufferObject *)obj, ptr, size, ANY_BUFFER)) {
|
if (!get_buf((PyBufferObject *)obj, view, flags)) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -266,17 +240,11 @@ get_bufx(PyObject *obj, void **ptr, Py_ssize_t *size)
|
||||||
}
|
}
|
||||||
bp = obj->ob_type->tp_as_buffer;
|
bp = obj->ob_type->tp_as_buffer;
|
||||||
if (bp == NULL ||
|
if (bp == NULL ||
|
||||||
bp->bf_getreadbuffer == NULL ||
|
bp->bf_getbuffer == NULL)
|
||||||
bp->bf_getsegcount == NULL)
|
|
||||||
return 0;
|
return 0;
|
||||||
if ((*bp->bf_getsegcount)(obj, NULL) != 1)
|
if ((*bp->bf_getbuffer)(obj, view, PyBUF_SIMPLE) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
*size = (*bp->bf_getreadbuffer)(obj, 0, ptr);
|
return 1;
|
||||||
if (*size < 0) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -285,12 +253,15 @@ buffer_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
void *p1, *p2;
|
void *p1, *p2;
|
||||||
Py_ssize_t len1, len2, min_len;
|
Py_ssize_t len1, len2, min_len;
|
||||||
int cmp, ok;
|
int cmp, ok;
|
||||||
|
PyBuffer v1, v2;
|
||||||
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
if (!get_bufx(self, &p1, &len1))
|
if (!get_bufx(self, &v1, PyBUF_SIMPLE))
|
||||||
ok = 0;
|
ok = 0;
|
||||||
if (!get_bufx(other, &p2, &len2))
|
if (!get_bufx(other, &v2, PyBUF_SIMPLE)) {
|
||||||
|
if (ok) PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
/* If we can't get the buffers,
|
/* If we can't get the buffers,
|
||||||
== and != are still defined
|
== and != are still defined
|
||||||
|
@ -305,11 +276,17 @@ buffer_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
Py_INCREF(result);
|
Py_INCREF(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
len1 = v1.len;
|
||||||
|
len2 = v2.len;
|
||||||
|
p1 = v1.buf;
|
||||||
|
p2 = v2.buf;
|
||||||
min_len = (len1 < len2) ? len1 : len2;
|
min_len = (len1 < len2) ? len1 : len2;
|
||||||
cmp = memcmp(p1, p2, min_len);
|
cmp = memcmp(p1, p2, min_len);
|
||||||
if (cmp == 0)
|
if (cmp == 0)
|
||||||
cmp = (len1 < len2) ? -1 :
|
cmp = (len1 < len2) ? -1 :
|
||||||
(len1 > len2) ? 1 : 0;
|
(len1 > len2) ? 1 : 0;
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
|
PyObject_ReleaseBuffer(other, &v2);
|
||||||
return Py_CmpToRich(op, cmp);
|
return Py_CmpToRich(op, cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,8 +314,7 @@ buffer_repr(PyBufferObject *self)
|
||||||
static long
|
static long
|
||||||
buffer_hash(PyBufferObject *self)
|
buffer_hash(PyBufferObject *self)
|
||||||
{
|
{
|
||||||
void *ptr;
|
PyBuffer view;
|
||||||
Py_ssize_t size;
|
|
||||||
register Py_ssize_t len;
|
register Py_ssize_t len;
|
||||||
register unsigned char *p;
|
register unsigned char *p;
|
||||||
register long x;
|
register long x;
|
||||||
|
@ -346,42 +322,39 @@ buffer_hash(PyBufferObject *self)
|
||||||
if ( self->b_hash != -1 )
|
if ( self->b_hash != -1 )
|
||||||
return self->b_hash;
|
return self->b_hash;
|
||||||
|
|
||||||
/* XXX potential bugs here, a readonly buffer does not imply that the
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
* underlying memory is immutable. b_readonly is a necessary but not
|
return -1;
|
||||||
* sufficient condition for a buffer to be hashable. Perhaps it would
|
if (!(self->b_readonly)) {
|
||||||
* be better to only allow hashing if the underlying object is known to
|
PyErr_SetString(PyExc_TypeError,
|
||||||
* be immutable (e.g. PyString_Check() is true). Another idea would
|
"writable buffers are not hashable");
|
||||||
* be to call tp_hash on the underlying object and see if it raises
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
* an error. */
|
|
||||||
if ( !self->b_readonly )
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"writable buffers are not hashable");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
p = (unsigned char *) view.buf;
|
||||||
return -1;
|
len = view.len;
|
||||||
p = (unsigned char *) ptr;
|
|
||||||
len = size;
|
|
||||||
x = *p << 7;
|
x = *p << 7;
|
||||||
while (--len >= 0)
|
while (--len >= 0)
|
||||||
x = (1000003*x) ^ *p++;
|
x = (1000003*x) ^ *p++;
|
||||||
x ^= size;
|
x ^= view.len;
|
||||||
if (x == -1)
|
if (x == -1)
|
||||||
x = -2;
|
x = -2;
|
||||||
self->b_hash = x;
|
self->b_hash = x;
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffer_str(PyBufferObject *self)
|
buffer_str(PyBufferObject *self)
|
||||||
{
|
{
|
||||||
void *ptr;
|
PyBuffer view;
|
||||||
Py_ssize_t size;
|
PyObject *res;
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
|
||||||
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
return PyString_FromStringAndSize((const char *)ptr, size);
|
res = PyString_FromStringAndSize((const char *)view.buf, view.len);
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sequence methods */
|
/* Sequence methods */
|
||||||
|
@ -389,71 +362,58 @@ buffer_str(PyBufferObject *self)
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
buffer_length(PyBufferObject *self)
|
buffer_length(PyBufferObject *self)
|
||||||
{
|
{
|
||||||
void *ptr;
|
PyBuffer view;
|
||||||
Py_ssize_t size;
|
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return -1;
|
return -1;
|
||||||
return size;
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return view.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffer_concat(PyBufferObject *self, PyObject *other)
|
buffer_concat(PyBufferObject *self, PyObject *other)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb = other->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = other->ob_type->tp_as_buffer;
|
||||||
void *ptr1, *ptr2;
|
|
||||||
char *p;
|
char *p;
|
||||||
PyObject *ob;
|
PyObject *ob;
|
||||||
Py_ssize_t size, count;
|
PyBuffer view, view2;
|
||||||
|
|
||||||
if ( pb == NULL ||
|
if ( pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL)
|
||||||
pb->bf_getsegcount == NULL )
|
|
||||||
{
|
{
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
|
||||||
{
|
|
||||||
/* ### use a different exception type/message? */
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"single-segment buffer object expected");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* optimize special case */
|
/* optimize special case */
|
||||||
/* XXX bad idea type-wise */
|
/* XXX bad idea type-wise */
|
||||||
if ( size == 0 )
|
if ( view.len == 0 ) {
|
||||||
{
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
Py_INCREF(other);
|
Py_INCREF(other);
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyUnicode_Check(other)) {
|
if (PyObject_GetBuffer((PyObject *)other, &view2, PyBUF_SIMPLE) < 0) {
|
||||||
/* XXX HACK */
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
if ( (count = (*pb->bf_getcharbuffer)(other, 0,
|
return NULL;
|
||||||
(char **)&ptr2)) < 0 )
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX Should return a bytes object, really */
|
ob = PyBytes_FromStringAndSize(NULL, view.len+view2.len);
|
||||||
ob = PyString_FromStringAndSize(NULL, size + count);
|
if ( ob == NULL ) {
|
||||||
if ( ob == NULL )
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
PyObject_ReleaseBuffer(other, &view2);
|
||||||
return NULL;
|
return NULL;
|
||||||
p = PyString_AS_STRING(ob);
|
}
|
||||||
memcpy(p, ptr1, size);
|
p = PyBytes_AS_STRING(ob);
|
||||||
memcpy(p + size, ptr2, count);
|
memcpy(p, view.buf, view.len);
|
||||||
|
memcpy(p + view.len, view2.buf, view2.len);
|
||||||
|
|
||||||
/* there is an extra byte in the string object, so this is safe */
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
p[size + count] = '\0';
|
PyObject_ReleaseBuffer(other, &view2);
|
||||||
|
return ob;
|
||||||
return ob;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -461,81 +421,83 @@ buffer_repeat(PyBufferObject *self, Py_ssize_t count)
|
||||||
{
|
{
|
||||||
PyObject *ob;
|
PyObject *ob;
|
||||||
register char *p;
|
register char *p;
|
||||||
void *ptr;
|
PyBuffer view;
|
||||||
Py_ssize_t size;
|
|
||||||
|
|
||||||
if ( count < 0 )
|
if ( count < 0 )
|
||||||
count = 0;
|
count = 0;
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
ob = PyString_FromStringAndSize(NULL, size * count);
|
ob = PyBytes_FromStringAndSize(NULL, view.len * count);
|
||||||
if ( ob == NULL )
|
if ( ob == NULL )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
p = PyString_AS_STRING(ob);
|
p = PyBytes_AS_STRING(ob);
|
||||||
while ( count-- )
|
while ( count-- )
|
||||||
{
|
{
|
||||||
memcpy(p, ptr, size);
|
memcpy(p, view.buf, view.len);
|
||||||
p += size;
|
p += view.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* there is an extra byte in the string object, so this is safe */
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
return ob;
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffer_item(PyBufferObject *self, Py_ssize_t idx)
|
buffer_item(PyBufferObject *self, Py_ssize_t idx)
|
||||||
{
|
{
|
||||||
void *ptr;
|
PyBuffer view;
|
||||||
Py_ssize_t size;
|
PyObject *ob;
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
|
||||||
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
if ( idx < 0 || idx >= size ) {
|
if ( idx < 0 || idx >= view.len ) {
|
||||||
PyErr_SetString(PyExc_IndexError, "buffer index out of range");
|
PyErr_SetString(PyExc_IndexError, "buffer index out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return PyString_FromStringAndSize((char *)ptr + idx, 1);
|
ob = PyBytes_FromStringAndSize((char *)view.buf + idx, 1);
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
|
buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
|
||||||
{
|
{
|
||||||
void *ptr;
|
PyObject *ob;
|
||||||
Py_ssize_t size;
|
PyBuffer view;
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
if ( left < 0 )
|
if ( left < 0 )
|
||||||
left = 0;
|
left = 0;
|
||||||
if ( right < 0 )
|
if ( right < 0 )
|
||||||
right = 0;
|
right = 0;
|
||||||
if ( right > size )
|
if ( right > view.len )
|
||||||
right = size;
|
right = view.len;
|
||||||
if ( right < left )
|
if ( right < left )
|
||||||
right = left;
|
right = left;
|
||||||
return PyString_FromStringAndSize((char *)ptr + left,
|
ob = PyBytes_FromStringAndSize((char *)view.buf + left,
|
||||||
right - left);
|
right - left);
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
|
buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb;
|
PyBufferProcs *pb;
|
||||||
void *ptr1, *ptr2;
|
PyBuffer view, view2;
|
||||||
Py_ssize_t size;
|
|
||||||
Py_ssize_t count;
|
|
||||||
|
|
||||||
if ( self->b_readonly ) {
|
if (!get_buf(self, &view, PyBUF_SIMPLE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ( self->b_readonly || view.readonly ) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"buffer is read-only");
|
"buffer is read-only");
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
if (idx < 0 || idx >= view.len) {
|
||||||
return -1;
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
|
||||||
if (idx < 0 || idx >= size) {
|
|
||||||
PyErr_SetString(PyExc_IndexError,
|
PyErr_SetString(PyExc_IndexError,
|
||||||
"buffer assignment index out of range");
|
"buffer assignment index out of range");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -543,29 +505,27 @@ buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
|
||||||
|
|
||||||
pb = other ? other->ob_type->tp_as_buffer : NULL;
|
pb = other ? other->ob_type->tp_as_buffer : NULL;
|
||||||
if ( pb == NULL ||
|
if ( pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getsegcount == NULL )
|
|
||||||
{
|
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
|
||||||
{
|
if (PyObject_GetBuffer(other, &view2, PyBUF_SIMPLE) < 0) {
|
||||||
/* ### use a different exception type/message? */
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
PyErr_SetString(PyExc_TypeError,
|
return -1;
|
||||||
"single-segment buffer object expected");
|
}
|
||||||
return -1;
|
if ( view.len != 1 ) {
|
||||||
}
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
PyObject_ReleaseBuffer(other, &view2);
|
||||||
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
|
||||||
return -1;
|
|
||||||
if ( count != 1 ) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"right operand must be a single byte");
|
"right operand must be a single byte");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
((char *)ptr1)[idx] = *(char *)ptr2;
|
((char *)(view.buf))[idx] = *((char *)(view2.buf));
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
PyObject_ReleaseBuffer(other, &view2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,125 +533,60 @@ static int
|
||||||
buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
|
buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
|
||||||
{
|
{
|
||||||
PyBufferProcs *pb;
|
PyBufferProcs *pb;
|
||||||
void *ptr1, *ptr2;
|
PyBuffer v1, v2;
|
||||||
Py_ssize_t size;
|
|
||||||
Py_ssize_t slice_len;
|
Py_ssize_t slice_len;
|
||||||
Py_ssize_t count;
|
|
||||||
|
|
||||||
if ( self->b_readonly ) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"buffer is read-only");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb = other ? other->ob_type->tp_as_buffer : NULL;
|
pb = other ? other->ob_type->tp_as_buffer : NULL;
|
||||||
if ( pb == NULL ||
|
if ( pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL)
|
||||||
pb->bf_getsegcount == NULL )
|
|
||||||
{
|
{
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
if (!get_buf(self, &v1, PyBUF_SIMPLE))
|
||||||
{
|
return -1;
|
||||||
/* ### use a different exception type/message? */
|
|
||||||
|
if ( self->b_readonly || v1.readonly) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"single-segment buffer object expected");
|
"buffer is read-only");
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
|
||||||
return -1;
|
if ((*pb->bf_getbuffer)(other, &v2, PyBUF_SIMPLE) < 0) {
|
||||||
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ( left < 0 )
|
if ( left < 0 )
|
||||||
left = 0;
|
left = 0;
|
||||||
else if ( left > size )
|
else if ( left > v1.len )
|
||||||
left = size;
|
left = v1.len;
|
||||||
if ( right < left )
|
if ( right < left )
|
||||||
right = left;
|
right = left;
|
||||||
else if ( right > size )
|
else if ( right > v1.len )
|
||||||
right = size;
|
right = v1.len;
|
||||||
slice_len = right - left;
|
slice_len = right - left;
|
||||||
|
|
||||||
if ( count != slice_len ) {
|
if ( v2.len != slice_len ) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"right operand length must match slice length");
|
"right operand length must match slice length");
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
|
PyObject_ReleaseBuffer(other, &v2);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( slice_len )
|
if ( slice_len )
|
||||||
memcpy((char *)ptr1 + left, ptr2, slice_len);
|
memcpy((char *)v1.buf + left, v2.buf, slice_len);
|
||||||
|
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &v1);
|
||||||
|
PyObject_ReleaseBuffer(other, &v2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buffer methods */
|
/* Buffer methods */
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
|
||||||
{
|
|
||||||
Py_ssize_t size;
|
|
||||||
if ( idx != 0 ) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
|
||||||
"accessing non-existent buffer segment");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!get_buf(self, pp, &size, READ_BUFFER))
|
|
||||||
return -1;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
|
||||||
{
|
|
||||||
Py_ssize_t size;
|
|
||||||
|
|
||||||
if ( self->b_readonly )
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "buffer is read-only");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( idx != 0 ) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
|
||||||
"accessing non-existent buffer segment");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!get_buf(self, pp, &size, WRITE_BUFFER))
|
|
||||||
return -1;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
Py_ssize_t size;
|
|
||||||
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
|
||||||
return -1;
|
|
||||||
if (lenp)
|
|
||||||
*lenp = size;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
Py_ssize_t size;
|
|
||||||
if ( idx != 0 ) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
|
||||||
"accessing non-existent buffer segment");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
|
|
||||||
return -1;
|
|
||||||
*pp = (const char *)ptr;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PySequenceMethods buffer_as_sequence = {
|
static PySequenceMethods buffer_as_sequence = {
|
||||||
(lenfunc)buffer_length, /*sq_length*/
|
(lenfunc)buffer_length, /*sq_length*/
|
||||||
(binaryfunc)buffer_concat, /*sq_concat*/
|
(binaryfunc)buffer_concat, /*sq_concat*/
|
||||||
|
@ -703,10 +598,8 @@ static PySequenceMethods buffer_as_sequence = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyBufferProcs buffer_as_buffer = {
|
static PyBufferProcs buffer_as_buffer = {
|
||||||
(readbufferproc)buffer_getreadbuf,
|
(getbufferproc)buffer_getbuf,
|
||||||
(writebufferproc)buffer_getwritebuf,
|
(releasebufferproc)buffer_releasebuf,
|
||||||
(segcountproc)buffer_getsegcount,
|
|
||||||
(charbufferproc)buffer_getcharbuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PyTypeObject PyBuffer_Type = {
|
PyTypeObject PyBuffer_Type = {
|
||||||
|
|
|
@ -26,6 +26,7 @@ PyBytes_Init(void)
|
||||||
return 0;
|
return 0;
|
||||||
nullbytes->ob_bytes = NULL;
|
nullbytes->ob_bytes = NULL;
|
||||||
Py_Size(nullbytes) = nullbytes->ob_alloc = 0;
|
Py_Size(nullbytes) = nullbytes->ob_alloc = 0;
|
||||||
|
nullbytes->ob_exports = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,22 +49,44 @@ _getbytevalue(PyObject* arg, int *value)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bytes_getbuffer(PyBytesObject *obj, PyBuffer *view, int flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *ptr;
|
||||||
|
if (view == NULL) {
|
||||||
|
obj->ob_exports++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (obj->ob_bytes == NULL)
|
||||||
|
ptr = "";
|
||||||
|
else
|
||||||
|
ptr = obj->ob_bytes;
|
||||||
|
ret = PyBuffer_FillInfo(view, ptr, Py_Size(obj), 0, flags);
|
||||||
|
if (ret >= 0) {
|
||||||
|
obj->ob_exports++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bytes_releasebuffer(PyBytesObject *obj, PyBuffer *view)
|
||||||
|
{
|
||||||
|
obj->ob_exports--;
|
||||||
|
}
|
||||||
|
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_getbuffer(PyObject *obj, void **ptr)
|
_getbuffer(PyObject *obj, PyBuffer *view)
|
||||||
{
|
{
|
||||||
PyBufferProcs *buffer = Py_Type(obj)->tp_as_buffer;
|
PyBufferProcs *buffer = Py_Type(obj)->tp_as_buffer;
|
||||||
|
|
||||||
if (buffer == NULL ||
|
if (buffer == NULL ||
|
||||||
PyUnicode_Check(obj) ||
|
PyUnicode_Check(obj) ||
|
||||||
buffer->bf_getreadbuffer == NULL ||
|
buffer->bf_getbuffer == NULL) return -1;
|
||||||
buffer->bf_getsegcount == NULL ||
|
|
||||||
buffer->bf_getsegcount(obj, NULL) != 1)
|
|
||||||
{
|
|
||||||
*ptr = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer->bf_getreadbuffer(obj, 0, ptr);
|
if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0)
|
||||||
|
return -1;
|
||||||
|
return view->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Direct API functions */
|
/* Direct API functions */
|
||||||
|
@ -104,6 +127,7 @@ PyBytes_FromStringAndSize(const char *bytes, Py_ssize_t size)
|
||||||
}
|
}
|
||||||
Py_Size(new) = size;
|
Py_Size(new) = size;
|
||||||
new->ob_alloc = alloc;
|
new->ob_alloc = alloc;
|
||||||
|
new->ob_exports = 0;
|
||||||
|
|
||||||
return (PyObject *)new;
|
return (PyObject *)new;
|
||||||
}
|
}
|
||||||
|
@ -155,6 +179,15 @@ PyBytes_Resize(PyObject *self, Py_ssize_t size)
|
||||||
alloc = size + 1;
|
alloc = size + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((PyBytesObject *)self)->ob_exports > 0) {
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "%d: %s", ((PyBytesObject *)self)->ob_exports, ((PyBytesObject *)self)->ob_bytes);
|
||||||
|
*/
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"Existing exports of data: object cannot be re-sized");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
sval = PyMem_Realloc(((PyBytesObject *)self)->ob_bytes, alloc);
|
sval = PyMem_Realloc(((PyBytesObject *)self)->ob_bytes, alloc);
|
||||||
if (sval == NULL) {
|
if (sval == NULL) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
|
@ -172,27 +205,38 @@ PyBytes_Resize(PyObject *self, Py_ssize_t size)
|
||||||
PyObject *
|
PyObject *
|
||||||
PyBytes_Concat(PyObject *a, PyObject *b)
|
PyBytes_Concat(PyObject *a, PyObject *b)
|
||||||
{
|
{
|
||||||
Py_ssize_t asize, bsize, size;
|
Py_ssize_t size;
|
||||||
void *aptr, *bptr;
|
PyBuffer va, vb;
|
||||||
PyBytesObject *result;
|
PyBytesObject *result;
|
||||||
|
|
||||||
asize = _getbuffer(a, &aptr);
|
va.len = -1;
|
||||||
bsize = _getbuffer(b, &bptr);
|
vb.len = -1;
|
||||||
if (asize < 0 || bsize < 0) {
|
if (_getbuffer(a, &va) < 0 ||
|
||||||
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
|
_getbuffer(b, &vb) < 0) {
|
||||||
Py_Type(a)->tp_name, Py_Type(b)->tp_name);
|
if (va.len != -1)
|
||||||
return NULL;
|
PyObject_ReleaseBuffer(a, &va);
|
||||||
|
if (vb.len != -1)
|
||||||
|
PyObject_ReleaseBuffer(b, &vb);
|
||||||
|
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
|
||||||
|
Py_Type(a)->tp_name, Py_Type(b)->tp_name);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = asize + bsize;
|
size = va.len + vb.len;
|
||||||
if (size < 0)
|
if (size < 0) {
|
||||||
return PyErr_NoMemory();
|
PyObject_ReleaseBuffer(a, &va);
|
||||||
|
PyObject_ReleaseBuffer(b, &vb);
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
result = (PyBytesObject *) PyBytes_FromStringAndSize(NULL, size);
|
result = (PyBytesObject *) PyBytes_FromStringAndSize(NULL, size);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
memcpy(result->ob_bytes, aptr, asize);
|
memcpy(result->ob_bytes, va.buf, va.len);
|
||||||
memcpy(result->ob_bytes + asize, bptr, bsize);
|
memcpy(result->ob_bytes + va.len, vb.buf, vb.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject_ReleaseBuffer(a, &va);
|
||||||
|
PyObject_ReleaseBuffer(b, &vb);
|
||||||
return (PyObject *)result;
|
return (PyObject *)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,30 +257,32 @@ bytes_concat(PyBytesObject *self, PyObject *other)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytes_iconcat(PyBytesObject *self, PyObject *other)
|
bytes_iconcat(PyBytesObject *self, PyObject *other)
|
||||||
{
|
{
|
||||||
void *optr;
|
|
||||||
Py_ssize_t osize;
|
|
||||||
Py_ssize_t mysize;
|
Py_ssize_t mysize;
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
|
PyBuffer vo;
|
||||||
|
|
||||||
/* XXX What if other == self? */
|
if (_getbuffer(other, &vo) < 0) {
|
||||||
osize = _getbuffer(other, &optr);
|
PyErr_Format(PyExc_TypeError,
|
||||||
if (osize < 0) {
|
"can't concat bytes to %.100s", Py_Type(self)->tp_name);
|
||||||
PyErr_Format(PyExc_TypeError,
|
return NULL;
|
||||||
"can't concat bytes to %.100s", Py_Type(other)->tp_name);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mysize = Py_Size(self);
|
mysize = Py_Size(self);
|
||||||
size = mysize + osize;
|
size = mysize + vo.len;
|
||||||
if (size < 0)
|
if (size < 0) {
|
||||||
return PyErr_NoMemory();
|
PyObject_ReleaseBuffer(other, &vo);
|
||||||
if (size < self->ob_alloc) {
|
return PyErr_NoMemory();
|
||||||
Py_Size(self) = size;
|
|
||||||
self->ob_bytes[Py_Size(self)] = '\0'; /* Trailing null byte */
|
|
||||||
}
|
}
|
||||||
else if (PyBytes_Resize((PyObject *)self, size) < 0)
|
if (size < self->ob_alloc) {
|
||||||
return NULL;
|
Py_Size(self) = size;
|
||||||
memcpy(self->ob_bytes + mysize, optr, osize);
|
self->ob_bytes[Py_Size(self)] = '\0'; /* Trailing null byte */
|
||||||
|
}
|
||||||
|
else if (PyBytes_Resize((PyObject *)self, size) < 0) {
|
||||||
|
PyObject_ReleaseBuffer(other, &vo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(self->ob_bytes + mysize, vo.buf, vo.len);
|
||||||
|
PyObject_ReleaseBuffer(other, &vo);
|
||||||
Py_INCREF(self);
|
Py_INCREF(self);
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
@ -409,9 +455,12 @@ bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
|
||||||
{
|
{
|
||||||
Py_ssize_t avail, needed;
|
Py_ssize_t avail, needed;
|
||||||
void *bytes;
|
void *bytes;
|
||||||
|
PyBuffer vbytes;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
vbytes.len = -1;
|
||||||
if (values == (PyObject *)self) {
|
if (values == (PyObject *)self) {
|
||||||
/* Make a copy an call this function recursively */
|
/* Make a copy and call this function recursively */
|
||||||
int err;
|
int err;
|
||||||
values = PyBytes_FromObject(values);
|
values = PyBytes_FromObject(values);
|
||||||
if (values == NULL)
|
if (values == NULL)
|
||||||
|
@ -426,13 +475,14 @@ bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
|
||||||
needed = 0;
|
needed = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
needed = _getbuffer(values, &bytes);
|
if (_getbuffer(values, &vbytes) < 0) {
|
||||||
if (needed < 0) {
|
PyErr_Format(PyExc_TypeError,
|
||||||
PyErr_Format(PyExc_TypeError,
|
"can't set bytes slice from %.100s",
|
||||||
"can't set bytes slice from %.100s",
|
Py_Type(values)->tp_name);
|
||||||
Py_Type(values)->tp_name);
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
needed = vbytes.len;
|
||||||
|
bytes = vbytes.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lo < 0)
|
if (lo < 0)
|
||||||
|
@ -458,8 +508,10 @@ bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
|
||||||
Py_Size(self) - hi);
|
Py_Size(self) - hi);
|
||||||
}
|
}
|
||||||
if (PyBytes_Resize((PyObject *)self,
|
if (PyBytes_Resize((PyObject *)self,
|
||||||
Py_Size(self) + needed - avail) < 0)
|
Py_Size(self) + needed - avail) < 0) {
|
||||||
return -1;
|
res = -1;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
if (avail < needed) {
|
if (avail < needed) {
|
||||||
/*
|
/*
|
||||||
0 lo hi old_size
|
0 lo hi old_size
|
||||||
|
@ -475,7 +527,11 @@ bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
|
||||||
if (needed > 0)
|
if (needed > 0)
|
||||||
memcpy(self->ob_bytes + lo, bytes, needed);
|
memcpy(self->ob_bytes + lo, bytes, needed);
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
finish:
|
||||||
|
if (vbytes.len != -1)
|
||||||
|
PyObject_ReleaseBuffer(values, &vbytes);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -743,16 +799,22 @@ bytes_init(PyBytesObject *self, PyObject *args, PyObject *kwds)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyObject_CheckReadBuffer(arg)) {
|
/* Use the modern buffer interface */
|
||||||
const void *bytes;
|
if (PyObject_CheckBuffer(arg)) {
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
if (PyObject_AsReadBuffer(arg, &bytes, &size) < 0)
|
PyBuffer view;
|
||||||
|
if (PyObject_GetBuffer(arg, &view, PyBUF_FULL_RO) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (PyBytes_Resize((PyObject *)self, size) < 0)
|
size = view.len;
|
||||||
return -1;
|
if (PyBytes_Resize((PyObject *)self, size) < 0) goto fail;
|
||||||
memcpy(self->ob_bytes, bytes, size);
|
if (PyBuffer_ToContiguous(self->ob_bytes, &view, size, 'C') < 0)
|
||||||
|
goto fail;
|
||||||
|
PyObject_ReleaseBuffer(arg, &view);
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
PyObject_ReleaseBuffer(arg, &view);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Optimize this if the arguments is a list, tuple */
|
/* XXX Optimize this if the arguments is a list, tuple */
|
||||||
|
@ -881,7 +943,7 @@ static PyObject *
|
||||||
bytes_richcompare(PyObject *self, PyObject *other, int op)
|
bytes_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
{
|
{
|
||||||
Py_ssize_t self_size, other_size;
|
Py_ssize_t self_size, other_size;
|
||||||
void *self_bytes, *other_bytes;
|
PyBuffer self_bytes, other_bytes;
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
Py_ssize_t minsize;
|
Py_ssize_t minsize;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
@ -897,6 +959,7 @@ bytes_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
|
|
||||||
other_size = _getbuffer(other, &other_bytes);
|
other_size = _getbuffer(other, &other_bytes);
|
||||||
if (other_size < 0) {
|
if (other_size < 0) {
|
||||||
|
PyObject_ReleaseBuffer(self, &self_bytes);
|
||||||
Py_INCREF(Py_NotImplemented);
|
Py_INCREF(Py_NotImplemented);
|
||||||
return Py_NotImplemented;
|
return Py_NotImplemented;
|
||||||
}
|
}
|
||||||
|
@ -910,7 +973,7 @@ bytes_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
if (other_size < minsize)
|
if (other_size < minsize)
|
||||||
minsize = other_size;
|
minsize = other_size;
|
||||||
|
|
||||||
cmp = memcmp(self_bytes, other_bytes, minsize);
|
cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize);
|
||||||
/* In ISO C, memcmp() guarantees to use unsigned bytes! */
|
/* In ISO C, memcmp() guarantees to use unsigned bytes! */
|
||||||
|
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
|
@ -931,6 +994,8 @@ bytes_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = cmp ? Py_True : Py_False;
|
res = cmp ? Py_True : Py_False;
|
||||||
|
PyObject_ReleaseBuffer(self, &self_bytes);
|
||||||
|
PyObject_ReleaseBuffer(other, &other_bytes);
|
||||||
Py_INCREF(res);
|
Py_INCREF(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -944,30 +1009,6 @@ bytes_dealloc(PyBytesObject *self)
|
||||||
Py_Type(self)->tp_free((PyObject *)self);
|
Py_Type(self)->tp_free((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
bytes_getbuffer(PyBytesObject *self, Py_ssize_t index, const void **ptr)
|
|
||||||
{
|
|
||||||
if (index != 0) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
|
||||||
"accessing non-existent bytes segment");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (self->ob_bytes == NULL)
|
|
||||||
*ptr = "";
|
|
||||||
else
|
|
||||||
*ptr = self->ob_bytes;
|
|
||||||
return Py_Size(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_ssize_t
|
|
||||||
bytes_getsegcount(PyStringObject *self, Py_ssize_t *lenp)
|
|
||||||
{
|
|
||||||
if (lenp)
|
|
||||||
*lenp = Py_Size(self);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Methods */
|
/* Methods */
|
||||||
|
@ -1018,6 +1059,7 @@ bytes_find_internal(PyBytesObject *self, PyObject *args, int dir)
|
||||||
sub = PyBytes_AS_STRING(subobj);
|
sub = PyBytes_AS_STRING(subobj);
|
||||||
sub_len = PyBytes_GET_SIZE(subobj);
|
sub_len = PyBytes_GET_SIZE(subobj);
|
||||||
}
|
}
|
||||||
|
/* XXX --> use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len))
|
else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len))
|
||||||
/* XXX - the "expected a character buffer object" is pretty
|
/* XXX - the "expected a character buffer object" is pretty
|
||||||
confusing for a non-expert. remap to something else ? */
|
confusing for a non-expert. remap to something else ? */
|
||||||
|
@ -1075,6 +1117,7 @@ bytes_count(PyBytesObject *self, PyObject *args)
|
||||||
sub = PyBytes_AS_STRING(sub_obj);
|
sub = PyBytes_AS_STRING(sub_obj);
|
||||||
sub_len = PyBytes_GET_SIZE(sub_obj);
|
sub_len = PyBytes_GET_SIZE(sub_obj);
|
||||||
}
|
}
|
||||||
|
/* XXX --> use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(sub_obj, &sub, &sub_len))
|
else if (PyObject_AsCharBuffer(sub_obj, &sub, &sub_len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1162,6 +1205,7 @@ _bytes_tailmatch(PyBytesObject *self, PyObject *substr, Py_ssize_t start,
|
||||||
sub = PyBytes_AS_STRING(substr);
|
sub = PyBytes_AS_STRING(substr);
|
||||||
slen = PyBytes_GET_SIZE(substr);
|
slen = PyBytes_GET_SIZE(substr);
|
||||||
}
|
}
|
||||||
|
/* XXX --> Use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(substr, &sub, &slen))
|
else if (PyObject_AsCharBuffer(substr, &sub, &slen))
|
||||||
return -1;
|
return -1;
|
||||||
str = PyBytes_AS_STRING(self);
|
str = PyBytes_AS_STRING(self);
|
||||||
|
@ -1297,6 +1341,7 @@ bytes_translate(PyBytesObject *self, PyObject *args)
|
||||||
table1 = PyBytes_AS_STRING(tableobj);
|
table1 = PyBytes_AS_STRING(tableobj);
|
||||||
tablen = PyBytes_GET_SIZE(tableobj);
|
tablen = PyBytes_GET_SIZE(tableobj);
|
||||||
}
|
}
|
||||||
|
/* XXX -> Use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen))
|
else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1311,6 +1356,7 @@ bytes_translate(PyBytesObject *self, PyObject *args)
|
||||||
del_table = PyBytes_AS_STRING(delobj);
|
del_table = PyBytes_AS_STRING(delobj);
|
||||||
dellen = PyBytes_GET_SIZE(delobj);
|
dellen = PyBytes_GET_SIZE(delobj);
|
||||||
}
|
}
|
||||||
|
/* XXX -> use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen))
|
else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1973,9 +2019,11 @@ static PyObject *
|
||||||
bytes_replace(PyBytesObject *self, PyObject *args)
|
bytes_replace(PyBytesObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
Py_ssize_t count = -1;
|
Py_ssize_t count = -1;
|
||||||
PyObject *from, *to;
|
PyObject *from, *to, *res;
|
||||||
const char *from_s, *to_s;
|
const char *from_s, *to_s;
|
||||||
Py_ssize_t from_len, to_len;
|
Py_ssize_t from_len, to_len;
|
||||||
|
int relfrom=0, relto=0;
|
||||||
|
PyBuffer vfrom, vto;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
|
if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1984,19 +2032,38 @@ bytes_replace(PyBytesObject *self, PyObject *args)
|
||||||
from_s = PyBytes_AS_STRING(from);
|
from_s = PyBytes_AS_STRING(from);
|
||||||
from_len = PyBytes_GET_SIZE(from);
|
from_len = PyBytes_GET_SIZE(from);
|
||||||
}
|
}
|
||||||
else if (PyObject_AsCharBuffer(from, &from_s, &from_len))
|
else {
|
||||||
return NULL;
|
if (PyObject_GetBuffer(from, &vfrom, PyBUF_CHARACTER) < 0)
|
||||||
|
return NULL;
|
||||||
|
from_s = vfrom.buf;
|
||||||
|
from_len = vfrom.len;
|
||||||
|
relfrom = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (PyBytes_Check(to)) {
|
if (PyBytes_Check(to)) {
|
||||||
to_s = PyBytes_AS_STRING(to);
|
to_s = PyBytes_AS_STRING(to);
|
||||||
to_len = PyBytes_GET_SIZE(to);
|
to_len = PyBytes_GET_SIZE(to);
|
||||||
}
|
}
|
||||||
else if (PyObject_AsCharBuffer(to, &to_s, &to_len))
|
else {
|
||||||
return NULL;
|
if (PyObject_GetBuffer(to, &vto, PyBUF_CHARACTER) < 0) {
|
||||||
|
if (relfrom)
|
||||||
|
PyObject_ReleaseBuffer(from, &vfrom);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
to_s = vto.buf;
|
||||||
|
to_len = vto.len;
|
||||||
|
relto = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return (PyObject *)replace((PyBytesObject *) self,
|
res = (PyObject *)replace((PyBytesObject *) self,
|
||||||
from_s, from_len,
|
from_s, from_len,
|
||||||
to_s, to_len, count);
|
to_s, to_len, count);
|
||||||
|
|
||||||
|
if (relfrom)
|
||||||
|
PyObject_ReleaseBuffer(from, &vfrom);
|
||||||
|
if (relto)
|
||||||
|
PyObject_ReleaseBuffer(to, &vto);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2104,6 +2171,7 @@ bytes_split(PyBytesObject *self, PyObject *args)
|
||||||
sub = PyBytes_AS_STRING(subobj);
|
sub = PyBytes_AS_STRING(subobj);
|
||||||
n = PyBytes_GET_SIZE(subobj);
|
n = PyBytes_GET_SIZE(subobj);
|
||||||
}
|
}
|
||||||
|
/* XXX -> use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(subobj, &sub, &n))
|
else if (PyObject_AsCharBuffer(subobj, &sub, &n))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2261,6 +2329,7 @@ bytes_rsplit(PyBytesObject *self, PyObject *args)
|
||||||
sub = PyBytes_AS_STRING(subobj);
|
sub = PyBytes_AS_STRING(subobj);
|
||||||
n = PyBytes_GET_SIZE(subobj);
|
n = PyBytes_GET_SIZE(subobj);
|
||||||
}
|
}
|
||||||
|
/* XXX -> Use the modern buffer interface */
|
||||||
else if (PyObject_AsCharBuffer(subobj, &sub, &n))
|
else if (PyObject_AsCharBuffer(subobj, &sub, &n))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2756,12 +2825,8 @@ static PyMappingMethods bytes_as_mapping = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyBufferProcs bytes_as_buffer = {
|
static PyBufferProcs bytes_as_buffer = {
|
||||||
(readbufferproc)bytes_getbuffer,
|
(getbufferproc)bytes_getbuffer,
|
||||||
(writebufferproc)bytes_getbuffer,
|
(releasebufferproc)bytes_releasebuffer,
|
||||||
(segcountproc)bytes_getsegcount,
|
|
||||||
/* XXX Bytes are not characters! But we need to implement
|
|
||||||
bf_getcharbuffer() so we can be used as 't#' argument to codecs. */
|
|
||||||
(charbufferproc)bytes_getbuffer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyMethodDef
|
static PyMethodDef
|
||||||
|
|
|
@ -1539,6 +1539,11 @@ SimpleExtendsException(PyExc_Exception, ReferenceError,
|
||||||
*/
|
*/
|
||||||
SimpleExtendsException(PyExc_Exception, MemoryError, "Out of memory.");
|
SimpleExtendsException(PyExc_Exception, MemoryError, "Out of memory.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BufferError extends Exception
|
||||||
|
*/
|
||||||
|
SimpleExtendsException(PyExc_Exception, BufferError, "Buffer error.");
|
||||||
|
|
||||||
|
|
||||||
/* Warning category docstrings */
|
/* Warning category docstrings */
|
||||||
|
|
||||||
|
|
540
Objects/memoryobject.c
Normal file
540
Objects/memoryobject.c
Normal file
|
@ -0,0 +1,540 @@
|
||||||
|
|
||||||
|
/* Memoryview object implementation */
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
memory_getbuf(PyMemoryViewObject *self, PyBuffer *view, int flags)
|
||||||
|
{
|
||||||
|
if (view != NULL)
|
||||||
|
memcpy(view, &(self->view), sizeof(PyBuffer));
|
||||||
|
return self->base->ob_type->tp_as_buffer->bf_getbuffer(self->base,
|
||||||
|
NULL, PyBUF_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
memory_releasebuf(PyMemoryViewObject *self, PyBuffer *view)
|
||||||
|
{
|
||||||
|
PyObject_ReleaseBuffer(self->base, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(memory_doc,
|
||||||
|
"memoryview(object)\n\
|
||||||
|
\n\
|
||||||
|
Create a new memoryview object which references the given object.");
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyMemoryView_FromMemory(PyBuffer *info)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyMemoryView_FromObject(PyObject *base)
|
||||||
|
{
|
||||||
|
PyMemoryViewObject *mview;
|
||||||
|
|
||||||
|
if (!PyObject_CheckBuffer(base)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"cannot make memory view because object does "\
|
||||||
|
"not have the buffer interface");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
|
||||||
|
&PyMemoryView_Type);
|
||||||
|
if (mview == NULL) return NULL;
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL) < 0) {
|
||||||
|
PyObject_DEL(mview);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mview->base = base;
|
||||||
|
Py_INCREF(base);
|
||||||
|
return (PyObject *)mview;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
PyObject *obj;
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
|
||||||
|
|
||||||
|
return PyMemoryView_FromObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
|
||||||
|
Py_ssize_t *strides, int itemsize, char fort)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
Py_ssize_t outstride;
|
||||||
|
|
||||||
|
if (nd==0) {
|
||||||
|
memcpy(dest, src, itemsize);
|
||||||
|
}
|
||||||
|
else if (nd == 1) {
|
||||||
|
for (k = 0; k<shape[0]; k++) {
|
||||||
|
memcpy(dest, src, itemsize);
|
||||||
|
dest += itemsize;
|
||||||
|
src += strides[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (fort == 'F') {
|
||||||
|
/* Copy first dimension first,
|
||||||
|
second dimension second, etc...
|
||||||
|
Set up the recursive loop backwards so that final
|
||||||
|
dimension is actually copied last.
|
||||||
|
*/
|
||||||
|
outstride = itemsize;
|
||||||
|
for (k=1; k<nd-1;k++) {
|
||||||
|
outstride *= shape[k];
|
||||||
|
}
|
||||||
|
for (k=0; k<shape[nd-1]; k++) {
|
||||||
|
_strided_copy_nd(dest, src, nd-1, shape,
|
||||||
|
strides, itemsize, fort);
|
||||||
|
dest += outstride;
|
||||||
|
src += strides[nd-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
/* Copy last dimension first,
|
||||||
|
second-to-last dimension second, etc.
|
||||||
|
Set up the recursion so that the
|
||||||
|
first dimension is copied last
|
||||||
|
*/
|
||||||
|
outstride = itemsize;
|
||||||
|
for (k=1; k < nd; k++) {
|
||||||
|
outstride *= shape[k];
|
||||||
|
}
|
||||||
|
for (k=0; k<shape[0]; k++) {
|
||||||
|
_strided_copy_nd(dest, src, nd-1, shape+1,
|
||||||
|
strides+1, itemsize,
|
||||||
|
fort);
|
||||||
|
dest += outstride;
|
||||||
|
src += strides[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
|
||||||
|
void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
|
||||||
|
|
||||||
|
static int
|
||||||
|
_indirect_copy_nd(char *dest, PyBuffer *view, char fort)
|
||||||
|
{
|
||||||
|
Py_ssize_t *indices;
|
||||||
|
int k;
|
||||||
|
Py_ssize_t elements;
|
||||||
|
char *ptr;
|
||||||
|
void (*func)(int, Py_ssize_t *, Py_ssize_t *);
|
||||||
|
|
||||||
|
|
||||||
|
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
|
||||||
|
if (indices == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (k=0; k<view->ndim;k++) {
|
||||||
|
indices[k] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
elements = 1;
|
||||||
|
for (k=0; k<view->ndim; k++) {
|
||||||
|
elements *= view->shape[k];
|
||||||
|
}
|
||||||
|
if (fort == 'F') {
|
||||||
|
func = _add_one_to_index_F;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
func = _add_one_to_index_C;
|
||||||
|
}
|
||||||
|
while (elements--) {
|
||||||
|
func(view->ndim, indices, view->shape);
|
||||||
|
ptr = PyBuffer_GetPointer(view, indices);
|
||||||
|
memcpy(dest, ptr, view->itemsize);
|
||||||
|
dest += view->itemsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMem_Free(indices);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get a the data from an object as a contiguous chunk of memory (in
|
||||||
|
either 'C' or 'F'ortran order) even if it means copying it into a
|
||||||
|
separate memory area.
|
||||||
|
|
||||||
|
Returns a new reference to a Memory view object. If no copy is needed,
|
||||||
|
the memory view object points to the original memory and holds a
|
||||||
|
lock on the original. If a copy is needed, then the memory view object
|
||||||
|
points to a brand-new Bytes object (and holds a memory lock on it).
|
||||||
|
|
||||||
|
buffertype
|
||||||
|
|
||||||
|
PyBUF_READ buffer only needs to be read-only
|
||||||
|
PyBUF_WRITE buffer needs to be writeable (give error if not contiguous)
|
||||||
|
PyBUF_SHADOW buffer needs to be writeable so shadow it with
|
||||||
|
a contiguous buffer if it is not. The view will point to
|
||||||
|
the shadow buffer which can be written to and then
|
||||||
|
will be copied back into the other buffer when the memory
|
||||||
|
view is de-allocated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
|
||||||
|
{
|
||||||
|
PyMemoryViewObject *mem;
|
||||||
|
PyObject *bytes;
|
||||||
|
PyBuffer *view;
|
||||||
|
int flags;
|
||||||
|
char *dest;
|
||||||
|
|
||||||
|
if (!PyObject_CheckBuffer(obj)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"object does not have the buffer interface");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
|
||||||
|
if (mem == NULL) return NULL;
|
||||||
|
|
||||||
|
view = &PyMemoryView(mem);
|
||||||
|
flags = PyBUF_FULL_RO;
|
||||||
|
switch(buffertype) {
|
||||||
|
case PyBUF_WRITE:
|
||||||
|
flags = PyBUF_FULL;
|
||||||
|
break;
|
||||||
|
case PyBUF_SHADOW:
|
||||||
|
flags = PyBUF_FULL_LCK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer(obj, view, flags) != 0) {
|
||||||
|
PyObject_DEL(mem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyBuffer_IsContiguous(view, fort)) {
|
||||||
|
/* no copy needed */
|
||||||
|
Py_INCREF(obj);
|
||||||
|
mem->base = obj;
|
||||||
|
return (PyObject *)mem;
|
||||||
|
}
|
||||||
|
/* otherwise a copy is needed */
|
||||||
|
if (buffertype == PyBUF_WRITE) {
|
||||||
|
PyObject_DEL(mem);
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"writeable contiguous buffer requested for a non-contiguous" \
|
||||||
|
"object.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bytes = PyBytes_FromStringAndSize(NULL, view->len);
|
||||||
|
if (bytes == NULL) {
|
||||||
|
PyObject_ReleaseBuffer(obj, view);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dest = PyBytes_AS_STRING(bytes);
|
||||||
|
/* different copying strategy depending on whether
|
||||||
|
or not any pointer de-referencing is needed
|
||||||
|
*/
|
||||||
|
/* strided or in-direct copy */
|
||||||
|
if (view->suboffsets==NULL) {
|
||||||
|
_strided_copy_nd(dest, view->buf, view->ndim, view->shape,
|
||||||
|
view->strides, view->itemsize, fort);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_indirect_copy_nd(dest, view, fort) < 0) {
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
PyObject_ReleaseBuffer(obj, view);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffertype == PyBUF_SHADOW) {
|
||||||
|
/* return a shadowed memory-view object */
|
||||||
|
view->buf = dest;
|
||||||
|
mem->base = PyTuple_Pack(2, obj, bytes);
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject_ReleaseBuffer(obj, view);
|
||||||
|
/* steal the reference */
|
||||||
|
mem->base = bytes;
|
||||||
|
}
|
||||||
|
return (PyObject *)mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_format_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return PyUnicode_FromString(self->view.format);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_itemsize_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return PyInt_FromLong(self->view.itemsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_IntTupleFromSsizet(int len, Py_ssize_t *vals)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PyObject *o;
|
||||||
|
PyObject *intTuple;
|
||||||
|
|
||||||
|
if (vals == NULL) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
intTuple = PyTuple_New(len);
|
||||||
|
if (!intTuple) return NULL;
|
||||||
|
for(i=0; i<len; i++) {
|
||||||
|
o = PyInt_FromSsize_t(vals[i]);
|
||||||
|
if (!o) {
|
||||||
|
Py_DECREF(intTuple);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyTuple_SET_ITEM(intTuple, i, o);
|
||||||
|
}
|
||||||
|
return intTuple;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_shape_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_strides_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_suboffsets_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_size_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return PyInt_FromSsize_t(self->view.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_readonly_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return PyInt_FromLong(self->view.readonly);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_ndim_get(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
return PyInt_FromLong(self->view.ndim);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyGetSetDef memory_getsetlist[] ={
|
||||||
|
{"format",
|
||||||
|
(getter)memory_format_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"itemsize",
|
||||||
|
(getter)memory_itemsize_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"shape",
|
||||||
|
(getter)memory_shape_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"strides",
|
||||||
|
(getter)memory_strides_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"suboffsets",
|
||||||
|
(getter)memory_suboffsets_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"size",
|
||||||
|
(getter)memory_size_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"readonly",
|
||||||
|
(getter)memory_readonly_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{"ndim",
|
||||||
|
(getter)memory_ndim_get,
|
||||||
|
NULL, NULL},
|
||||||
|
{NULL, NULL, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_tobytes(PyMemoryViewObject *mem, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, "")) return NULL;
|
||||||
|
/* Create new Bytes object for data */
|
||||||
|
return PyBytes_FromObject((PyObject *)mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_tolist(PyMemoryViewObject *mem, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, "")) return NULL;
|
||||||
|
Py_INCREF(Py_NotImplemented);
|
||||||
|
return Py_NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static PyMethodDef memory_methods[] = {
|
||||||
|
{"tobytes", (PyCFunction)memory_tobytes, 1, NULL},
|
||||||
|
{"tolist", (PyCFunction)memory_tolist, 1, NULL},
|
||||||
|
{NULL, NULL} /* sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
memory_dealloc(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (PyTuple_Check(self->base)) {
|
||||||
|
/* Special case when first element is generic object
|
||||||
|
with buffer interface and the second element is a
|
||||||
|
contiguous "shadow" that must be copied back into
|
||||||
|
the data areay of the first tuple element before
|
||||||
|
releasing the buffer on the first element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
|
||||||
|
PyTuple_GET_ITEM(self->base,1));
|
||||||
|
|
||||||
|
/* The view member should have readonly == -1 in
|
||||||
|
this instance indicating that the memory can
|
||||||
|
be "locked" and was locked and will be unlocked
|
||||||
|
again after this call.
|
||||||
|
*/
|
||||||
|
PyObject_ReleaseBuffer(PyTuple_GET_ITEM(self->base,0),
|
||||||
|
&(self->view));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject_ReleaseBuffer(self->base, &(self->view));
|
||||||
|
}
|
||||||
|
Py_DECREF(self->base);
|
||||||
|
PyObject_DEL(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_repr(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( self->base == NULL )
|
||||||
|
return PyUnicode_FromFormat("<memory at %p>",
|
||||||
|
self);
|
||||||
|
else
|
||||||
|
return PyUnicode_FromFormat(
|
||||||
|
"<memory at %p>",
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_str(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
PyBuffer view;
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = PyBytes_FromStringAndSize(NULL, view.len);
|
||||||
|
PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sequence methods */
|
||||||
|
|
||||||
|
static Py_ssize_t
|
||||||
|
memory_length(PyMemoryViewObject *self)
|
||||||
|
{
|
||||||
|
PyBuffer view;
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
|
||||||
|
return -1;
|
||||||
|
PyObject_ReleaseBuffer((PyObject *)self, &view);
|
||||||
|
return view.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_subscript(PyMemoryViewObject *self, PyObject *key)
|
||||||
|
{
|
||||||
|
Py_INCREF(Py_NotImplemented);
|
||||||
|
return Py_NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As mapping */
|
||||||
|
static PyMappingMethods memory_as_mapping = {
|
||||||
|
(lenfunc)memory_length, /*mp_length*/
|
||||||
|
(binaryfunc)memory_subscript, /*mp_subscript*/
|
||||||
|
(objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Buffer methods */
|
||||||
|
|
||||||
|
static PyBufferProcs memory_as_buffer = {
|
||||||
|
(getbufferproc)memory_getbuf, /* bf_getbuffer */
|
||||||
|
(releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PyTypeObject PyMemoryView_Type = {
|
||||||
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
"memoryview",
|
||||||
|
sizeof(PyMemoryViewObject),
|
||||||
|
0,
|
||||||
|
(destructor)memory_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)memory_repr, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
&memory_as_mapping, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
(reprfunc)memory_str, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
&memory_as_buffer, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
memory_doc, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
memory_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
memory_getsetlist, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
0, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
memory_new, /* tp_new */
|
||||||
|
};
|
|
@ -1171,44 +1171,10 @@ string_subscript(PyStringObject* self, PyObject* item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
static int
|
||||||
string_buffer_getreadbuf(PyStringObject *self, Py_ssize_t index, const void **ptr)
|
string_buffer_getbuffer(PyStringObject *self, PyBuffer *view, int flags)
|
||||||
{
|
{
|
||||||
if ( index != 0 ) {
|
return PyBuffer_FillInfo(view, (void *)self->ob_sval, Py_Size(self), 0, flags);
|
||||||
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)
|
|
||||||
{
|
|
||||||
if ( index != 0 ) {
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
|
||||||
"accessing non-existent string segment");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*ptr = self->ob_sval;
|
|
||||||
return Py_Size(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods string_as_sequence = {
|
static PySequenceMethods string_as_sequence = {
|
||||||
|
@ -1229,14 +1195,11 @@ static PyMappingMethods string_as_mapping = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyBufferProcs string_as_buffer = {
|
static PyBufferProcs string_as_buffer = {
|
||||||
(readbufferproc)string_buffer_getreadbuf,
|
(getbufferproc)string_buffer_getbuffer,
|
||||||
(writebufferproc)string_buffer_getwritebuf,
|
NULL,
|
||||||
(segcountproc)string_buffer_getsegcount,
|
|
||||||
(charbufferproc)string_buffer_getcharbuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define LEFTSTRIP 0
|
#define LEFTSTRIP 0
|
||||||
#define RIGHTSTRIP 1
|
#define RIGHTSTRIP 1
|
||||||
#define BOTHSTRIP 2
|
#define BOTHSTRIP 2
|
||||||
|
|
|
@ -3251,10 +3251,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
||||||
basebase = base->tp_base;
|
basebase = base->tp_base;
|
||||||
if (basebase->tp_as_buffer == NULL)
|
if (basebase->tp_as_buffer == NULL)
|
||||||
basebase = NULL;
|
basebase = NULL;
|
||||||
COPYBUF(bf_getreadbuffer);
|
COPYBUF(bf_getbuffer);
|
||||||
COPYBUF(bf_getwritebuffer);
|
COPYBUF(bf_releasebuffer);
|
||||||
COPYBUF(bf_getsegcount);
|
|
||||||
COPYBUF(bf_getcharbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
basebase = base->tp_base;
|
basebase = base->tp_base;
|
||||||
|
|
|
@ -8108,57 +8108,26 @@ static PyMappingMethods unicode_as_mapping = {
|
||||||
(objobjargproc)0, /* mp_ass_subscript */
|
(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
|
static int
|
||||||
unicode_buffer_getsegcount(PyUnicodeObject *self,
|
unicode_buffer_getbuffer(PyUnicodeObject *self, PyBuffer *view, int flags)
|
||||||
Py_ssize_t *lenp)
|
|
||||||
{
|
{
|
||||||
if (lenp)
|
|
||||||
*lenp = PyUnicode_GET_DATA_SIZE(self);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_ssize_t
|
if (flags & PyBUF_CHARACTER) {
|
||||||
unicode_buffer_getcharbuf(PyUnicodeObject *self,
|
PyObject *str;
|
||||||
Py_ssize_t index,
|
|
||||||
const void **ptr)
|
str = _PyUnicode_AsDefaultEncodedString((PyObject *)self, NULL);
|
||||||
{
|
if (str == NULL) return -1;
|
||||||
PyObject *str;
|
return PyBuffer_FillInfo(view, (void *)PyString_AS_STRING(str),
|
||||||
|
PyString_GET_SIZE(str), 1, flags);
|
||||||
if (index != 0) {
|
}
|
||||||
PyErr_SetString(PyExc_SystemError,
|
else {
|
||||||
"accessing non-existent unicode segment");
|
return PyBuffer_FillInfo(view, (void *)self->str,
|
||||||
return -1;
|
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() */
|
/* Helpers for PyUnicode_Format() */
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -8853,10 +8822,8 @@ PyObject *PyUnicode_Format(PyObject *format,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyBufferProcs unicode_as_buffer = {
|
static PyBufferProcs unicode_as_buffer = {
|
||||||
(readbufferproc) unicode_buffer_getreadbuf,
|
(getbufferproc) unicode_buffer_getbuffer,
|
||||||
(writebufferproc) unicode_buffer_getwritebuf,
|
NULL,
|
||||||
(segcountproc) unicode_buffer_getsegcount,
|
|
||||||
(charbufferproc) unicode_buffer_getcharbuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -1704,6 +1704,7 @@ _PyBuiltin_Init(void)
|
||||||
SETBUILTIN("basestring", &PyBaseString_Type);
|
SETBUILTIN("basestring", &PyBaseString_Type);
|
||||||
SETBUILTIN("bool", &PyBool_Type);
|
SETBUILTIN("bool", &PyBool_Type);
|
||||||
SETBUILTIN("buffer", &PyBuffer_Type);
|
SETBUILTIN("buffer", &PyBuffer_Type);
|
||||||
|
SETBUILTIN("memoryview", &PyMemoryView_Type);
|
||||||
SETBUILTIN("bytes", &PyBytes_Type);
|
SETBUILTIN("bytes", &PyBytes_Type);
|
||||||
SETBUILTIN("classmethod", &PyClassMethod_Type);
|
SETBUILTIN("classmethod", &PyClassMethod_Type);
|
||||||
#ifndef WITHOUT_COMPLEX
|
#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 **);
|
void **p = va_arg(*p_va, void **);
|
||||||
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
|
||||||
int count;
|
int count;
|
||||||
|
int temp=-1;
|
||||||
|
PyBuffer view;
|
||||||
|
|
||||||
if (pb == NULL ||
|
if (pb == NULL ||
|
||||||
pb->bf_getwritebuffer == NULL ||
|
pb->bf_getbuffer == NULL ||
|
||||||
pb->bf_getsegcount == NULL)
|
((temp = (*pb->bf_getbuffer)(arg, &view,
|
||||||
return converterr("read-write buffer", arg, msgbuf, bufsize);
|
PyBUF_SIMPLE)) != 0) ||
|
||||||
if ((*pb->bf_getsegcount)(arg, NULL) != 1)
|
view.readonly == 1) {
|
||||||
|
if (temp==0 && pb->bf_releasebuffer != NULL) {
|
||||||
|
(*pb->bf_releasebuffer)(arg, &view);
|
||||||
|
}
|
||||||
return converterr("single-segment read-write buffer",
|
return converterr("single-segment read-write buffer",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0)
|
}
|
||||||
|
|
||||||
|
if ((count = view.len) < 0)
|
||||||
return converterr("(unspecified)", arg, msgbuf, bufsize);
|
return converterr("(unspecified)", arg, msgbuf, bufsize);
|
||||||
|
*p = view.buf;
|
||||||
if (*format == '#') {
|
if (*format == '#') {
|
||||||
FETCH_SIZE;
|
FETCH_SIZE;
|
||||||
STORE_SIZE(count);
|
STORE_SIZE(count);
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
|
if (pb->bf_releasebuffer != NULL)
|
||||||
|
(*pb->bf_releasebuffer)(arg, &view);
|
||||||
break;
|
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 **);
|
char **p = va_arg(*p_va, char **);
|
||||||
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
|
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
|
||||||
int count;
|
int count;
|
||||||
|
PyBuffer view;
|
||||||
|
|
||||||
if (*format++ != '#')
|
if (*format++ != '#')
|
||||||
return converterr(
|
return converterr(
|
||||||
"invalid use of 't' format character",
|
"invalid use of 't' format character",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
if (pb == NULL || pb->bf_getcharbuffer == NULL ||
|
if (pb == NULL || pb->bf_getbuffer == NULL)
|
||||||
pb->bf_getsegcount == NULL)
|
|
||||||
return converterr(
|
return converterr(
|
||||||
"string or read-only character buffer",
|
"string or read-only character buffer",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
|
|
||||||
if (pb->bf_getsegcount(arg, NULL) != 1)
|
if ((*pb->bf_getbuffer)(arg, &view, PyBUF_CHARACTER) != 0)
|
||||||
return converterr(
|
return converterr("string or single-segment read-only buffer",
|
||||||
"string or single-segment read-only buffer",
|
arg, msgbuf, bufsize);
|
||||||
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)
|
if (count < 0)
|
||||||
return converterr("(unspecified)", arg, msgbuf, bufsize);
|
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;
|
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
|
||||||
Py_ssize_t count;
|
Py_ssize_t count;
|
||||||
|
PyBuffer view;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
*p = NULL;
|
||||||
if (pb == NULL ||
|
if (pb == NULL ||
|
||||||
pb->bf_getreadbuffer == NULL ||
|
pb->bf_getbuffer == NULL) {
|
||||||
pb->bf_getsegcount == NULL) {
|
|
||||||
*errmsg = "string or read-only buffer";
|
*errmsg = "string or read-only buffer";
|
||||||
return -1;
|
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";
|
*errmsg = "string or single-segment read-only buffer";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) {
|
count = view.len;
|
||||||
*errmsg = "(unspecified)";
|
*p = view.buf;
|
||||||
}
|
if (pb->bf_releasebuffer != NULL)
|
||||||
|
(*pb->bf_releasebuffer)(arg, &view);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -358,12 +358,18 @@ w_object(PyObject *v, WFILE *p)
|
||||||
w_long(co->co_firstlineno, p);
|
w_long(co->co_firstlineno, p);
|
||||||
w_object(co->co_lnotab, 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 */
|
/* Write unknown buffer-style objects as a string */
|
||||||
char *s;
|
char *s;
|
||||||
PyBufferProcs *pb = v->ob_type->tp_as_buffer;
|
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);
|
w_byte(TYPE_STRING, p);
|
||||||
n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s);
|
n = view.len;
|
||||||
|
s = view.buf;
|
||||||
if (n > INT_MAX) {
|
if (n > INT_MAX) {
|
||||||
p->depth--;
|
p->depth--;
|
||||||
p->error = 1;
|
p->error = 1;
|
||||||
|
@ -371,6 +377,8 @@ w_object(PyObject *v, WFILE *p)
|
||||||
}
|
}
|
||||||
w_long((long)n, p);
|
w_long((long)n, p);
|
||||||
w_string(s, (int)n, p);
|
w_string(s, (int)n, p);
|
||||||
|
if (pb->bf_releasebuffer != NULL)
|
||||||
|
(*pb->bf_releasebuffer)(v, &view);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
w_byte(TYPE_UNKNOWN, p);
|
w_byte(TYPE_UNKNOWN, p);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue