cpython/Objects/bufferobject.c

569 lines
12 KiB
C
Raw Normal View History

1998-10-07 11:36:10 -03:00
/* Buffer object implementation */
#include "Python.h"
typedef struct {
PyObject_HEAD
PyObject *b_base;
void *b_ptr;
int b_size;
int b_readonly;
long b_hash;
} PyBufferObject;
static PyObject *
2000-07-09 01:06:11 -03:00
_PyBuffer_FromMemory(PyObject *base, void *ptr, int size, int readonly)
1998-10-07 11:36:10 -03:00
{
PyBufferObject * b;
if ( size < 0 ) {
PyErr_SetString(PyExc_ValueError,
"size must be zero or positive");
return NULL;
}
1998-10-07 11:36:10 -03:00
b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
if ( b == NULL )
return NULL;
Py_XINCREF(base);
b->b_base = base;
b->b_ptr = ptr;
b->b_size = size;
b->b_readonly = readonly;
b->b_hash = -1;
return (PyObject *) b;
}
static PyObject *
2000-07-09 01:06:11 -03:00
_PyBuffer_FromObject(PyObject *base, int offset, int size,
getreadbufferproc proc, int readonly)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
void *p;
int count;
if ( offset < 0 ) {
PyErr_SetString(PyExc_ValueError,
"offset must be zero or positive");
return NULL;
}
1998-10-07 11:36:10 -03:00
if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
{
1999-03-24 15:05:31 -04:00
PyErr_SetString(PyExc_TypeError,
"single-segment buffer object expected");
1998-10-07 11:36:10 -03:00
return NULL;
}
if ( (count = (*proc)(base, 0, &p)) < 0 )
return NULL;
/* apply constraints to the start/end */
if ( size == Py_END_OF_BUFFER || size < 0 )
1998-10-07 11:36:10 -03:00
size = count;
if ( offset > count )
offset = count;
if ( offset + size > count )
size = count - offset;
/* if the base object is another buffer, then "deref" it,
* except if the base of the other buffer is NULL
*/
if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) )
1998-10-07 11:36:10 -03:00
base = ((PyBufferObject *)base)->b_base;
1998-10-07 11:36:10 -03:00
return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
}
PyObject *
2000-07-09 01:06:11 -03:00
PyBuffer_FromObject(PyObject *base, int offset, int size)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
if ( pb == NULL ||
pb->bf_getreadbuffer == NULL ||
pb->bf_getsegcount == NULL )
{
PyErr_SetString(PyExc_TypeError, "buffer object expected");
return NULL;
}
1999-03-24 15:05:31 -04:00
return _PyBuffer_FromObject(base, offset, size,
pb->bf_getreadbuffer, 1);
1998-10-07 11:36:10 -03:00
}
PyObject *
2000-07-09 01:06:11 -03:00
PyBuffer_FromReadWriteObject(PyObject *base, int offset, int size)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb = base->ob_type->tp_as_buffer;
if ( pb == NULL ||
pb->bf_getwritebuffer == NULL ||
pb->bf_getsegcount == NULL )
{
PyErr_SetString(PyExc_TypeError, "buffer object expected");
return NULL;
}
1999-03-24 15:05:31 -04:00
return _PyBuffer_FromObject(base, offset, size,
(getreadbufferproc)pb->bf_getwritebuffer,
0);
1998-10-07 11:36:10 -03:00
}
PyObject *
2000-07-09 01:06:11 -03:00
PyBuffer_FromMemory(void *ptr, int size)
1998-10-07 11:36:10 -03:00
{
return _PyBuffer_FromMemory(NULL, ptr, size, 1);
}
PyObject *
2000-07-09 01:06:11 -03:00
PyBuffer_FromReadWriteMemory(void *ptr, int size)
1998-10-07 11:36:10 -03:00
{
return _PyBuffer_FromMemory(NULL, ptr, size, 0);
}
PyObject *
2000-07-09 01:06:11 -03:00
PyBuffer_New(int size)
1998-10-07 11:36:10 -03:00
{
2000-08-04 12:36:13 -03:00
PyObject *o;
1998-10-07 11:36:10 -03:00
PyBufferObject * b;
if (size < 0) {
PyErr_SetString(PyExc_ValueError,
"size must be zero or positive");
return NULL;
}
/* PyObject_New is inlined */
2000-08-04 12:36:13 -03:00
o = PyObject_MALLOC(sizeof(*b) + size);
if ( o == NULL )
return PyErr_NoMemory();
2000-08-04 12:36:13 -03:00
b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
1998-10-07 11:36:10 -03:00
b->b_base = NULL;
b->b_ptr = (void *)(b + 1);
b->b_size = size;
b->b_readonly = 0;
b->b_hash = -1;
2000-08-04 12:36:13 -03:00
return o;
1998-10-07 11:36:10 -03:00
}
/* Methods */
static PyObject *
buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *ob;
int offset = 0;
int size = Py_END_OF_BUFFER;
if ( !PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size) )
return NULL;
return PyBuffer_FromObject(ob, offset, size);
}
PyDoc_STRVAR(buffer_doc,
"buffer(object [, offset[, size]])\n\
\n\
Create a new buffer object which references the given object.\n\
The buffer will reference a slice of the target object from the\n\
start of the object (or at the specified offset). The slice will\n\
extend to the end of the target object (or with the specified size).");
1998-10-07 11:36:10 -03:00
static void
2000-07-09 01:06:11 -03:00
buffer_dealloc(PyBufferObject *self)
1998-10-07 11:36:10 -03:00
{
Py_XDECREF(self->b_base);
PyObject_DEL(self);
1998-10-07 11:36:10 -03:00
}
static int
2000-07-09 01:06:11 -03:00
buffer_compare(PyBufferObject *self, PyBufferObject *other)
1998-10-07 11:36:10 -03:00
{
int len_self = self->b_size;
int len_other = other->b_size;
int min_len = (len_self < len_other) ? len_self : len_other;
int cmp;
if (min_len > 0) {
cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
if (cmp != 0)
return cmp;
}
return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_repr(PyBufferObject *self)
1998-10-07 11:36:10 -03:00
{
char *status = self->b_readonly ? "read-only" : "read-write";
if ( self->b_base == NULL )
return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>",
status,
self->b_ptr,
self->b_size,
self);
1998-10-07 11:36:10 -03:00
else
return PyString_FromFormat(
"<%s buffer for %p, ptr %p, size %d at %p>",
1998-10-07 11:36:10 -03:00
status,
self->b_base,
self->b_ptr,
1998-10-07 11:36:10 -03:00
self->b_size,
self);
1998-10-07 11:36:10 -03:00
}
static long
2000-07-09 01:06:11 -03:00
buffer_hash(PyBufferObject *self)
1998-10-07 11:36:10 -03:00
{
register int len;
register unsigned char *p;
register long x;
if ( self->b_hash != -1 )
return self->b_hash;
if ( !self->b_readonly )
{
/* ### use different wording, since this is conditional? */
PyErr_SetString(PyExc_TypeError, "unhashable type");
return -1;
}
len = self->b_size;
p = (unsigned char *) self->b_ptr;
x = *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= self->b_size;
if (x == -1)
x = -2;
self->b_hash = x;
return x;
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_str(PyBufferObject *self)
1998-10-07 11:36:10 -03:00
{
return PyString_FromStringAndSize(self->b_ptr, self->b_size);
}
/* Sequence methods */
static int
2000-07-09 01:06:11 -03:00
buffer_length(PyBufferObject *self)
1998-10-07 11:36:10 -03:00
{
return self->b_size;
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_concat(PyBufferObject *self, PyObject *other)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb = other->ob_type->tp_as_buffer;
char *p1;
void *p2;
PyObject *ob;
int count;
if ( pb == NULL ||
pb->bf_getreadbuffer == NULL ||
pb->bf_getsegcount == NULL )
{
PyErr_BadArgument();
return NULL;
}
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
{
/* ### use a different exception type/message? */
1999-03-24 15:05:31 -04:00
PyErr_SetString(PyExc_TypeError,
"single-segment buffer object expected");
1998-10-07 11:36:10 -03:00
return NULL;
}
/* optimize special case */
if ( self->b_size == 0 )
{
Py_INCREF(other);
return other;
}
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
return NULL;
ob = PyString_FromStringAndSize(NULL, self->b_size + count);
p1 = PyString_AS_STRING(ob);
memcpy(p1, self->b_ptr, self->b_size);
memcpy(p1 + self->b_size, p2, count);
/* there is an extra byte in the string object, so this is safe */
p1[self->b_size + count] = '\0';
return ob;
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_repeat(PyBufferObject *self, int count)
1998-10-07 11:36:10 -03:00
{
PyObject *ob;
register char *p;
void *ptr = self->b_ptr;
int size = self->b_size;
if ( count < 0 )
count = 0;
ob = PyString_FromStringAndSize(NULL, size * count);
if ( ob == NULL )
return NULL;
p = PyString_AS_STRING(ob);
while ( count-- )
{
memcpy(p, ptr, size);
p += size;
}
/* there is an extra byte in the string object, so this is safe */
*p = '\0';
return ob;
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_item(PyBufferObject *self, int idx)
1998-10-07 11:36:10 -03:00
{
if ( idx < 0 || idx >= self->b_size )
{
PyErr_SetString(PyExc_IndexError, "buffer index out of range");
return NULL;
}
return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
}
static PyObject *
2000-07-09 01:06:11 -03:00
buffer_slice(PyBufferObject *self, int left, int right)
1998-10-07 11:36:10 -03:00
{
if ( left < 0 )
left = 0;
if ( right < 0 )
right = 0;
if ( right > self->b_size )
right = self->b_size;
if ( right < left )
right = left;
1999-03-24 15:05:31 -04:00
return PyString_FromStringAndSize((char *)self->b_ptr + left,
right - left);
1998-10-07 11:36:10 -03:00
}
static int
2000-07-09 01:06:11 -03:00
buffer_ass_item(PyBufferObject *self, int idx, PyObject *other)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb;
void *p;
int count;
if ( self->b_readonly ) {
PyErr_SetString(PyExc_TypeError,
"buffer is read-only");
return -1;
}
if (idx < 0 || idx >= self->b_size) {
PyErr_SetString(PyExc_IndexError,
"buffer assignment index out of range");
return -1;
}
pb = other ? other->ob_type->tp_as_buffer : NULL;
if ( pb == NULL ||
pb->bf_getreadbuffer == NULL ||
pb->bf_getsegcount == NULL )
{
PyErr_BadArgument();
return -1;
}
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
{
/* ### use a different exception type/message? */
1999-03-24 15:05:31 -04:00
PyErr_SetString(PyExc_TypeError,
"single-segment buffer object expected");
1998-10-07 11:36:10 -03:00
return -1;
}
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
return -1;
if ( count != 1 ) {
PyErr_SetString(PyExc_TypeError,
"right operand must be a single byte");
return -1;
}
((char *)self->b_ptr)[idx] = *(char *)p;
return 0;
}
static int
2000-07-09 01:06:11 -03:00
buffer_ass_slice(PyBufferObject *self, int left, int right, PyObject *other)
1998-10-07 11:36:10 -03:00
{
PyBufferProcs *pb;
void *p;
int slice_len;
int count;
if ( self->b_readonly ) {
PyErr_SetString(PyExc_TypeError,
"buffer is read-only");
return -1;
}
pb = other ? other->ob_type->tp_as_buffer : NULL;
if ( pb == NULL ||
pb->bf_getreadbuffer == NULL ||
pb->bf_getsegcount == NULL )
{
PyErr_BadArgument();
return -1;
}
if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
{
/* ### use a different exception type/message? */
1999-03-24 15:05:31 -04:00
PyErr_SetString(PyExc_TypeError,
"single-segment buffer object expected");
1998-10-07 11:36:10 -03:00
return -1;
}
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
return -1;
if ( left < 0 )
left = 0;
else if ( left > self->b_size )
left = self->b_size;
if ( right < left )
right = left;
else if ( right > self->b_size )
right = self->b_size;
slice_len = right - left;
if ( count != slice_len ) {
1999-03-24 15:05:31 -04:00
PyErr_SetString(
PyExc_TypeError,
"right operand length must match slice length");
1998-10-07 11:36:10 -03:00
return -1;
}
if ( slice_len )
memcpy((char *)self->b_ptr + left, p, slice_len);
return 0;
}
/* Buffer methods */
static int
2000-07-09 01:06:11 -03:00
buffer_getreadbuf(PyBufferObject *self, int idx, void **pp)
1998-10-07 11:36:10 -03:00
{
if ( idx != 0 ) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent buffer segment");
1998-10-07 11:36:10 -03:00
return -1;
}
*pp = self->b_ptr;
return self->b_size;
}
static int
2000-07-09 01:06:11 -03:00
buffer_getwritebuf(PyBufferObject *self, int idx, void **pp)
1998-10-07 11:36:10 -03:00
{
if ( self->b_readonly )
{
PyErr_SetString(PyExc_TypeError, "buffer is read-only");
return -1;
}
return buffer_getreadbuf(self, idx, pp);
}
static int
2000-07-09 01:06:11 -03:00
buffer_getsegcount(PyBufferObject *self, int *lenp)
1998-10-07 11:36:10 -03:00
{
if ( lenp )
*lenp = self->b_size;
return 1;
}
static int
2000-07-09 01:06:11 -03:00
buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp)
{
if ( idx != 0 ) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent buffer segment");
return -1;
}
*pp = (const char *)self->b_ptr;
return self->b_size;
}
1998-10-07 11:36:10 -03:00
static PySequenceMethods buffer_as_sequence = {
(inquiry)buffer_length, /*sq_length*/
(binaryfunc)buffer_concat, /*sq_concat*/
(intargfunc)buffer_repeat, /*sq_repeat*/
(intargfunc)buffer_item, /*sq_item*/
(intintargfunc)buffer_slice, /*sq_slice*/
(intobjargproc)buffer_ass_item, /*sq_ass_item*/
(intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
};
static PyBufferProcs buffer_as_buffer = {
(getreadbufferproc)buffer_getreadbuf,
(getwritebufferproc)buffer_getwritebuf,
(getsegcountproc)buffer_getsegcount,
(getcharbufferproc)buffer_getcharbuf,
1998-10-07 11:36:10 -03:00
};
PyTypeObject PyBuffer_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"buffer",
sizeof(PyBufferObject),
0,
2001-08-02 01:15:00 -03:00
(destructor)buffer_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)buffer_compare, /* tp_compare */
(reprfunc)buffer_repr, /* tp_repr */
0, /* tp_as_number */
&buffer_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)buffer_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)buffer_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&buffer_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
buffer_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* 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 */
buffer_new, /* tp_new */
1998-10-07 11:36:10 -03:00
};