minibuffer.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* Implementation of a C object with the 'buffer' or 'memoryview'
  2. * interface at C-level (as approriate for the version of Python we're
  3. * compiling for), but only a minimal but *consistent* part of the
  4. * 'buffer' interface at application level.
  5. */
  6. typedef struct {
  7. PyObject_HEAD
  8. char *mb_data;
  9. Py_ssize_t mb_size;
  10. PyObject *mb_keepalive;
  11. PyObject *mb_weakreflist; /* weakref support */
  12. } MiniBufferObj;
  13. static Py_ssize_t mb_length(MiniBufferObj *self)
  14. {
  15. return self->mb_size;
  16. }
  17. static PyObject *mb_item(MiniBufferObj *self, Py_ssize_t idx)
  18. {
  19. if (idx < 0 || idx >= self->mb_size ) {
  20. PyErr_SetString(PyExc_IndexError, "buffer index out of range");
  21. return NULL;
  22. }
  23. return PyBytes_FromStringAndSize(self->mb_data + idx, 1);
  24. }
  25. static PyObject *mb_slice(MiniBufferObj *self,
  26. Py_ssize_t left, Py_ssize_t right)
  27. {
  28. Py_ssize_t size = self->mb_size;
  29. if (left < 0) left = 0;
  30. if (right > size) right = size;
  31. if (left > right) left = right;
  32. return PyBytes_FromStringAndSize(self->mb_data + left, right - left);
  33. }
  34. static int mb_ass_item(MiniBufferObj *self, Py_ssize_t idx, PyObject *other)
  35. {
  36. if (idx < 0 || idx >= self->mb_size) {
  37. PyErr_SetString(PyExc_IndexError,
  38. "buffer assignment index out of range");
  39. return -1;
  40. }
  41. if (PyBytes_Check(other) && PyBytes_GET_SIZE(other) == 1) {
  42. self->mb_data[idx] = PyBytes_AS_STRING(other)[0];
  43. return 0;
  44. }
  45. else {
  46. PyErr_Format(PyExc_TypeError,
  47. "must assign a "STR_OR_BYTES
  48. " of length 1, not %.200s", Py_TYPE(other)->tp_name);
  49. return -1;
  50. }
  51. }
  52. static int mb_ass_slice(MiniBufferObj *self,
  53. Py_ssize_t left, Py_ssize_t right, PyObject *other)
  54. {
  55. const void *buffer;
  56. Py_ssize_t buffer_len, count;
  57. Py_ssize_t size = self->mb_size;
  58. if (PyObject_AsReadBuffer(other, &buffer, &buffer_len) < 0)
  59. return -1;
  60. if (left < 0) left = 0;
  61. if (right > size) right = size;
  62. if (left > right) left = right;
  63. count = right - left;
  64. if (count != buffer_len) {
  65. PyErr_SetString(PyExc_ValueError,
  66. "right operand length must match slice length");
  67. return -1;
  68. }
  69. memcpy(self->mb_data + left, buffer, count);
  70. return 0;
  71. }
  72. #if PY_MAJOR_VERSION < 3
  73. static Py_ssize_t mb_getdata(MiniBufferObj *self, Py_ssize_t idx, void **pp)
  74. {
  75. *pp = self->mb_data;
  76. return self->mb_size;
  77. }
  78. static Py_ssize_t mb_getsegcount(MiniBufferObj *self, Py_ssize_t *lenp)
  79. {
  80. if (lenp)
  81. *lenp = self->mb_size;
  82. return 1;
  83. }
  84. static PyObject *mb_str(MiniBufferObj *self)
  85. {
  86. /* Python 2: we want str(buffer) to behave like buffer[:], because
  87. that's what bytes(buffer) does on Python 3 and there is no way
  88. we can prevent this. */
  89. return PyString_FromStringAndSize(self->mb_data, self->mb_size);
  90. }
  91. #endif
  92. static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags)
  93. {
  94. return PyBuffer_FillInfo(view, (PyObject *)self,
  95. self->mb_data, self->mb_size,
  96. /*readonly=*/0, flags);
  97. }
  98. static PySequenceMethods mb_as_sequence = {
  99. (lenfunc)mb_length, /*sq_length*/
  100. (binaryfunc)0, /*sq_concat*/
  101. (ssizeargfunc)0, /*sq_repeat*/
  102. (ssizeargfunc)mb_item, /*sq_item*/
  103. (ssizessizeargfunc)mb_slice, /*sq_slice*/
  104. (ssizeobjargproc)mb_ass_item, /*sq_ass_item*/
  105. (ssizessizeobjargproc)mb_ass_slice, /*sq_ass_slice*/
  106. };
  107. static PyBufferProcs mb_as_buffer = {
  108. #if PY_MAJOR_VERSION < 3
  109. (readbufferproc)mb_getdata,
  110. (writebufferproc)mb_getdata,
  111. (segcountproc)mb_getsegcount,
  112. (charbufferproc)mb_getdata,
  113. #endif
  114. (getbufferproc)mb_getbuf,
  115. (releasebufferproc)0,
  116. };
  117. static void
  118. mb_dealloc(MiniBufferObj *ob)
  119. {
  120. PyObject_GC_UnTrack(ob);
  121. if (ob->mb_weakreflist != NULL)
  122. PyObject_ClearWeakRefs((PyObject *)ob);
  123. Py_XDECREF(ob->mb_keepalive);
  124. Py_TYPE(ob)->tp_free((PyObject *)ob);
  125. }
  126. static int
  127. mb_traverse(MiniBufferObj *ob, visitproc visit, void *arg)
  128. {
  129. Py_VISIT(ob->mb_keepalive);
  130. return 0;
  131. }
  132. static int
  133. mb_clear(MiniBufferObj *ob)
  134. {
  135. Py_CLEAR(ob->mb_keepalive);
  136. return 0;
  137. }
  138. #if PY_MAJOR_VERSION >= 3
  139. /* pfffffffffffff pages of copy-paste from listobject.c */
  140. static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item)
  141. {
  142. if (PyIndex_Check(item)) {
  143. Py_ssize_t i;
  144. i = PyNumber_AsSsize_t(item, PyExc_IndexError);
  145. if (i == -1 && PyErr_Occurred())
  146. return NULL;
  147. if (i < 0)
  148. i += self->mb_size;
  149. return mb_item(self, i);
  150. }
  151. else if (PySlice_Check(item)) {
  152. Py_ssize_t start, stop, step, slicelength;
  153. if (PySlice_GetIndicesEx(item, self->mb_size,
  154. &start, &stop, &step, &slicelength) < 0)
  155. return NULL;
  156. if (step == 1)
  157. return mb_slice(self, start, stop);
  158. else {
  159. PyErr_SetString(PyExc_TypeError,
  160. "buffer doesn't support slicing with step != 1");
  161. return NULL;
  162. }
  163. }
  164. else {
  165. PyErr_Format(PyExc_TypeError,
  166. "buffer indices must be integers, not %.200s",
  167. item->ob_type->tp_name);
  168. return NULL;
  169. }
  170. }
  171. static int
  172. mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value)
  173. {
  174. if (PyIndex_Check(item)) {
  175. Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
  176. if (i == -1 && PyErr_Occurred())
  177. return -1;
  178. if (i < 0)
  179. i += self->mb_size;
  180. return mb_ass_item(self, i, value);
  181. }
  182. else if (PySlice_Check(item)) {
  183. Py_ssize_t start, stop, step, slicelength;
  184. if (PySlice_GetIndicesEx(item, self->mb_size,
  185. &start, &stop, &step, &slicelength) < 0) {
  186. return -1;
  187. }
  188. if (step == 1)
  189. return mb_ass_slice(self, start, stop, value);
  190. else {
  191. PyErr_SetString(PyExc_TypeError,
  192. "buffer doesn't support slicing with step != 1");
  193. return -1;
  194. }
  195. }
  196. else {
  197. PyErr_Format(PyExc_TypeError,
  198. "buffer indices must be integers, not %.200s",
  199. item->ob_type->tp_name);
  200. return -1;
  201. }
  202. }
  203. static PyMappingMethods mb_as_mapping = {
  204. (lenfunc)mb_length, /*mp_length*/
  205. (binaryfunc)mb_subscript, /*mp_subscript*/
  206. (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/
  207. };
  208. #endif
  209. #if PY_MAJOR_VERSION >= 3
  210. # define MINIBUF_TPFLAGS 0
  211. #else
  212. # define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER)
  213. #endif
  214. static PyTypeObject MiniBuffer_Type = {
  215. PyVarObject_HEAD_INIT(NULL, 0)
  216. "_cffi_backend.buffer",
  217. sizeof(MiniBufferObj),
  218. 0,
  219. (destructor)mb_dealloc, /* tp_dealloc */
  220. 0, /* tp_print */
  221. 0, /* tp_getattr */
  222. 0, /* tp_setattr */
  223. 0, /* tp_compare */
  224. 0, /* tp_repr */
  225. 0, /* tp_as_number */
  226. &mb_as_sequence, /* tp_as_sequence */
  227. #if PY_MAJOR_VERSION < 3
  228. 0, /* tp_as_mapping */
  229. #else
  230. &mb_as_mapping, /* tp_as_mapping */
  231. #endif
  232. 0, /* tp_hash */
  233. 0, /* tp_call */
  234. #if PY_MAJOR_VERSION < 3
  235. (reprfunc)mb_str, /* tp_str */
  236. #else
  237. 0, /* tp_str */
  238. #endif
  239. PyObject_GenericGetAttr, /* tp_getattro */
  240. 0, /* tp_setattro */
  241. &mb_as_buffer, /* tp_as_buffer */
  242. (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
  243. MINIBUF_TPFLAGS), /* tp_flags */
  244. 0, /* tp_doc */
  245. (traverseproc)mb_traverse, /* tp_traverse */
  246. (inquiry)mb_clear, /* tp_clear */
  247. 0, /* tp_richcompare */
  248. offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */
  249. };
  250. static PyObject *minibuffer_new(char *data, Py_ssize_t size,
  251. PyObject *keepalive)
  252. {
  253. MiniBufferObj *ob = PyObject_GC_New(MiniBufferObj, &MiniBuffer_Type);
  254. if (ob != NULL) {
  255. ob->mb_data = data;
  256. ob->mb_size = size;
  257. ob->mb_keepalive = keepalive; Py_INCREF(keepalive);
  258. ob->mb_weakreflist = NULL;
  259. PyObject_GC_Track(ob);
  260. }
  261. return (PyObject *)ob;
  262. }