Skip to content

Commit

Permalink
Blob: implement the memory buffer interface
Browse files Browse the repository at this point in the history
This allows us to expose access to the blob's data without the need to
copy it into new buffer.
  • Loading branch information
carlosmn committed Apr 23, 2014
1 parent d8bd6f7 commit 1c76d56
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
60 changes: 58 additions & 2 deletions src/blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,58 @@ PyGetSetDef Blob_getseters[] = {
{NULL}
};

static int
Blob_getbuffer(Blob *self, Py_buffer *view, int flags)
{
return PyBuffer_FillInfo(view, (PyObject *) self,
(void *) git_blob_rawcontent(self->blob),
git_blob_rawsize(self->blob), 1, flags);
}

#if PY_MAJOR_VERSION == 2

PyDoc_STRVAR(Blob__doc__, "Blob objects.");
static Py_ssize_t
Blob_getreadbuffer(Blob *self, Py_ssize_t index, const void **ptr)
{
if (index != 0) {
PyErr_SetString(PyExc_SystemError,
"accessing non-existent blob segment");
return -1;
}
*ptr = (void *) git_blob_rawcontent(self->blob);
return git_blob_rawsize(self->blob);
}

static Py_ssize_t
Blob_getsegcount(Blob *self, Py_ssize_t *lenp)
{
if (lenp)
*lenp = git_blob_rawsize(self->blob);

return 1;
}

static PyBufferProcs Blob_as_buffer = {
(readbufferproc)Blob_getreadbuffer,
NULL, /* bf_getwritebuffer */
(segcountproc)Blob_getsegcount,
NULL, /* charbufferproc */
(getbufferproc)Blob_getbuffer,
};

#else

static PyBufferProcs Blob_as_buffer = {
(getbufferproc)Blob_getbuffer,
};

#endif /* python 2 vs python 3 buffers */

PyDoc_STRVAR(Blob__doc__, "Blob object.\n"
"\n"
"Blobs implement the buffer interface, which means you can get access\n"
"to its data via `memoryview(blob)` without the need to create a copy."
);

PyTypeObject BlobType = {
PyVarObject_HEAD_INIT(NULL, 0)
Expand All @@ -180,8 +230,14 @@ PyTypeObject BlobType = {
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
&Blob_as_buffer, /* tp_as_buffer */
#if PY_MAJOR_VERSION == 2
Py_TPFLAGS_DEFAULT | /* tp_flags */
Py_TPFLAGS_HAVE_GETCHARBUFFER |
Py_TPFLAGS_HAVE_NEWBUFFER,
#else
Py_TPFLAGS_DEFAULT, /* tp_flags */
#endif
Blob__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
Expand Down
7 changes: 7 additions & 0 deletions test/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ def test_create_blob(self):
self.assertEqual(BLOB_NEW_CONTENT, blob.data)
self.assertEqual(len(BLOB_NEW_CONTENT), blob.size)
self.assertEqual(BLOB_NEW_CONTENT, blob.read_raw())
blob_buffer = memoryview(blob)
self.assertEqual(len(BLOB_NEW_CONTENT), len(blob_buffer))
self.assertEqual(BLOB_NEW_CONTENT, blob_buffer)
def set_content():
blob_buffer[:2] = b'hi'

self.assertRaises(TypeError, set_content)

def test_create_blob_fromworkdir(self):

Expand Down

0 comments on commit 1c76d56

Please sign in to comment.