• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Test PEP 688 - Buffers */
2 
3 #include "parts.h"
4 
5 
6 #include <stddef.h>                 // offsetof
7 
8 typedef struct {
9     PyObject_HEAD
10     PyObject *obj;
11     Py_ssize_t references;
12 } testBufObject;
13 
14 static PyObject *
testbuf_new(PyTypeObject * type,PyObject * args,PyObject * kwds)15 testbuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
16 {
17     PyObject *obj = PyBytes_FromString("test");
18     if (obj == NULL) {
19         return NULL;
20     }
21     testBufObject *self = (testBufObject *)type->tp_alloc(type, 0);
22     if (self == NULL) {
23         Py_DECREF(obj);
24         return NULL;
25     }
26     self->obj = obj;
27     self->references = 0;
28     return (PyObject *)self;
29 }
30 
31 static int
testbuf_traverse(testBufObject * self,visitproc visit,void * arg)32 testbuf_traverse(testBufObject *self, visitproc visit, void *arg)
33 {
34     Py_VISIT(self->obj);
35     return 0;
36 }
37 
38 static int
testbuf_clear(testBufObject * self)39 testbuf_clear(testBufObject *self)
40 {
41     Py_CLEAR(self->obj);
42     return 0;
43 }
44 
45 static void
testbuf_dealloc(testBufObject * self)46 testbuf_dealloc(testBufObject *self)
47 {
48     PyObject_GC_UnTrack(self);
49     Py_XDECREF(self->obj);
50     Py_TYPE(self)->tp_free((PyObject *) self);
51 }
52 
53 static int
testbuf_getbuf(testBufObject * self,Py_buffer * view,int flags)54 testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags)
55 {
56     int buf = PyObject_GetBuffer(self->obj, view, flags);
57     if (buf == 0) {
58         Py_SETREF(view->obj, Py_NewRef(self));
59         self->references++;
60     }
61     return buf;
62 }
63 
64 static void
testbuf_releasebuf(testBufObject * self,Py_buffer * view)65 testbuf_releasebuf(testBufObject *self, Py_buffer *view)
66 {
67     self->references--;
68     assert(self->references >= 0);
69 }
70 
71 static PyBufferProcs testbuf_as_buffer = {
72     .bf_getbuffer = (getbufferproc) testbuf_getbuf,
73     .bf_releasebuffer = (releasebufferproc) testbuf_releasebuf,
74 };
75 
76 static struct PyMemberDef testbuf_members[] = {
77     {"references", Py_T_PYSSIZET, offsetof(testBufObject, references), Py_READONLY},
78     {NULL},
79 };
80 
81 static PyTypeObject testBufType = {
82     PyVarObject_HEAD_INIT(NULL, 0)
83     .tp_name = "testBufType",
84     .tp_basicsize = sizeof(testBufObject),
85     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
86     .tp_new = testbuf_new,
87     .tp_dealloc = (destructor) testbuf_dealloc,
88     .tp_traverse = (traverseproc) testbuf_traverse,
89     .tp_clear = (inquiry) testbuf_clear,
90     .tp_as_buffer = &testbuf_as_buffer,
91     .tp_members = testbuf_members
92 };
93 
94 int
_PyTestCapi_Init_Buffer(PyObject * m)95 _PyTestCapi_Init_Buffer(PyObject *m) {
96     if (PyType_Ready(&testBufType) < 0) {
97         return -1;
98     }
99     if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) {
100         return -1;
101     }
102 
103     return 0;
104 }
105