minibuffer.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. /* forward: from _cffi_backend.c */
  53. static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only);
  54. static int mb_ass_slice(MiniBufferObj *self,
  55. Py_ssize_t left, Py_ssize_t right, PyObject *other)
  56. {
  57. Py_ssize_t count;
  58. Py_ssize_t size = self->mb_size;
  59. Py_buffer src_view;
  60. if (_fetch_as_buffer(other, &src_view, 0) < 0)
  61. return -1;
  62. if (left < 0) left = 0;
  63. if (right > size) right = size;
  64. if (left > right) left = right;
  65. count = right - left;
  66. if (count != src_view.len) {
  67. PyBuffer_Release(&src_view);
  68. PyErr_SetString(PyExc_ValueError,
  69. "right operand length must match slice length");
  70. return -1;
  71. }
  72. memcpy(self->mb_data + left, src_view.buf, count);
  73. PyBuffer_Release(&src_view);
  74. return 0;
  75. }
  76. #if PY_MAJOR_VERSION < 3
  77. static Py_ssize_t mb_getdata(MiniBufferObj *self, Py_ssize_t idx, void **pp)
  78. {
  79. *pp = self->mb_data;
  80. return self->mb_size;
  81. }
  82. static Py_ssize_t mb_getsegcount(MiniBufferObj *self, Py_ssize_t *lenp)
  83. {
  84. if (lenp)
  85. *lenp = self->mb_size;
  86. return 1;
  87. }
  88. static PyObject *mb_str(MiniBufferObj *self)
  89. {
  90. /* Python 2: we want str(buffer) to behave like buffer[:], because
  91. that's what bytes(buffer) does on Python 3 and there is no way
  92. we can prevent this. */
  93. return PyString_FromStringAndSize(self->mb_data, self->mb_size);
  94. }
  95. #endif
  96. static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags)
  97. {
  98. return PyBuffer_FillInfo(view, (PyObject *)self,
  99. self->mb_data, self->mb_size,
  100. /*readonly=*/0, flags);
  101. }
  102. static PySequenceMethods mb_as_sequence = {
  103. (lenfunc)mb_length, /*sq_length*/
  104. (binaryfunc)0, /*sq_concat*/
  105. (ssizeargfunc)0, /*sq_repeat*/
  106. (ssizeargfunc)mb_item, /*sq_item*/
  107. (ssizessizeargfunc)mb_slice, /*sq_slice*/
  108. (ssizeobjargproc)mb_ass_item, /*sq_ass_item*/
  109. (ssizessizeobjargproc)mb_ass_slice, /*sq_ass_slice*/
  110. };
  111. static PyBufferProcs mb_as_buffer = {
  112. #if PY_MAJOR_VERSION < 3
  113. (readbufferproc)mb_getdata,
  114. (writebufferproc)mb_getdata,
  115. (segcountproc)mb_getsegcount,
  116. (charbufferproc)mb_getdata,
  117. #endif
  118. (getbufferproc)mb_getbuf,
  119. (releasebufferproc)0,
  120. };
  121. static void
  122. mb_dealloc(MiniBufferObj *ob)
  123. {
  124. PyObject_GC_UnTrack(ob);
  125. if (ob->mb_weakreflist != NULL)
  126. PyObject_ClearWeakRefs((PyObject *)ob);
  127. Py_XDECREF(ob->mb_keepalive);
  128. Py_TYPE(ob)->tp_free((PyObject *)ob);
  129. }
  130. static int
  131. mb_traverse(MiniBufferObj *ob, visitproc visit, void *arg)
  132. {
  133. Py_VISIT(ob->mb_keepalive);
  134. return 0;
  135. }
  136. static int
  137. mb_clear(MiniBufferObj *ob)
  138. {
  139. Py_CLEAR(ob->mb_keepalive);
  140. return 0;
  141. }
  142. static PyObject *
  143. mb_richcompare(PyObject *self, PyObject *other, int op)
  144. {
  145. Py_ssize_t self_size, other_size;
  146. Py_buffer self_bytes, other_bytes;
  147. PyObject *res;
  148. Py_ssize_t minsize;
  149. int cmp, rc;
  150. /* Bytes can be compared to anything that supports the (binary)
  151. buffer API. Except that a comparison with Unicode is always an
  152. error, even if the comparison is for equality. */
  153. rc = PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type);
  154. if (!rc)
  155. rc = PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type);
  156. if (rc < 0)
  157. return NULL;
  158. if (rc) {
  159. Py_INCREF(Py_NotImplemented);
  160. return Py_NotImplemented;
  161. }
  162. if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) {
  163. PyErr_Clear();
  164. Py_INCREF(Py_NotImplemented);
  165. return Py_NotImplemented;
  166. }
  167. self_size = self_bytes.len;
  168. if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) {
  169. PyErr_Clear();
  170. PyBuffer_Release(&self_bytes);
  171. Py_INCREF(Py_NotImplemented);
  172. return Py_NotImplemented;
  173. }
  174. other_size = other_bytes.len;
  175. if (self_size != other_size && (op == Py_EQ || op == Py_NE)) {
  176. /* Shortcut: if the lengths differ, the objects differ */
  177. cmp = (op == Py_NE);
  178. }
  179. else {
  180. minsize = self_size;
  181. if (other_size < minsize)
  182. minsize = other_size;
  183. cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize);
  184. /* In ISO C, memcmp() guarantees to use unsigned bytes! */
  185. if (cmp == 0) {
  186. if (self_size < other_size)
  187. cmp = -1;
  188. else if (self_size > other_size)
  189. cmp = 1;
  190. }
  191. switch (op) {
  192. case Py_LT: cmp = cmp < 0; break;
  193. case Py_LE: cmp = cmp <= 0; break;
  194. case Py_EQ: cmp = cmp == 0; break;
  195. case Py_NE: cmp = cmp != 0; break;
  196. case Py_GT: cmp = cmp > 0; break;
  197. case Py_GE: cmp = cmp >= 0; break;
  198. }
  199. }
  200. res = cmp ? Py_True : Py_False;
  201. PyBuffer_Release(&self_bytes);
  202. PyBuffer_Release(&other_bytes);
  203. Py_INCREF(res);
  204. return res;
  205. }
  206. #if PY_MAJOR_VERSION >= 3
  207. /* pfffffffffffff pages of copy-paste from listobject.c */
  208. /* pfffffffffffff#2: the PySlice_GetIndicesEx() *macro* should not
  209. be called, because C extension modules compiled with it differ
  210. on ABI between 3.6.0, 3.6.1 and 3.6.2. */
  211. #if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && !defined(PYPY_VERSION)
  212. #undef PySlice_GetIndicesEx
  213. #endif
  214. static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item)
  215. {
  216. if (PyIndex_Check(item)) {
  217. Py_ssize_t i;
  218. i = PyNumber_AsSsize_t(item, PyExc_IndexError);
  219. if (i == -1 && PyErr_Occurred())
  220. return NULL;
  221. if (i < 0)
  222. i += self->mb_size;
  223. return mb_item(self, i);
  224. }
  225. else if (PySlice_Check(item)) {
  226. Py_ssize_t start, stop, step, slicelength;
  227. if (PySlice_GetIndicesEx(item, self->mb_size,
  228. &start, &stop, &step, &slicelength) < 0)
  229. return NULL;
  230. if (step == 1)
  231. return mb_slice(self, start, stop);
  232. else {
  233. PyErr_SetString(PyExc_TypeError,
  234. "buffer doesn't support slicing with step != 1");
  235. return NULL;
  236. }
  237. }
  238. else {
  239. PyErr_Format(PyExc_TypeError,
  240. "buffer indices must be integers, not %.200s",
  241. item->ob_type->tp_name);
  242. return NULL;
  243. }
  244. }
  245. static int
  246. mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value)
  247. {
  248. if (PyIndex_Check(item)) {
  249. Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
  250. if (i == -1 && PyErr_Occurred())
  251. return -1;
  252. if (i < 0)
  253. i += self->mb_size;
  254. return mb_ass_item(self, i, value);
  255. }
  256. else if (PySlice_Check(item)) {
  257. Py_ssize_t start, stop, step, slicelength;
  258. if (PySlice_GetIndicesEx(item, self->mb_size,
  259. &start, &stop, &step, &slicelength) < 0) {
  260. return -1;
  261. }
  262. if (step == 1)
  263. return mb_ass_slice(self, start, stop, value);
  264. else {
  265. PyErr_SetString(PyExc_TypeError,
  266. "buffer doesn't support slicing with step != 1");
  267. return -1;
  268. }
  269. }
  270. else {
  271. PyErr_Format(PyExc_TypeError,
  272. "buffer indices must be integers, not %.200s",
  273. item->ob_type->tp_name);
  274. return -1;
  275. }
  276. }
  277. static PyMappingMethods mb_as_mapping = {
  278. (lenfunc)mb_length, /*mp_length*/
  279. (binaryfunc)mb_subscript, /*mp_subscript*/
  280. (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/
  281. };
  282. #endif
  283. #if PY_MAJOR_VERSION >= 3
  284. # define MINIBUF_TPFLAGS 0
  285. #else
  286. # define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER)
  287. #endif
  288. PyDoc_STRVAR(ffi_buffer_doc,
  289. "ffi.buffer(cdata[, byte_size]):\n"
  290. "Return a read-write buffer object that references the raw C data\n"
  291. "pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n"
  292. "array. Can be passed to functions expecting a buffer, or directly\n"
  293. "manipulated with:\n"
  294. "\n"
  295. " buf[:] get a copy of it in a regular string, or\n"
  296. " buf[idx] as a single character\n"
  297. " buf[:] = ...\n"
  298. " buf[idx] = ... change the content");
  299. static PyObject * /* forward, implemented in _cffi_backend.c */
  300. b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
  301. static PyTypeObject MiniBuffer_Type = {
  302. PyVarObject_HEAD_INIT(NULL, 0)
  303. "_cffi_backend.buffer",
  304. sizeof(MiniBufferObj),
  305. 0,
  306. (destructor)mb_dealloc, /* tp_dealloc */
  307. 0, /* tp_print */
  308. 0, /* tp_getattr */
  309. 0, /* tp_setattr */
  310. 0, /* tp_compare */
  311. 0, /* tp_repr */
  312. 0, /* tp_as_number */
  313. &mb_as_sequence, /* tp_as_sequence */
  314. #if PY_MAJOR_VERSION < 3
  315. 0, /* tp_as_mapping */
  316. #else
  317. &mb_as_mapping, /* tp_as_mapping */
  318. #endif
  319. 0, /* tp_hash */
  320. 0, /* tp_call */
  321. #if PY_MAJOR_VERSION < 3
  322. (reprfunc)mb_str, /* tp_str */
  323. #else
  324. 0, /* tp_str */
  325. #endif
  326. PyObject_GenericGetAttr, /* tp_getattro */
  327. 0, /* tp_setattro */
  328. &mb_as_buffer, /* tp_as_buffer */
  329. (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
  330. MINIBUF_TPFLAGS), /* tp_flags */
  331. ffi_buffer_doc, /* tp_doc */
  332. (traverseproc)mb_traverse, /* tp_traverse */
  333. (inquiry)mb_clear, /* tp_clear */
  334. (richcmpfunc)mb_richcompare, /* tp_richcompare */
  335. offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */
  336. 0, /* tp_iter */
  337. 0, /* tp_iternext */
  338. 0, /* tp_methods */
  339. 0, /* tp_members */
  340. 0, /* tp_getset */
  341. 0, /* tp_base */
  342. 0, /* tp_dict */
  343. 0, /* tp_descr_get */
  344. 0, /* tp_descr_set */
  345. 0, /* tp_dictoffset */
  346. 0, /* tp_init */
  347. 0, /* tp_alloc */
  348. b_buffer_new, /* tp_new */
  349. 0, /* tp_free */
  350. };
  351. static PyObject *minibuffer_new(char *data, Py_ssize_t size,
  352. PyObject *keepalive)
  353. {
  354. MiniBufferObj *ob = PyObject_GC_New(MiniBufferObj, &MiniBuffer_Type);
  355. if (ob != NULL) {
  356. ob->mb_data = data;
  357. ob->mb_size = size;
  358. ob->mb_keepalive = keepalive; Py_INCREF(keepalive);
  359. ob->mb_weakreflist = NULL;
  360. PyObject_GC_Track(ob);
  361. }
  362. return (PyObject *)ob;
  363. }