]>
Commit | Line | Data |
---|---|---|
53b2ba57 DM |
1 | \r |
2 | /* Memoryview object implementation */\r | |
3 | \r | |
4 | #include "Python.h"\r | |
5 | \r | |
6 | static Py_ssize_t\r | |
7 | get_shape0(Py_buffer *buf)\r | |
8 | {\r | |
9 | if (buf->shape != NULL)\r | |
10 | return buf->shape[0];\r | |
11 | if (buf->ndim == 0)\r | |
12 | return 1;\r | |
13 | PyErr_SetString(PyExc_TypeError,\r | |
14 | "exported buffer does not have any shape information associated "\r | |
15 | "to it");\r | |
16 | return -1;\r | |
17 | }\r | |
18 | \r | |
19 | static void\r | |
20 | dup_buffer(Py_buffer *dest, Py_buffer *src)\r | |
21 | {\r | |
22 | *dest = *src;\r | |
23 | if (src->ndim == 1 && src->shape != NULL) {\r | |
24 | dest->shape = &(dest->smalltable[0]);\r | |
25 | dest->shape[0] = get_shape0(src);\r | |
26 | }\r | |
27 | if (src->ndim == 1 && src->strides != NULL) {\r | |
28 | dest->strides = &(dest->smalltable[1]);\r | |
29 | dest->strides[0] = src->strides[0];\r | |
30 | }\r | |
31 | }\r | |
32 | \r | |
33 | static int\r | |
34 | memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)\r | |
35 | {\r | |
36 | int res = 0;\r | |
37 | if (self->view.obj != NULL)\r | |
38 | res = PyObject_GetBuffer(self->view.obj, view, flags);\r | |
39 | if (view)\r | |
40 | dup_buffer(view, &self->view);\r | |
41 | return res;\r | |
42 | }\r | |
43 | \r | |
44 | static void\r | |
45 | memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)\r | |
46 | {\r | |
47 | PyBuffer_Release(view);\r | |
48 | }\r | |
49 | \r | |
50 | PyDoc_STRVAR(memory_doc,\r | |
51 | "memoryview(object)\n\\r | |
52 | \n\\r | |
53 | Create a new memoryview object which references the given object.");\r | |
54 | \r | |
55 | PyObject *\r | |
56 | PyMemoryView_FromBuffer(Py_buffer *info)\r | |
57 | {\r | |
58 | PyMemoryViewObject *mview;\r | |
59 | \r | |
60 | mview = (PyMemoryViewObject *)\r | |
61 | PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);\r | |
62 | if (mview == NULL)\r | |
63 | return NULL;\r | |
64 | mview->base = NULL;\r | |
65 | dup_buffer(&mview->view, info);\r | |
66 | /* NOTE: mview->view.obj should already have been incref'ed as\r | |
67 | part of PyBuffer_FillInfo(). */\r | |
68 | _PyObject_GC_TRACK(mview);\r | |
69 | return (PyObject *)mview;\r | |
70 | }\r | |
71 | \r | |
72 | PyObject *\r | |
73 | PyMemoryView_FromObject(PyObject *base)\r | |
74 | {\r | |
75 | PyMemoryViewObject *mview;\r | |
76 | Py_buffer view;\r | |
77 | \r | |
78 | if (!PyObject_CheckBuffer(base)) {\r | |
79 | PyErr_SetString(PyExc_TypeError,\r | |
80 | "cannot make memory view because object does "\r | |
81 | "not have the buffer interface");\r | |
82 | return NULL;\r | |
83 | }\r | |
84 | \r | |
85 | if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)\r | |
86 | return NULL;\r | |
87 | \r | |
88 | mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);\r | |
89 | if (mview == NULL) {\r | |
90 | PyBuffer_Release(&view);\r | |
91 | return NULL;\r | |
92 | }\r | |
93 | \r | |
94 | mview->base = base;\r | |
95 | Py_INCREF(base);\r | |
96 | return (PyObject *)mview;\r | |
97 | }\r | |
98 | \r | |
99 | static PyObject *\r | |
100 | memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)\r | |
101 | {\r | |
102 | PyObject *obj;\r | |
103 | static char *kwlist[] = {"object", 0};\r | |
104 | \r | |
105 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,\r | |
106 | &obj)) {\r | |
107 | return NULL;\r | |
108 | }\r | |
109 | \r | |
110 | return PyMemoryView_FromObject(obj);\r | |
111 | }\r | |
112 | \r | |
113 | \r | |
114 | static void\r | |
115 | _strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,\r | |
116 | Py_ssize_t *strides, Py_ssize_t itemsize, char fort)\r | |
117 | {\r | |
118 | int k;\r | |
119 | Py_ssize_t outstride;\r | |
120 | \r | |
121 | if (nd==0) {\r | |
122 | memcpy(dest, src, itemsize);\r | |
123 | }\r | |
124 | else if (nd == 1) {\r | |
125 | for (k = 0; k<shape[0]; k++) {\r | |
126 | memcpy(dest, src, itemsize);\r | |
127 | dest += itemsize;\r | |
128 | src += strides[0];\r | |
129 | }\r | |
130 | }\r | |
131 | else {\r | |
132 | if (fort == 'F') {\r | |
133 | /* Copy first dimension first,\r | |
134 | second dimension second, etc...\r | |
135 | Set up the recursive loop backwards so that final\r | |
136 | dimension is actually copied last.\r | |
137 | */\r | |
138 | outstride = itemsize;\r | |
139 | for (k=1; k<nd-1;k++) {\r | |
140 | outstride *= shape[k];\r | |
141 | }\r | |
142 | for (k=0; k<shape[nd-1]; k++) {\r | |
143 | _strided_copy_nd(dest, src, nd-1, shape,\r | |
144 | strides, itemsize, fort);\r | |
145 | dest += outstride;\r | |
146 | src += strides[nd-1];\r | |
147 | }\r | |
148 | }\r | |
149 | \r | |
150 | else {\r | |
151 | /* Copy last dimension first,\r | |
152 | second-to-last dimension second, etc.\r | |
153 | Set up the recursion so that the\r | |
154 | first dimension is copied last\r | |
155 | */\r | |
156 | outstride = itemsize;\r | |
157 | for (k=1; k < nd; k++) {\r | |
158 | outstride *= shape[k];\r | |
159 | }\r | |
160 | for (k=0; k<shape[0]; k++) {\r | |
161 | _strided_copy_nd(dest, src, nd-1, shape+1,\r | |
162 | strides+1, itemsize,\r | |
163 | fort);\r | |
164 | dest += outstride;\r | |
165 | src += strides[0];\r | |
166 | }\r | |
167 | }\r | |
168 | }\r | |
169 | return;\r | |
170 | }\r | |
171 | \r | |
172 | static int\r | |
173 | _indirect_copy_nd(char *dest, Py_buffer *view, char fort)\r | |
174 | {\r | |
175 | Py_ssize_t *indices;\r | |
176 | int k;\r | |
177 | Py_ssize_t elements;\r | |
178 | char *ptr;\r | |
179 | void (*func)(int, Py_ssize_t *, const Py_ssize_t *);\r | |
180 | \r | |
181 | if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {\r | |
182 | PyErr_NoMemory();\r | |
183 | return -1;\r | |
184 | }\r | |
185 | \r | |
186 | indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);\r | |
187 | if (indices == NULL) {\r | |
188 | PyErr_NoMemory();\r | |
189 | return -1;\r | |
190 | }\r | |
191 | for (k=0; k<view->ndim;k++) {\r | |
192 | indices[k] = 0;\r | |
193 | }\r | |
194 | \r | |
195 | elements = 1;\r | |
196 | for (k=0; k<view->ndim; k++) {\r | |
197 | elements *= view->shape[k];\r | |
198 | }\r | |
199 | if (fort == 'F') {\r | |
200 | func = _Py_add_one_to_index_F;\r | |
201 | }\r | |
202 | else {\r | |
203 | func = _Py_add_one_to_index_C;\r | |
204 | }\r | |
205 | while (elements--) {\r | |
206 | func(view->ndim, indices, view->shape);\r | |
207 | ptr = PyBuffer_GetPointer(view, indices);\r | |
208 | memcpy(dest, ptr, view->itemsize);\r | |
209 | dest += view->itemsize;\r | |
210 | }\r | |
211 | \r | |
212 | PyMem_Free(indices);\r | |
213 | return 0;\r | |
214 | }\r | |
215 | \r | |
216 | /*\r | |
217 | Get a the data from an object as a contiguous chunk of memory (in\r | |
218 | either 'C' or 'F'ortran order) even if it means copying it into a\r | |
219 | separate memory area.\r | |
220 | \r | |
221 | Returns a new reference to a Memory view object. If no copy is needed,\r | |
222 | the memory view object points to the original memory and holds a\r | |
223 | lock on the original. If a copy is needed, then the memory view object\r | |
224 | points to a brand-new Bytes object (and holds a memory lock on it).\r | |
225 | \r | |
226 | buffertype\r | |
227 | \r | |
228 | PyBUF_READ buffer only needs to be read-only\r | |
229 | PyBUF_WRITE buffer needs to be writable (give error if not contiguous)\r | |
230 | PyBUF_SHADOW buffer needs to be writable so shadow it with\r | |
231 | a contiguous buffer if it is not. The view will point to\r | |
232 | the shadow buffer which can be written to and then\r | |
233 | will be copied back into the other buffer when the memory\r | |
234 | view is de-allocated. While the shadow buffer is\r | |
235 | being used, it will have an exclusive write lock on\r | |
236 | the original buffer.\r | |
237 | */\r | |
238 | \r | |
239 | PyObject *\r | |
240 | PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)\r | |
241 | {\r | |
242 | PyMemoryViewObject *mem;\r | |
243 | PyObject *bytes;\r | |
244 | Py_buffer *view;\r | |
245 | int flags;\r | |
246 | char *dest;\r | |
247 | \r | |
248 | if (!PyObject_CheckBuffer(obj)) {\r | |
249 | PyErr_SetString(PyExc_TypeError,\r | |
250 | "object does not have the buffer interface");\r | |
251 | return NULL;\r | |
252 | }\r | |
253 | \r | |
254 | mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);\r | |
255 | if (mem == NULL)\r | |
256 | return NULL;\r | |
257 | \r | |
258 | view = &mem->view;\r | |
259 | flags = PyBUF_FULL_RO;\r | |
260 | switch(buffertype) {\r | |
261 | case PyBUF_WRITE:\r | |
262 | flags = PyBUF_FULL;\r | |
263 | break;\r | |
264 | }\r | |
265 | \r | |
266 | if (PyObject_GetBuffer(obj, view, flags) != 0) {\r | |
267 | Py_DECREF(mem);\r | |
268 | return NULL;\r | |
269 | }\r | |
270 | \r | |
271 | if (PyBuffer_IsContiguous(view, fort)) {\r | |
272 | /* no copy needed */\r | |
273 | Py_INCREF(obj);\r | |
274 | mem->base = obj;\r | |
275 | _PyObject_GC_TRACK(mem);\r | |
276 | return (PyObject *)mem;\r | |
277 | }\r | |
278 | /* otherwise a copy is needed */\r | |
279 | if (buffertype == PyBUF_WRITE) {\r | |
280 | Py_DECREF(mem);\r | |
281 | PyErr_SetString(PyExc_BufferError,\r | |
282 | "writable contiguous buffer requested "\r | |
283 | "for a non-contiguousobject.");\r | |
284 | return NULL;\r | |
285 | }\r | |
286 | bytes = PyBytes_FromStringAndSize(NULL, view->len);\r | |
287 | if (bytes == NULL) {\r | |
288 | Py_DECREF(mem);\r | |
289 | return NULL;\r | |
290 | }\r | |
291 | dest = PyBytes_AS_STRING(bytes);\r | |
292 | /* different copying strategy depending on whether\r | |
293 | or not any pointer de-referencing is needed\r | |
294 | */\r | |
295 | /* strided or in-direct copy */\r | |
296 | if (view->suboffsets==NULL) {\r | |
297 | _strided_copy_nd(dest, view->buf, view->ndim, view->shape,\r | |
298 | view->strides, view->itemsize, fort);\r | |
299 | }\r | |
300 | else {\r | |
301 | if (_indirect_copy_nd(dest, view, fort) < 0) {\r | |
302 | Py_DECREF(bytes);\r | |
303 | Py_DECREF(mem);\r | |
304 | return NULL;\r | |
305 | }\r | |
306 | }\r | |
307 | if (buffertype == PyBUF_SHADOW) {\r | |
308 | /* return a shadowed memory-view object */\r | |
309 | view->buf = dest;\r | |
310 | mem->base = PyTuple_Pack(2, obj, bytes);\r | |
311 | Py_DECREF(bytes);\r | |
312 | if (mem->base == NULL) {\r | |
313 | Py_DECREF(mem);\r | |
314 | return NULL;\r | |
315 | }\r | |
316 | }\r | |
317 | else {\r | |
318 | PyBuffer_Release(view); /* XXX ? */\r | |
319 | /* steal the reference */\r | |
320 | mem->base = bytes;\r | |
321 | }\r | |
322 | _PyObject_GC_TRACK(mem);\r | |
323 | return (PyObject *)mem;\r | |
324 | }\r | |
325 | \r | |
326 | \r | |
327 | static PyObject *\r | |
328 | memory_format_get(PyMemoryViewObject *self)\r | |
329 | {\r | |
330 | return PyString_FromString(self->view.format);\r | |
331 | }\r | |
332 | \r | |
333 | static PyObject *\r | |
334 | memory_itemsize_get(PyMemoryViewObject *self)\r | |
335 | {\r | |
336 | return PyLong_FromSsize_t(self->view.itemsize);\r | |
337 | }\r | |
338 | \r | |
339 | static PyObject *\r | |
340 | _IntTupleFromSsizet(int len, Py_ssize_t *vals)\r | |
341 | {\r | |
342 | int i;\r | |
343 | PyObject *o;\r | |
344 | PyObject *intTuple;\r | |
345 | \r | |
346 | if (vals == NULL) {\r | |
347 | Py_INCREF(Py_None);\r | |
348 | return Py_None;\r | |
349 | }\r | |
350 | intTuple = PyTuple_New(len);\r | |
351 | if (!intTuple) return NULL;\r | |
352 | for(i=0; i<len; i++) {\r | |
353 | o = PyLong_FromSsize_t(vals[i]);\r | |
354 | if (!o) {\r | |
355 | Py_DECREF(intTuple);\r | |
356 | return NULL;\r | |
357 | }\r | |
358 | PyTuple_SET_ITEM(intTuple, i, o);\r | |
359 | }\r | |
360 | return intTuple;\r | |
361 | }\r | |
362 | \r | |
363 | static PyObject *\r | |
364 | memory_shape_get(PyMemoryViewObject *self)\r | |
365 | {\r | |
366 | return _IntTupleFromSsizet(self->view.ndim, self->view.shape);\r | |
367 | }\r | |
368 | \r | |
369 | static PyObject *\r | |
370 | memory_strides_get(PyMemoryViewObject *self)\r | |
371 | {\r | |
372 | return _IntTupleFromSsizet(self->view.ndim, self->view.strides);\r | |
373 | }\r | |
374 | \r | |
375 | static PyObject *\r | |
376 | memory_suboffsets_get(PyMemoryViewObject *self)\r | |
377 | {\r | |
378 | return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);\r | |
379 | }\r | |
380 | \r | |
381 | static PyObject *\r | |
382 | memory_readonly_get(PyMemoryViewObject *self)\r | |
383 | {\r | |
384 | return PyBool_FromLong(self->view.readonly);\r | |
385 | }\r | |
386 | \r | |
387 | static PyObject *\r | |
388 | memory_ndim_get(PyMemoryViewObject *self)\r | |
389 | {\r | |
390 | return PyLong_FromLong(self->view.ndim);\r | |
391 | }\r | |
392 | \r | |
393 | static PyGetSetDef memory_getsetlist[] ={\r | |
394 | {"format", (getter)memory_format_get, NULL, NULL},\r | |
395 | {"itemsize", (getter)memory_itemsize_get, NULL, NULL},\r | |
396 | {"shape", (getter)memory_shape_get, NULL, NULL},\r | |
397 | {"strides", (getter)memory_strides_get, NULL, NULL},\r | |
398 | {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},\r | |
399 | {"readonly", (getter)memory_readonly_get, NULL, NULL},\r | |
400 | {"ndim", (getter)memory_ndim_get, NULL, NULL},\r | |
401 | {NULL, NULL, NULL, NULL},\r | |
402 | };\r | |
403 | \r | |
404 | \r | |
405 | static PyObject *\r | |
406 | memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)\r | |
407 | {\r | |
408 | Py_buffer view;\r | |
409 | PyObject *res;\r | |
410 | \r | |
411 | if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_SIMPLE) < 0)\r | |
412 | return NULL;\r | |
413 | \r | |
414 | res = PyBytes_FromStringAndSize(NULL, view.len);\r | |
415 | PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');\r | |
416 | PyBuffer_Release(&view);\r | |
417 | return res;\r | |
418 | }\r | |
419 | \r | |
420 | /* TODO: rewrite this function using the struct module to unpack\r | |
421 | each buffer item */\r | |
422 | \r | |
423 | static PyObject *\r | |
424 | memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)\r | |
425 | {\r | |
426 | Py_buffer *view = &(mem->view);\r | |
427 | Py_ssize_t i;\r | |
428 | PyObject *res, *item;\r | |
429 | char *buf;\r | |
430 | \r | |
431 | if (strcmp(view->format, "B") || view->itemsize != 1) {\r | |
432 | PyErr_SetString(PyExc_NotImplementedError, \r | |
433 | "tolist() only supports byte views");\r | |
434 | return NULL;\r | |
435 | }\r | |
436 | if (view->ndim != 1) {\r | |
437 | PyErr_SetString(PyExc_NotImplementedError, \r | |
438 | "tolist() only supports one-dimensional objects");\r | |
439 | return NULL;\r | |
440 | }\r | |
441 | res = PyList_New(view->len);\r | |
442 | if (res == NULL)\r | |
443 | return NULL;\r | |
444 | buf = view->buf;\r | |
445 | for (i = 0; i < view->len; i++) {\r | |
446 | item = PyInt_FromLong((unsigned char) *buf);\r | |
447 | if (item == NULL) {\r | |
448 | Py_DECREF(res);\r | |
449 | return NULL;\r | |
450 | }\r | |
451 | PyList_SET_ITEM(res, i, item);\r | |
452 | buf++;\r | |
453 | }\r | |
454 | return res;\r | |
455 | }\r | |
456 | \r | |
457 | static PyMethodDef memory_methods[] = {\r | |
458 | {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},\r | |
459 | {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},\r | |
460 | {NULL, NULL} /* sentinel */\r | |
461 | };\r | |
462 | \r | |
463 | \r | |
464 | static void\r | |
465 | memory_dealloc(PyMemoryViewObject *self)\r | |
466 | {\r | |
467 | _PyObject_GC_UNTRACK(self);\r | |
468 | if (self->view.obj != NULL) {\r | |
469 | if (self->base && PyTuple_Check(self->base)) {\r | |
470 | /* Special case when first element is generic object\r | |
471 | with buffer interface and the second element is a\r | |
472 | contiguous "shadow" that must be copied back into\r | |
473 | the data areay of the first tuple element before\r | |
474 | releasing the buffer on the first element.\r | |
475 | */\r | |
476 | \r | |
477 | PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),\r | |
478 | PyTuple_GET_ITEM(self->base,1));\r | |
479 | \r | |
480 | /* The view member should have readonly == -1 in\r | |
481 | this instance indicating that the memory can\r | |
482 | be "locked" and was locked and will be unlocked\r | |
483 | again after this call.\r | |
484 | */\r | |
485 | PyBuffer_Release(&(self->view));\r | |
486 | }\r | |
487 | else {\r | |
488 | PyBuffer_Release(&(self->view));\r | |
489 | }\r | |
490 | Py_CLEAR(self->base);\r | |
491 | }\r | |
492 | PyObject_GC_Del(self);\r | |
493 | }\r | |
494 | \r | |
495 | static PyObject *\r | |
496 | memory_repr(PyMemoryViewObject *self)\r | |
497 | {\r | |
498 | return PyString_FromFormat("<memory at %p>", self);\r | |
499 | }\r | |
500 | \r | |
501 | /* Sequence methods */\r | |
502 | static Py_ssize_t\r | |
503 | memory_length(PyMemoryViewObject *self)\r | |
504 | {\r | |
505 | return get_shape0(&self->view);\r | |
506 | }\r | |
507 | \r | |
508 | /* Alternate version of memory_subcript that only accepts indices.\r | |
509 | Used by PySeqIter_New().\r | |
510 | */\r | |
511 | static PyObject *\r | |
512 | memory_item(PyMemoryViewObject *self, Py_ssize_t result)\r | |
513 | {\r | |
514 | Py_buffer *view = &(self->view);\r | |
515 | \r | |
516 | if (view->ndim == 0) {\r | |
517 | PyErr_SetString(PyExc_IndexError,\r | |
518 | "invalid indexing of 0-dim memory");\r | |
519 | return NULL;\r | |
520 | }\r | |
521 | if (view->ndim == 1) {\r | |
522 | /* Return a bytes object */\r | |
523 | char *ptr;\r | |
524 | ptr = (char *)view->buf;\r | |
525 | if (result < 0) {\r | |
526 | result += get_shape0(view);\r | |
527 | }\r | |
528 | if ((result < 0) || (result >= get_shape0(view))) {\r | |
529 | PyErr_SetString(PyExc_IndexError,\r | |
530 | "index out of bounds");\r | |
531 | return NULL;\r | |
532 | }\r | |
533 | if (view->strides == NULL)\r | |
534 | ptr += view->itemsize * result;\r | |
535 | else\r | |
536 | ptr += view->strides[0] * result;\r | |
537 | if (view->suboffsets != NULL &&\r | |
538 | view->suboffsets[0] >= 0) {\r | |
539 | ptr = *((char **)ptr) + view->suboffsets[0];\r | |
540 | }\r | |
541 | return PyBytes_FromStringAndSize(ptr, view->itemsize);\r | |
542 | } else {\r | |
543 | /* Return a new memory-view object */\r | |
544 | Py_buffer newview;\r | |
545 | memset(&newview, 0, sizeof(newview));\r | |
546 | /* XXX: This needs to be fixed so it actually returns a sub-view */\r | |
547 | return PyMemoryView_FromBuffer(&newview);\r | |
548 | }\r | |
549 | }\r | |
550 | \r | |
551 | /*\r | |
552 | mem[obj] returns a bytes object holding the data for one element if\r | |
553 | obj fully indexes the memory view or another memory-view object\r | |
554 | if it does not.\r | |
555 | \r | |
556 | 0-d memory-view objects can be referenced using ... or () but\r | |
557 | not with anything else.\r | |
558 | */\r | |
559 | static PyObject *\r | |
560 | memory_subscript(PyMemoryViewObject *self, PyObject *key)\r | |
561 | {\r | |
562 | Py_buffer *view;\r | |
563 | view = &(self->view);\r | |
564 | \r | |
565 | if (view->ndim == 0) {\r | |
566 | if (key == Py_Ellipsis ||\r | |
567 | (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {\r | |
568 | Py_INCREF(self);\r | |
569 | return (PyObject *)self;\r | |
570 | }\r | |
571 | else {\r | |
572 | PyErr_SetString(PyExc_IndexError,\r | |
573 | "invalid indexing of 0-dim memory");\r | |
574 | return NULL;\r | |
575 | }\r | |
576 | }\r | |
577 | if (PyIndex_Check(key)) {\r | |
578 | Py_ssize_t result;\r | |
579 | result = PyNumber_AsSsize_t(key, NULL);\r | |
580 | if (result == -1 && PyErr_Occurred())\r | |
581 | return NULL;\r | |
582 | return memory_item(self, result);\r | |
583 | }\r | |
584 | else if (PySlice_Check(key)) {\r | |
585 | Py_ssize_t start, stop, step, slicelength;\r | |
586 | \r | |
587 | if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),\r | |
588 | &start, &stop, &step, &slicelength) < 0) {\r | |
589 | return NULL;\r | |
590 | }\r | |
591 | \r | |
592 | if (step == 1 && view->ndim == 1) {\r | |
593 | Py_buffer newview;\r | |
594 | void *newbuf = (char *) view->buf\r | |
595 | + start * view->itemsize;\r | |
596 | int newflags = view->readonly\r | |
597 | ? PyBUF_CONTIG_RO : PyBUF_CONTIG;\r | |
598 | \r | |
599 | /* XXX There should be an API to create a subbuffer */\r | |
600 | if (view->obj != NULL) {\r | |
601 | if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)\r | |
602 | return NULL;\r | |
603 | }\r | |
604 | else {\r | |
605 | newview = *view;\r | |
606 | }\r | |
607 | newview.buf = newbuf;\r | |
608 | newview.len = slicelength * newview.itemsize;\r | |
609 | newview.format = view->format;\r | |
610 | newview.shape = &(newview.smalltable[0]);\r | |
611 | newview.shape[0] = slicelength;\r | |
612 | newview.strides = &(newview.itemsize);\r | |
613 | return PyMemoryView_FromBuffer(&newview);\r | |
614 | }\r | |
615 | PyErr_SetNone(PyExc_NotImplementedError);\r | |
616 | return NULL;\r | |
617 | }\r | |
618 | PyErr_Format(PyExc_TypeError,\r | |
619 | "cannot index memory using \"%.200s\"", \r | |
620 | key->ob_type->tp_name);\r | |
621 | return NULL;\r | |
622 | }\r | |
623 | \r | |
624 | \r | |
625 | /* Need to support assigning memory if we can */\r | |
626 | static int\r | |
627 | memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)\r | |
628 | {\r | |
629 | Py_ssize_t start, len, bytelen;\r | |
630 | Py_buffer srcview;\r | |
631 | Py_buffer *view = &(self->view);\r | |
632 | char *srcbuf, *destbuf;\r | |
633 | \r | |
634 | if (view->readonly) {\r | |
635 | PyErr_SetString(PyExc_TypeError,\r | |
636 | "cannot modify read-only memory");\r | |
637 | return -1;\r | |
638 | }\r | |
639 | if (value == NULL) {\r | |
640 | PyErr_SetString(PyExc_TypeError,\r | |
641 | "cannot delete memory");\r | |
642 | return -1;\r | |
643 | }\r | |
644 | if (view->ndim != 1) {\r | |
645 | PyErr_SetNone(PyExc_NotImplementedError);\r | |
646 | return -1;\r | |
647 | }\r | |
648 | if (PyIndex_Check(key)) {\r | |
649 | start = PyNumber_AsSsize_t(key, NULL);\r | |
650 | if (start == -1 && PyErr_Occurred())\r | |
651 | return -1;\r | |
652 | if (start < 0) {\r | |
653 | start += get_shape0(view);\r | |
654 | }\r | |
655 | if ((start < 0) || (start >= get_shape0(view))) {\r | |
656 | PyErr_SetString(PyExc_IndexError,\r | |
657 | "index out of bounds");\r | |
658 | return -1;\r | |
659 | }\r | |
660 | len = 1;\r | |
661 | }\r | |
662 | else if (PySlice_Check(key)) {\r | |
663 | Py_ssize_t stop, step;\r | |
664 | \r | |
665 | if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),\r | |
666 | &start, &stop, &step, &len) < 0) {\r | |
667 | return -1;\r | |
668 | }\r | |
669 | if (step != 1) {\r | |
670 | PyErr_SetNone(PyExc_NotImplementedError);\r | |
671 | return -1;\r | |
672 | }\r | |
673 | }\r | |
674 | else {\r | |
675 | PyErr_Format(PyExc_TypeError,\r | |
676 | "cannot index memory using \"%.200s\"", \r | |
677 | key->ob_type->tp_name);\r | |
678 | return -1;\r | |
679 | }\r | |
680 | if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {\r | |
681 | return -1;\r | |
682 | }\r | |
683 | /* XXX should we allow assignment of different item sizes\r | |
684 | as long as the byte length is the same?\r | |
685 | (e.g. assign 2 shorts to a 4-byte slice) */\r | |
686 | if (srcview.itemsize != view->itemsize) {\r | |
687 | PyErr_Format(PyExc_TypeError,\r | |
688 | "mismatching item sizes for \"%.200s\" and \"%.200s\"", \r | |
689 | view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);\r | |
690 | goto _error;\r | |
691 | }\r | |
692 | bytelen = len * view->itemsize;\r | |
693 | if (bytelen != srcview.len) {\r | |
694 | PyErr_SetString(PyExc_ValueError,\r | |
695 | "cannot modify size of memoryview object");\r | |
696 | goto _error;\r | |
697 | }\r | |
698 | /* Do the actual copy */\r | |
699 | destbuf = (char *) view->buf + start * view->itemsize;\r | |
700 | srcbuf = (char *) srcview.buf;\r | |
701 | if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)\r | |
702 | /* No overlapping */\r | |
703 | memcpy(destbuf, srcbuf, bytelen);\r | |
704 | else\r | |
705 | memmove(destbuf, srcbuf, bytelen);\r | |
706 | \r | |
707 | PyBuffer_Release(&srcview);\r | |
708 | return 0;\r | |
709 | \r | |
710 | _error:\r | |
711 | PyBuffer_Release(&srcview);\r | |
712 | return -1;\r | |
713 | }\r | |
714 | \r | |
715 | static PyObject *\r | |
716 | memory_richcompare(PyObject *v, PyObject *w, int op)\r | |
717 | {\r | |
718 | Py_buffer vv, ww;\r | |
719 | int equal = 0;\r | |
720 | PyObject *res;\r | |
721 | \r | |
722 | vv.obj = NULL;\r | |
723 | ww.obj = NULL;\r | |
724 | if (op != Py_EQ && op != Py_NE)\r | |
725 | goto _notimpl;\r | |
726 | if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {\r | |
727 | PyErr_Clear();\r | |
728 | goto _notimpl;\r | |
729 | }\r | |
730 | if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {\r | |
731 | PyErr_Clear();\r | |
732 | goto _notimpl;\r | |
733 | }\r | |
734 | \r | |
735 | if (vv.itemsize != ww.itemsize || vv.len != ww.len)\r | |
736 | goto _end;\r | |
737 | \r | |
738 | equal = !memcmp(vv.buf, ww.buf, vv.len);\r | |
739 | \r | |
740 | _end:\r | |
741 | PyBuffer_Release(&vv);\r | |
742 | PyBuffer_Release(&ww);\r | |
743 | if ((equal && op == Py_EQ) || (!equal && op == Py_NE))\r | |
744 | res = Py_True;\r | |
745 | else\r | |
746 | res = Py_False;\r | |
747 | Py_INCREF(res);\r | |
748 | return res;\r | |
749 | \r | |
750 | _notimpl:\r | |
751 | PyBuffer_Release(&vv);\r | |
752 | PyBuffer_Release(&ww);\r | |
753 | Py_INCREF(Py_NotImplemented);\r | |
754 | return Py_NotImplemented;\r | |
755 | }\r | |
756 | \r | |
757 | \r | |
758 | static int\r | |
759 | memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)\r | |
760 | {\r | |
761 | if (self->base != NULL)\r | |
762 | Py_VISIT(self->base);\r | |
763 | if (self->view.obj != NULL)\r | |
764 | Py_VISIT(self->view.obj);\r | |
765 | return 0;\r | |
766 | }\r | |
767 | \r | |
768 | static int\r | |
769 | memory_clear(PyMemoryViewObject *self)\r | |
770 | {\r | |
771 | Py_CLEAR(self->base);\r | |
772 | PyBuffer_Release(&self->view);\r | |
773 | return 0;\r | |
774 | }\r | |
775 | \r | |
776 | \r | |
777 | /* As mapping */\r | |
778 | static PyMappingMethods memory_as_mapping = {\r | |
779 | (lenfunc)memory_length, /* mp_length */\r | |
780 | (binaryfunc)memory_subscript, /* mp_subscript */\r | |
781 | (objobjargproc)memory_ass_sub, /* mp_ass_subscript */\r | |
782 | };\r | |
783 | \r | |
784 | static PySequenceMethods memory_as_sequence = {\r | |
785 | 0, /* sq_length */\r | |
786 | 0, /* sq_concat */\r | |
787 | 0, /* sq_repeat */\r | |
788 | (ssizeargfunc)memory_item, /* sq_item */\r | |
789 | };\r | |
790 | \r | |
791 | /* Buffer methods */\r | |
792 | static PyBufferProcs memory_as_buffer = {\r | |
793 | 0, /* bf_getreadbuffer */\r | |
794 | 0, /* bf_getwritebuffer */\r | |
795 | 0, /* bf_getsegcount */\r | |
796 | 0, /* bf_getcharbuffer */\r | |
797 | (getbufferproc)memory_getbuf, /* bf_getbuffer */\r | |
798 | (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */\r | |
799 | };\r | |
800 | \r | |
801 | \r | |
802 | PyTypeObject PyMemoryView_Type = {\r | |
803 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
804 | "memoryview",\r | |
805 | sizeof(PyMemoryViewObject),\r | |
806 | 0,\r | |
807 | (destructor)memory_dealloc, /* tp_dealloc */\r | |
808 | 0, /* tp_print */\r | |
809 | 0, /* tp_getattr */\r | |
810 | 0, /* tp_setattr */\r | |
811 | 0, /* tp_compare */\r | |
812 | (reprfunc)memory_repr, /* tp_repr */\r | |
813 | 0, /* tp_as_number */\r | |
814 | &memory_as_sequence, /* tp_as_sequence */\r | |
815 | &memory_as_mapping, /* tp_as_mapping */\r | |
816 | 0, /* tp_hash */\r | |
817 | 0, /* tp_call */\r | |
818 | 0, /* tp_str */\r | |
819 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
820 | 0, /* tp_setattro */\r | |
821 | &memory_as_buffer, /* tp_as_buffer */\r | |
822 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |\r | |
823 | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */\r | |
824 | memory_doc, /* tp_doc */\r | |
825 | (traverseproc)memory_traverse, /* tp_traverse */\r | |
826 | (inquiry)memory_clear, /* tp_clear */\r | |
827 | memory_richcompare, /* tp_richcompare */\r | |
828 | 0, /* tp_weaklistoffset */\r | |
829 | 0, /* tp_iter */\r | |
830 | 0, /* tp_iternext */\r | |
831 | memory_methods, /* tp_methods */\r | |
832 | 0, /* tp_members */\r | |
833 | memory_getsetlist, /* tp_getset */\r | |
834 | 0, /* tp_base */\r | |
835 | 0, /* tp_dict */\r | |
836 | 0, /* tp_descr_get */\r | |
837 | 0, /* tp_descr_set */\r | |
838 | 0, /* tp_dictoffset */\r | |
839 | 0, /* tp_init */\r | |
840 | 0, /* tp_alloc */\r | |
841 | memory_new, /* tp_new */\r | |
842 | };\r |