2 /* Buffer object implementation */
19 get_buf(PyBufferObject
*self
, void **ptr
, Py_ssize_t
*size
)
21 if (self
->b_base
== NULL
) {
27 Py_ssize_t count
, offset
;
29 PyBufferProcs
*bp
= self
->b_base
->ob_type
->tp_as_buffer
;
30 if ((*bp
->bf_getsegcount
)(self
->b_base
, NULL
) != 1) {
31 PyErr_SetString(PyExc_TypeError
,
32 "single-segment buffer object expected");
36 proc
= bp
->bf_getreadbuffer
;
38 proc
= (readbufferproc
)bp
->bf_getwritebuffer
;
39 if ((count
= (*proc
)(self
->b_base
, 0, ptr
)) < 0)
41 /* apply constraints to the start/end */
42 if (self
->b_offset
> count
)
45 offset
= self
->b_offset
;
46 *(char **)ptr
= *(char **)ptr
+ offset
;
47 if (self
->b_size
== Py_END_OF_BUFFER
)
51 if (offset
+ *size
> count
)
52 *size
= count
- offset
;
59 buffer_from_memory(PyObject
*base
, Py_ssize_t size
, Py_ssize_t offset
, void *ptr
,
64 if (size
< 0 && size
!= Py_END_OF_BUFFER
) {
65 PyErr_SetString(PyExc_ValueError
,
66 "size must be zero or positive");
70 PyErr_SetString(PyExc_ValueError
,
71 "offset must be zero or positive");
75 b
= PyObject_NEW(PyBufferObject
, &PyBuffer_Type
);
84 b
->b_readonly
= readonly
;
87 return (PyObject
*) b
;
91 buffer_from_object(PyObject
*base
, Py_ssize_t size
, Py_ssize_t offset
, int readonly
)
94 PyErr_SetString(PyExc_ValueError
,
95 "offset must be zero or positive");
98 if ( PyBuffer_Check(base
) && (((PyBufferObject
*)base
)->b_base
) ) {
99 /* another buffer, refer to the base object */
100 PyBufferObject
*b
= (PyBufferObject
*)base
;
101 if (b
->b_size
!= Py_END_OF_BUFFER
) {
102 Py_ssize_t base_size
= b
->b_size
- offset
;
105 if (size
== Py_END_OF_BUFFER
|| size
> base_size
)
108 offset
+= b
->b_offset
;
111 return buffer_from_memory(base
, size
, offset
, NULL
, readonly
);
116 PyBuffer_FromObject(PyObject
*base
, Py_ssize_t offset
, Py_ssize_t size
)
118 PyBufferProcs
*pb
= base
->ob_type
->tp_as_buffer
;
121 pb
->bf_getreadbuffer
== NULL
||
122 pb
->bf_getsegcount
== NULL
)
124 PyErr_SetString(PyExc_TypeError
, "buffer object expected");
128 return buffer_from_object(base
, size
, offset
, 1);
132 PyBuffer_FromReadWriteObject(PyObject
*base
, Py_ssize_t offset
, Py_ssize_t size
)
134 PyBufferProcs
*pb
= base
->ob_type
->tp_as_buffer
;
137 pb
->bf_getwritebuffer
== NULL
||
138 pb
->bf_getsegcount
== NULL
)
140 PyErr_SetString(PyExc_TypeError
, "buffer object expected");
144 return buffer_from_object(base
, size
, offset
, 0);
148 PyBuffer_FromMemory(void *ptr
, Py_ssize_t size
)
150 return buffer_from_memory(NULL
, size
, 0, ptr
, 1);
154 PyBuffer_FromReadWriteMemory(void *ptr
, Py_ssize_t size
)
156 return buffer_from_memory(NULL
, size
, 0, ptr
, 0);
160 PyBuffer_New(Py_ssize_t size
)
166 PyErr_SetString(PyExc_ValueError
,
167 "size must be zero or positive");
170 /* XXX: check for overflow in multiply */
171 /* Inline PyObject_New */
172 o
= (PyObject
*)PyObject_MALLOC(sizeof(*b
) + size
);
174 return PyErr_NoMemory();
175 b
= (PyBufferObject
*) PyObject_INIT(o
, &PyBuffer_Type
);
178 b
->b_ptr
= (void *)(b
+ 1);
190 buffer_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
193 Py_ssize_t offset
= 0;
194 Py_ssize_t size
= Py_END_OF_BUFFER
;
196 if (!_PyArg_NoKeywords("buffer()", kw
))
199 if (!PyArg_ParseTuple(args
, "O|nn:buffer", &ob
, &offset
, &size
))
201 return PyBuffer_FromObject(ob
, offset
, size
);
204 PyDoc_STRVAR(buffer_doc
,
205 "buffer(object [, offset[, size]])\n\
207 Create a new buffer object which references the given object.\n\
208 The buffer will reference a slice of the target object from the\n\
209 start of the object (or at the specified offset). The slice will\n\
210 extend to the end of the target object (or with the specified size).");
214 buffer_dealloc(PyBufferObject
*self
)
216 Py_XDECREF(self
->b_base
);
221 buffer_compare(PyBufferObject
*self
, PyBufferObject
*other
)
224 Py_ssize_t len_self
, len_other
, min_len
;
227 if (!get_buf(self
, &p1
, &len_self
))
229 if (!get_buf(other
, &p2
, &len_other
))
231 min_len
= (len_self
< len_other
) ? len_self
: len_other
;
233 cmp
= memcmp(p1
, p2
, min_len
);
237 return (len_self
< len_other
) ? -1 : (len_self
> len_other
) ? 1 : 0;
241 buffer_repr(PyBufferObject
*self
)
243 const char *status
= self
->b_readonly
? "read-only" : "read-write";
245 if ( self
->b_base
== NULL
)
246 return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>",
252 return PyString_FromFormat(
253 "<%s buffer for %p, size %zd, offset %zd at %p>",
262 buffer_hash(PyBufferObject
*self
)
266 register Py_ssize_t len
;
267 register unsigned char *p
;
270 if ( self
->b_hash
!= -1 )
273 /* XXX potential bugs here, a readonly buffer does not imply that the
274 * underlying memory is immutable. b_readonly is a necessary but not
275 * sufficient condition for a buffer to be hashable. Perhaps it would
276 * be better to only allow hashing if the underlying object is known to
277 * be immutable (e.g. PyString_Check() is true). Another idea would
278 * be to call tp_hash on the underlying object and see if it raises
280 if ( !self
->b_readonly
)
282 PyErr_SetString(PyExc_TypeError
,
283 "writable buffers are not hashable");
287 if (!get_buf(self
, &ptr
, &size
))
289 p
= (unsigned char *) ptr
;
293 x
= (1000003*x
) ^ *p
++;
302 buffer_str(PyBufferObject
*self
)
306 if (!get_buf(self
, &ptr
, &size
))
308 return PyString_FromStringAndSize((const char *)ptr
, size
);
311 /* Sequence methods */
314 buffer_length(PyBufferObject
*self
)
318 if (!get_buf(self
, &ptr
, &size
))
324 buffer_concat(PyBufferObject
*self
, PyObject
*other
)
326 PyBufferProcs
*pb
= other
->ob_type
->tp_as_buffer
;
330 Py_ssize_t size
, count
;
333 pb
->bf_getreadbuffer
== NULL
||
334 pb
->bf_getsegcount
== NULL
)
339 if ( (*pb
->bf_getsegcount
)(other
, NULL
) != 1 )
341 /* ### use a different exception type/message? */
342 PyErr_SetString(PyExc_TypeError
,
343 "single-segment buffer object expected");
347 if (!get_buf(self
, &ptr1
, &size
))
350 /* optimize special case */
357 if ( (count
= (*pb
->bf_getreadbuffer
)(other
, 0, &ptr2
)) < 0 )
360 ob
= PyString_FromStringAndSize(NULL
, size
+ count
);
363 p
= PyString_AS_STRING(ob
);
364 memcpy(p
, ptr1
, size
);
365 memcpy(p
+ size
, ptr2
, count
);
367 /* there is an extra byte in the string object, so this is safe */
368 p
[size
+ count
] = '\0';
374 buffer_repeat(PyBufferObject
*self
, Py_ssize_t count
)
383 if (!get_buf(self
, &ptr
, &size
))
385 ob
= PyString_FromStringAndSize(NULL
, size
* count
);
389 p
= PyString_AS_STRING(ob
);
392 memcpy(p
, ptr
, size
);
396 /* there is an extra byte in the string object, so this is safe */
403 buffer_item(PyBufferObject
*self
, Py_ssize_t idx
)
407 if (!get_buf(self
, &ptr
, &size
))
409 if ( idx
< 0 || idx
>= size
) {
410 PyErr_SetString(PyExc_IndexError
, "buffer index out of range");
413 return PyString_FromStringAndSize((char *)ptr
+ idx
, 1);
417 buffer_slice(PyBufferObject
*self
, Py_ssize_t left
, Py_ssize_t right
)
421 if (!get_buf(self
, &ptr
, &size
))
431 return PyString_FromStringAndSize((char *)ptr
+ left
,
436 buffer_ass_item(PyBufferObject
*self
, Py_ssize_t idx
, PyObject
*other
)
443 if ( self
->b_readonly
) {
444 PyErr_SetString(PyExc_TypeError
,
445 "buffer is read-only");
449 if (!get_buf(self
, &ptr1
, &size
))
452 if (idx
< 0 || idx
>= size
) {
453 PyErr_SetString(PyExc_IndexError
,
454 "buffer assignment index out of range");
458 pb
= other
? other
->ob_type
->tp_as_buffer
: NULL
;
460 pb
->bf_getreadbuffer
== NULL
||
461 pb
->bf_getsegcount
== NULL
)
466 if ( (*pb
->bf_getsegcount
)(other
, NULL
) != 1 )
468 /* ### use a different exception type/message? */
469 PyErr_SetString(PyExc_TypeError
,
470 "single-segment buffer object expected");
474 if ( (count
= (*pb
->bf_getreadbuffer
)(other
, 0, &ptr2
)) < 0 )
477 PyErr_SetString(PyExc_TypeError
,
478 "right operand must be a single byte");
482 ((char *)ptr1
)[idx
] = *(char *)ptr2
;
487 buffer_ass_slice(PyBufferObject
*self
, Py_ssize_t left
, Py_ssize_t right
, PyObject
*other
)
492 Py_ssize_t slice_len
;
495 if ( self
->b_readonly
) {
496 PyErr_SetString(PyExc_TypeError
,
497 "buffer is read-only");
501 pb
= other
? other
->ob_type
->tp_as_buffer
: NULL
;
503 pb
->bf_getreadbuffer
== NULL
||
504 pb
->bf_getsegcount
== NULL
)
509 if ( (*pb
->bf_getsegcount
)(other
, NULL
) != 1 )
511 /* ### use a different exception type/message? */
512 PyErr_SetString(PyExc_TypeError
,
513 "single-segment buffer object expected");
516 if (!get_buf(self
, &ptr1
, &size
))
518 if ( (count
= (*pb
->bf_getreadbuffer
)(other
, 0, &ptr2
)) < 0 )
523 else if ( left
> size
)
527 else if ( right
> size
)
529 slice_len
= right
- left
;
531 if ( count
!= slice_len
) {
534 "right operand length must match slice length");
539 memcpy((char *)ptr1
+ left
, ptr2
, slice_len
);
547 buffer_getreadbuf(PyBufferObject
*self
, Py_ssize_t idx
, void **pp
)
551 PyErr_SetString(PyExc_SystemError
,
552 "accessing non-existent buffer segment");
555 if (!get_buf(self
, pp
, &size
))
561 buffer_getwritebuf(PyBufferObject
*self
, Py_ssize_t idx
, void **pp
)
563 if ( self
->b_readonly
)
565 PyErr_SetString(PyExc_TypeError
, "buffer is read-only");
568 return buffer_getreadbuf(self
, idx
, pp
);
572 buffer_getsegcount(PyBufferObject
*self
, Py_ssize_t
*lenp
)
576 if (!get_buf(self
, &ptr
, &size
))
584 buffer_getcharbuf(PyBufferObject
*self
, Py_ssize_t idx
, const char **pp
)
589 PyErr_SetString(PyExc_SystemError
,
590 "accessing non-existent buffer segment");
593 if (!get_buf(self
, &ptr
, &size
))
595 *pp
= (const char *)ptr
;
600 static PySequenceMethods buffer_as_sequence
= {
601 (lenfunc
)buffer_length
, /*sq_length*/
602 (binaryfunc
)buffer_concat
, /*sq_concat*/
603 (ssizeargfunc
)buffer_repeat
, /*sq_repeat*/
604 (ssizeargfunc
)buffer_item
, /*sq_item*/
605 (ssizessizeargfunc
)buffer_slice
, /*sq_slice*/
606 (ssizeobjargproc
)buffer_ass_item
, /*sq_ass_item*/
607 (ssizessizeobjargproc
)buffer_ass_slice
, /*sq_ass_slice*/
610 static PyBufferProcs buffer_as_buffer
= {
611 (readbufferproc
)buffer_getreadbuf
,
612 (writebufferproc
)buffer_getwritebuf
,
613 (segcountproc
)buffer_getsegcount
,
614 (charbufferproc
)buffer_getcharbuf
,
617 PyTypeObject PyBuffer_Type
= {
618 PyObject_HEAD_INIT(&PyType_Type
)
621 sizeof(PyBufferObject
),
623 (destructor
)buffer_dealloc
, /* tp_dealloc */
627 (cmpfunc
)buffer_compare
, /* tp_compare */
628 (reprfunc
)buffer_repr
, /* tp_repr */
629 0, /* tp_as_number */
630 &buffer_as_sequence
, /* tp_as_sequence */
631 0, /* tp_as_mapping */
632 (hashfunc
)buffer_hash
, /* tp_hash */
634 (reprfunc
)buffer_str
, /* tp_str */
635 PyObject_GenericGetAttr
, /* tp_getattro */
637 &buffer_as_buffer
, /* tp_as_buffer */
638 Py_TPFLAGS_DEFAULT
, /* tp_flags */
639 buffer_doc
, /* tp_doc */
642 0, /* tp_richcompare */
643 0, /* tp_weaklistoffset */
651 0, /* tp_descr_get */
652 0, /* tp_descr_set */
653 0, /* tp_dictoffset */
656 buffer_new
, /* tp_new */