This commit was manufactured by cvs2svn to create tag 'r23a1-fork'.
[python/dscho.git] / Objects / bufferobject.c
blobc0e3c80da49b368dbaaf2e984cb9415f27ae2826
2 /* Buffer object implementation */
4 #include "Python.h"
7 typedef struct {
8 PyObject_HEAD
9 PyObject *b_base;
10 void *b_ptr;
11 int b_size;
12 int b_readonly;
13 long b_hash;
14 } PyBufferObject;
17 static PyObject *
18 _PyBuffer_FromMemory(PyObject *base, void *ptr, int size, int readonly)
20 PyBufferObject * b;
22 if ( size < 0 ) {
23 PyErr_SetString(PyExc_ValueError,
24 "size must be zero or positive");
25 return NULL;
28 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
29 if ( b == NULL )
30 return NULL;
32 Py_XINCREF(base);
33 b->b_base = base;
34 b->b_ptr = ptr;
35 b->b_size = size;
36 b->b_readonly = readonly;
37 b->b_hash = -1;
39 return (PyObject *) b;
42 static PyObject *
43 _PyBuffer_FromObject(PyObject *base, int offset, int size,
44 getreadbufferproc proc, int readonly)
46 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
47 void *p;
48 int count;
50 if ( offset < 0 ) {
51 PyErr_SetString(PyExc_ValueError,
52 "offset must be zero or positive");
53 return NULL;
56 if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
58 PyErr_SetString(PyExc_TypeError,
59 "single-segment buffer object expected");
60 return NULL;
62 if ( (count = (*proc)(base, 0, &p)) < 0 )
63 return NULL;
65 /* apply constraints to the start/end */
66 if ( size == Py_END_OF_BUFFER || size < 0 )
67 size = count;
68 if ( offset > count )
69 offset = count;
70 if ( offset + size > count )
71 size = count - offset;
73 /* if the base object is another buffer, then "deref" it,
74 * except if the base of the other buffer is NULL
76 if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) )
77 base = ((PyBufferObject *)base)->b_base;
79 return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
83 PyObject *
84 PyBuffer_FromObject(PyObject *base, int offset, int size)
86 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
88 if ( pb == NULL ||
89 pb->bf_getreadbuffer == NULL ||
90 pb->bf_getsegcount == NULL )
92 PyErr_SetString(PyExc_TypeError, "buffer object expected");
93 return NULL;
96 return _PyBuffer_FromObject(base, offset, size,
97 pb->bf_getreadbuffer, 1);
100 PyObject *
101 PyBuffer_FromReadWriteObject(PyObject *base, int offset, int size)
103 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
105 if ( pb == NULL ||
106 pb->bf_getwritebuffer == NULL ||
107 pb->bf_getsegcount == NULL )
109 PyErr_SetString(PyExc_TypeError, "buffer object expected");
110 return NULL;
113 return _PyBuffer_FromObject(base, offset, size,
114 (getreadbufferproc)pb->bf_getwritebuffer,
118 PyObject *
119 PyBuffer_FromMemory(void *ptr, int size)
121 return _PyBuffer_FromMemory(NULL, ptr, size, 1);
124 PyObject *
125 PyBuffer_FromReadWriteMemory(void *ptr, int size)
127 return _PyBuffer_FromMemory(NULL, ptr, size, 0);
130 PyObject *
131 PyBuffer_New(int size)
133 PyObject *o;
134 PyBufferObject * b;
136 if (size < 0) {
137 PyErr_SetString(PyExc_ValueError,
138 "size must be zero or positive");
139 return NULL;
141 /* Inline PyObject_New */
142 o = PyObject_MALLOC(sizeof(*b) + size);
143 if ( o == NULL )
144 return PyErr_NoMemory();
145 b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
147 b->b_base = NULL;
148 b->b_ptr = (void *)(b + 1);
149 b->b_size = size;
150 b->b_readonly = 0;
151 b->b_hash = -1;
153 return o;
156 /* Methods */
158 static PyObject *
159 buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
161 PyObject *ob;
162 int offset = 0;
163 int size = Py_END_OF_BUFFER;
165 if ( !PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size) )
166 return NULL;
167 return PyBuffer_FromObject(ob, offset, size);
170 PyDoc_STRVAR(buffer_doc,
171 "buffer(object [, offset[, size]])\n\
173 Create a new buffer object which references the given object.\n\
174 The buffer will reference a slice of the target object from the\n\
175 start of the object (or at the specified offset). The slice will\n\
176 extend to the end of the target object (or with the specified size).");
179 static void
180 buffer_dealloc(PyBufferObject *self)
182 Py_XDECREF(self->b_base);
183 PyObject_DEL(self);
186 static int
187 buffer_compare(PyBufferObject *self, PyBufferObject *other)
189 int len_self = self->b_size;
190 int len_other = other->b_size;
191 int min_len = (len_self < len_other) ? len_self : len_other;
192 int cmp;
193 if (min_len > 0) {
194 cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
195 if (cmp != 0)
196 return cmp;
198 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
201 static PyObject *
202 buffer_repr(PyBufferObject *self)
204 char *status = self->b_readonly ? "read-only" : "read-write";
206 if ( self->b_base == NULL )
207 return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>",
208 status,
209 self->b_ptr,
210 self->b_size,
211 self);
212 else
213 return PyString_FromFormat(
214 "<%s buffer for %p, ptr %p, size %d at %p>",
215 status,
216 self->b_base,
217 self->b_ptr,
218 self->b_size,
219 self);
222 static long
223 buffer_hash(PyBufferObject *self)
225 register int len;
226 register unsigned char *p;
227 register long x;
229 if ( self->b_hash != -1 )
230 return self->b_hash;
232 if ( !self->b_readonly )
234 /* ### use different wording, since this is conditional? */
235 PyErr_SetString(PyExc_TypeError, "unhashable type");
236 return -1;
239 len = self->b_size;
240 p = (unsigned char *) self->b_ptr;
241 x = *p << 7;
242 while (--len >= 0)
243 x = (1000003*x) ^ *p++;
244 x ^= self->b_size;
245 if (x == -1)
246 x = -2;
247 self->b_hash = x;
248 return x;
251 static PyObject *
252 buffer_str(PyBufferObject *self)
254 return PyString_FromStringAndSize(self->b_ptr, self->b_size);
257 /* Sequence methods */
259 static int
260 buffer_length(PyBufferObject *self)
262 return self->b_size;
265 static PyObject *
266 buffer_concat(PyBufferObject *self, PyObject *other)
268 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
269 char *p1;
270 void *p2;
271 PyObject *ob;
272 int count;
274 if ( pb == NULL ||
275 pb->bf_getreadbuffer == NULL ||
276 pb->bf_getsegcount == NULL )
278 PyErr_BadArgument();
279 return NULL;
281 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
283 /* ### use a different exception type/message? */
284 PyErr_SetString(PyExc_TypeError,
285 "single-segment buffer object expected");
286 return NULL;
289 /* optimize special case */
290 if ( self->b_size == 0 )
292 Py_INCREF(other);
293 return other;
296 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
297 return NULL;
299 ob = PyString_FromStringAndSize(NULL, self->b_size + count);
300 p1 = PyString_AS_STRING(ob);
301 memcpy(p1, self->b_ptr, self->b_size);
302 memcpy(p1 + self->b_size, p2, count);
304 /* there is an extra byte in the string object, so this is safe */
305 p1[self->b_size + count] = '\0';
307 return ob;
310 static PyObject *
311 buffer_repeat(PyBufferObject *self, int count)
313 PyObject *ob;
314 register char *p;
315 void *ptr = self->b_ptr;
316 int size = self->b_size;
318 if ( count < 0 )
319 count = 0;
320 ob = PyString_FromStringAndSize(NULL, size * count);
321 if ( ob == NULL )
322 return NULL;
324 p = PyString_AS_STRING(ob);
325 while ( count-- )
327 memcpy(p, ptr, size);
328 p += size;
331 /* there is an extra byte in the string object, so this is safe */
332 *p = '\0';
334 return ob;
337 static PyObject *
338 buffer_item(PyBufferObject *self, int idx)
340 if ( idx < 0 || idx >= self->b_size )
342 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
343 return NULL;
345 return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
348 static PyObject *
349 buffer_slice(PyBufferObject *self, int left, int right)
351 if ( left < 0 )
352 left = 0;
353 if ( right < 0 )
354 right = 0;
355 if ( right > self->b_size )
356 right = self->b_size;
357 if ( right < left )
358 right = left;
359 return PyString_FromStringAndSize((char *)self->b_ptr + left,
360 right - left);
363 static int
364 buffer_ass_item(PyBufferObject *self, int idx, PyObject *other)
366 PyBufferProcs *pb;
367 void *p;
368 int count;
370 if ( self->b_readonly ) {
371 PyErr_SetString(PyExc_TypeError,
372 "buffer is read-only");
373 return -1;
376 if (idx < 0 || idx >= self->b_size) {
377 PyErr_SetString(PyExc_IndexError,
378 "buffer assignment index out of range");
379 return -1;
382 pb = other ? other->ob_type->tp_as_buffer : NULL;
383 if ( pb == NULL ||
384 pb->bf_getreadbuffer == NULL ||
385 pb->bf_getsegcount == NULL )
387 PyErr_BadArgument();
388 return -1;
390 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
392 /* ### use a different exception type/message? */
393 PyErr_SetString(PyExc_TypeError,
394 "single-segment buffer object expected");
395 return -1;
398 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
399 return -1;
400 if ( count != 1 ) {
401 PyErr_SetString(PyExc_TypeError,
402 "right operand must be a single byte");
403 return -1;
406 ((char *)self->b_ptr)[idx] = *(char *)p;
407 return 0;
410 static int
411 buffer_ass_slice(PyBufferObject *self, int left, int right, PyObject *other)
413 PyBufferProcs *pb;
414 void *p;
415 int slice_len;
416 int count;
418 if ( self->b_readonly ) {
419 PyErr_SetString(PyExc_TypeError,
420 "buffer is read-only");
421 return -1;
424 pb = other ? other->ob_type->tp_as_buffer : NULL;
425 if ( pb == NULL ||
426 pb->bf_getreadbuffer == NULL ||
427 pb->bf_getsegcount == NULL )
429 PyErr_BadArgument();
430 return -1;
432 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
434 /* ### use a different exception type/message? */
435 PyErr_SetString(PyExc_TypeError,
436 "single-segment buffer object expected");
437 return -1;
439 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
440 return -1;
442 if ( left < 0 )
443 left = 0;
444 else if ( left > self->b_size )
445 left = self->b_size;
446 if ( right < left )
447 right = left;
448 else if ( right > self->b_size )
449 right = self->b_size;
450 slice_len = right - left;
452 if ( count != slice_len ) {
453 PyErr_SetString(
454 PyExc_TypeError,
455 "right operand length must match slice length");
456 return -1;
459 if ( slice_len )
460 memcpy((char *)self->b_ptr + left, p, slice_len);
462 return 0;
465 /* Buffer methods */
467 static int
468 buffer_getreadbuf(PyBufferObject *self, int idx, void **pp)
470 if ( idx != 0 ) {
471 PyErr_SetString(PyExc_SystemError,
472 "accessing non-existent buffer segment");
473 return -1;
475 *pp = self->b_ptr;
476 return self->b_size;
479 static int
480 buffer_getwritebuf(PyBufferObject *self, int idx, void **pp)
482 if ( self->b_readonly )
484 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
485 return -1;
487 return buffer_getreadbuf(self, idx, pp);
490 static int
491 buffer_getsegcount(PyBufferObject *self, int *lenp)
493 if ( lenp )
494 *lenp = self->b_size;
495 return 1;
498 static int
499 buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp)
501 if ( idx != 0 ) {
502 PyErr_SetString(PyExc_SystemError,
503 "accessing non-existent buffer segment");
504 return -1;
506 *pp = (const char *)self->b_ptr;
507 return self->b_size;
511 static PySequenceMethods buffer_as_sequence = {
512 (inquiry)buffer_length, /*sq_length*/
513 (binaryfunc)buffer_concat, /*sq_concat*/
514 (intargfunc)buffer_repeat, /*sq_repeat*/
515 (intargfunc)buffer_item, /*sq_item*/
516 (intintargfunc)buffer_slice, /*sq_slice*/
517 (intobjargproc)buffer_ass_item, /*sq_ass_item*/
518 (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
521 static PyBufferProcs buffer_as_buffer = {
522 (getreadbufferproc)buffer_getreadbuf,
523 (getwritebufferproc)buffer_getwritebuf,
524 (getsegcountproc)buffer_getsegcount,
525 (getcharbufferproc)buffer_getcharbuf,
528 PyTypeObject PyBuffer_Type = {
529 PyObject_HEAD_INIT(&PyType_Type)
531 "buffer",
532 sizeof(PyBufferObject),
534 (destructor)buffer_dealloc, /* tp_dealloc */
535 0, /* tp_print */
536 0, /* tp_getattr */
537 0, /* tp_setattr */
538 (cmpfunc)buffer_compare, /* tp_compare */
539 (reprfunc)buffer_repr, /* tp_repr */
540 0, /* tp_as_number */
541 &buffer_as_sequence, /* tp_as_sequence */
542 0, /* tp_as_mapping */
543 (hashfunc)buffer_hash, /* tp_hash */
544 0, /* tp_call */
545 (reprfunc)buffer_str, /* tp_str */
546 PyObject_GenericGetAttr, /* tp_getattro */
547 0, /* tp_setattro */
548 &buffer_as_buffer, /* tp_as_buffer */
549 Py_TPFLAGS_DEFAULT, /* tp_flags */
550 buffer_doc, /* tp_doc */
551 0, /* tp_traverse */
552 0, /* tp_clear */
553 0, /* tp_richcompare */
554 0, /* tp_weaklistoffset */
555 0, /* tp_iter */
556 0, /* tp_iternext */
557 0, /* tp_methods */
558 0, /* tp_members */
559 0, /* tp_getset */
560 0, /* tp_base */
561 0, /* tp_dict */
562 0, /* tp_descr_get */
563 0, /* tp_descr_set */
564 0, /* tp_dictoffset */
565 0, /* tp_init */
566 0, /* tp_alloc */
567 buffer_new, /* tp_new */