Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(5)

Delta Between Two Patch Sets: Objects/memoryobject.c

Issue 15573: Support unknown formats in memoryview comparisons
Left Patch Set: Created 7 years, 7 months ago
Right Patch Set: Created 7 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_buffer.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* Memoryview object implementation */ 1 /* Memoryview object implementation */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 #include <stddef.h> 4 #include <stddef.h>
5 5
6 6
7 /****************************************************************************/ 7 /****************************************************************************/
8 /* ManagedBuffer Object */ 8 /* ManagedBuffer Object */
9 /****************************************************************************/ 9 /****************************************************************************/
10 10
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 #define XSTRINGIZE(v) #v 51 #define XSTRINGIZE(v) #v
52 #define STRINGIZE(v) XSTRINGIZE(v) 52 #define STRINGIZE(v) XSTRINGIZE(v)
53 53
54 #define CHECK_MBUF_RELEASED(mbuf) \ 54 #define CHECK_MBUF_RELEASED(mbuf) \
55 if (((_PyManagedBufferObject *)mbuf)->flags&_Py_MANAGED_BUFFER_RELEASED) { \ 55 if (((_PyManagedBufferObject *)mbuf)->flags&_Py_MANAGED_BUFFER_RELEASED) { \
56 PyErr_SetString(PyExc_ValueError, \ 56 PyErr_SetString(PyExc_ValueError, \
57 "operation forbidden on released memoryview object"); \ 57 "operation forbidden on released memoryview object"); \
58 return NULL; \ 58 return NULL; \
59 } 59 }
60 60
61 static PyObject * _IntTupleFromSsizet(int len, Py_ssize_t *vals);
62 61
63 Py_LOCAL_INLINE(_PyManagedBufferObject *) 62 Py_LOCAL_INLINE(_PyManagedBufferObject *)
64 mbuf_alloc(void) 63 mbuf_alloc(void)
65 { 64 {
66 _PyManagedBufferObject *mbuf; 65 _PyManagedBufferObject *mbuf;
67 66
68 mbuf = (_PyManagedBufferObject *) 67 mbuf = (_PyManagedBufferObject *)
69 PyObject_GC_New(_PyManagedBufferObject, &_PyManagedBuffer_Type); 68 PyObject_GC_New(_PyManagedBufferObject, &_PyManagedBuffer_Type);
70 if (mbuf == NULL) 69 if (mbuf == NULL)
71 return NULL; 70 return NULL;
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 NOTE: All buffers are assumed to have PyBUF_FULL information, which 239 NOTE: All buffers are assumed to have PyBUF_FULL information, which
241 is the case for memoryviews! */ 240 is the case for memoryviews! */
242 241
243 242
244 /* Assumptions: ndim >= 1. The macro tests for a corner case that should 243 /* Assumptions: ndim >= 1. The macro tests for a corner case that should
245 perhaps be explicitly forbidden in the PEP. */ 244 perhaps be explicitly forbidden in the PEP. */
246 #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \ 245 #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \
247 (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0) 246 (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0)
248 247
249 Py_LOCAL_INLINE(int) 248 Py_LOCAL_INLINE(int)
250 last_dim_is_contiguous(Py_buffer *dest, Py_buffer *src) 249 last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src)
251 { 250 {
252 assert(dest->ndim > 0 && src->ndim > 0); 251 assert(dest->ndim > 0 && src->ndim > 0);
253 return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) && 252 return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) &&
254 !HAVE_SUBOFFSETS_IN_LAST_DIM(src) && 253 !HAVE_SUBOFFSETS_IN_LAST_DIM(src) &&
255 dest->strides[dest->ndim-1] == dest->itemsize && 254 dest->strides[dest->ndim-1] == dest->itemsize &&
256 src->strides[src->ndim-1] == src->itemsize); 255 src->strides[src->ndim-1] == src->itemsize);
257 } 256 }
258 257
258 /* This is not a general function for determining format equivalence.
259 It is used in copy_single() and copy_buffer() to weed out non-matching
260 formats. Skipping the '@' character is specifically used in slice
261 assignments, where the lvalue is already known to have a single character
262 format. This is a performance hack that could be rewritten (if properly
263 benchmarked). */
264 Py_LOCAL_INLINE(int)
265 equiv_format(const Py_buffer *dest, const Py_buffer *src)
266 {
267 const char *dfmt, *sfmt;
268
269 assert(dest->format && src->format);
270 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
271 sfmt = src->format[0] == '@' ? src->format+1 : src->format;
272
273 if (strcmp(dfmt, sfmt) != 0 ||
274 dest->itemsize != src->itemsize) {
275 return 0;
276 }
277
278 return 1;
279 }
280
281 /* Two shapes are equivalent if they are either equal or identical up
282 to a zero element at the same position. For example, in NumPy arrays
283 the shapes [1, 0, 5] and [1, 0, 7] are equivalent. */
284 Py_LOCAL_INLINE(int)
285 equiv_shape(const Py_buffer *dest, const Py_buffer *src)
286 {
287 int i;
288
289 if (dest->ndim != src->ndim)
290 return 0;
291
292 for (i = 0; i < dest->ndim; i++) {
293 if (dest->shape[i] != src->shape[i])
294 return 0;
295 if (dest->shape[i] == 0)
296 break;
297 }
298
299 return 1;
300 }
301
259 /* Check that the logical structure of the destination and source buffers 302 /* Check that the logical structure of the destination and source buffers
260 is identical. */ 303 is identical. */
261 static int 304 static int
262 cmp_structure(Py_buffer *dest, Py_buffer *src) 305 equiv_structure(const Py_buffer *dest, const Py_buffer *src)
263 { 306 {
264 const char *dfmt, *sfmt; 307 if (!equiv_format(dest, src) ||
265 int i; 308 !equiv_shape(dest, src)) {
266 309 PyErr_SetString(PyExc_ValueError,
267 assert(dest->format && src->format); 310 "ndarray assignment: lvalue and rvalue have different structures");
268 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format; 311 return 0;
269 sfmt = src->format[0] == '@' ? src->format+1 : src->format; 312 }
270 313
271 if (strcmp(dfmt, sfmt) != 0 || 314 return 1;
272 dest->itemsize != src->itemsize ||
273 dest->ndim != src->ndim) {
274 goto value_error;
275 }
276
277 for (i = 0; i < dest->ndim; i++) {
278 if (dest->shape[i] != src->shape[i])
279 goto value_error;
280 if (dest->shape[i] == 0)
281 break;
282 }
283
284 return 0;
285
286 value_error:
287 PyErr_SetString(PyExc_ValueError,
288 "ndarray assignment: lvalue and rvalue have different structures");
289 return -1;
290 } 315 }
291 316
292 /* Base case for recursive multi-dimensional copying. Contiguous arrays are 317 /* Base case for recursive multi-dimensional copying. Contiguous arrays are
293 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or 318 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or
294 sizeof(mem) == shape[0] * itemsize. */ 319 sizeof(mem) == shape[0] * itemsize. */
295 static void 320 static void
296 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize, 321 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize,
297 char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets, 322 char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
298 char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets, 323 char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
299 char *mem) 324 char *mem)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 } 377 }
353 378
354 /* Faster copying of one-dimensional arrays. */ 379 /* Faster copying of one-dimensional arrays. */
355 static int 380 static int
356 copy_single(Py_buffer *dest, Py_buffer *src) 381 copy_single(Py_buffer *dest, Py_buffer *src)
357 { 382 {
358 char *mem = NULL; 383 char *mem = NULL;
359 384
360 assert(dest->ndim == 1); 385 assert(dest->ndim == 1);
361 386
362 if (cmp_structure(dest, src) < 0) 387 if (!equiv_structure(dest, src))
363 return -1; 388 return -1;
364 389
365 if (!last_dim_is_contiguous(dest, src)) { 390 if (!last_dim_is_contiguous(dest, src)) {
366 mem = PyMem_Malloc(dest->shape[0] * dest->itemsize); 391 mem = PyMem_Malloc(dest->shape[0] * dest->itemsize);
367 if (mem == NULL) { 392 if (mem == NULL) {
368 PyErr_NoMemory(); 393 PyErr_NoMemory();
369 return -1; 394 return -1;
370 } 395 }
371 } 396 }
372 397
(...skipping 11 matching lines...) Expand all
384 /* Recursively copy src to dest. Both buffers must have the same basic 409 /* Recursively copy src to dest. Both buffers must have the same basic
385 structure. Copying is atomic, the function never fails with a partial 410 structure. Copying is atomic, the function never fails with a partial
386 copy. */ 411 copy. */
387 static int 412 static int
388 copy_buffer(Py_buffer *dest, Py_buffer *src) 413 copy_buffer(Py_buffer *dest, Py_buffer *src)
389 { 414 {
390 char *mem = NULL; 415 char *mem = NULL;
391 416
392 assert(dest->ndim > 0); 417 assert(dest->ndim > 0);
393 418
394 if (cmp_structure(dest, src) < 0) 419 if (!equiv_structure(dest, src))
395 return -1; 420 return -1;
396 421
397 if (!last_dim_is_contiguous(dest, src)) { 422 if (!last_dim_is_contiguous(dest, src)) {
398 mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize); 423 mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
399 if (mem == NULL) { 424 if (mem == NULL) {
400 PyErr_NoMemory(); 425 PyErr_NoMemory();
401 return -1; 426 return -1;
402 } 427 }
403 } 428 }
404 429
(...skipping 1417 matching lines...) Expand 10 before | Expand all | Expand 10 after
1822 err_range: 1847 err_range:
1823 return value_error_int(fmt); 1848 return value_error_int(fmt);
1824 err_format: 1849 err_format:
1825 PyErr_Format(PyExc_NotImplementedError, 1850 PyErr_Format(PyExc_NotImplementedError,
1826 "memoryview: format %s not supported", fmt); 1851 "memoryview: format %s not supported", fmt);
1827 return -1; 1852 return -1;
1828 } 1853 }
1829 1854
1830 1855
1831 /****************************************************************************/ 1856 /****************************************************************************/
1857 /* unpack using the struct module */
1858 /****************************************************************************/
1859
1860 /* For reasonable performance it is necessary to cache all objects required
1861 for unpacking. An unpacker can handle the format passed to unpack_from().
1862 Invariant: All pointer fields of the struct should either be NULL or valid
1863 pointers. */
1864 struct unpacker {
1865 PyObject *unpack_from; /* Struct.unpack_from(format) */
1866 PyObject *mview; /* cached memoryview */
1867 char *item; /* buffer for mview */
1868 Py_ssize_t itemsize; /* len(item) */
1869 };
1870
1871 static struct unpacker *
1872 unpacker_new(void)
1873 {
1874 struct unpacker *x = PyMem_Malloc(sizeof *x);
1875
1876 if (x == NULL) {
1877 PyErr_NoMemory();
1878 return NULL;
1879 }
1880
1881 x->unpack_from = NULL;
1882 x->mview = NULL;
1883 x->item = NULL;
1884 x->itemsize = 0;
1885
1886 return x;
1887 }
1888
1889 static void
1890 unpacker_free(struct unpacker *x)
1891 {
1892 if (x) {
1893 Py_XDECREF(x->unpack_from);
1894 Py_XDECREF(x->mview);
1895 PyMem_Free(x->item);
1896 PyMem_Free(x);
1897 }
1898 }
1899
1900 /* Return a new unpacker for the given format. */
1901 static struct unpacker *
1902 struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
1903 {
1904 PyObject *structmodule; /* XXX cache these two */
1905 PyObject *Struct = NULL; /* XXX in globals? */
1906 PyObject *structobj = NULL;
1907 PyObject *format = NULL;
1908 struct unpacker *x = NULL;
1909
1910 structmodule = PyImport_ImportModule("struct");
1911 if (structmodule == NULL)
1912 return NULL;
1913
1914 Struct = PyObject_GetAttrString(structmodule, "Struct");
1915 Py_DECREF(structmodule);
1916 if (Struct == NULL)
1917 return NULL;
1918
1919 x = unpacker_new();
1920 if (x == NULL)
1921 goto error;
1922
1923 format = PyBytes_FromString(fmt);
1924 if (format == NULL)
1925 goto error;
1926
1927 structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
1928 if (structobj == NULL)
1929 goto error;
1930
1931 x->unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
1932 if (x->unpack_from == NULL)
1933 goto error;
1934
1935 x->item = PyMem_Malloc(itemsize);
1936 if (x->item == NULL) {
1937 PyErr_NoMemory();
1938 goto error;
1939 }
1940 x->itemsize = itemsize;
1941
1942 x->mview = PyMemoryView_FromMemory(x->item, itemsize, PyBUF_WRITE);
1943 if (x->mview == NULL)
1944 goto error;
1945
1946
1947 out:
1948 Py_XDECREF(Struct);
1949 Py_XDECREF(format);
1950 Py_XDECREF(structobj);
1951 return x;
1952
1953 error:
1954 unpacker_free(x);
1955 x = NULL;
1956 goto out;
1957 }
1958
1959 /* unpack a single item */
1960 static PyObject *
1961 struct_unpack_single(const char *ptr, struct unpacker *x)
1962 {
1963 PyObject *v;
1964
1965 memcpy(x->item, ptr, x->itemsize);
1966 v = PyObject_CallFunctionObjArgs(x->unpack_from, x->mview, NULL);
1967 if (v == NULL)
1968 return NULL;
1969
1970 if (PyTuple_GET_SIZE(v) == 1) {
1971 PyObject *tmp = PyTuple_GET_ITEM(v, 0);
1972 Py_INCREF(tmp);
1973 Py_DECREF(v);
1974 return tmp;
1975 }
1976
1977 return v;
1978 }
1979
1980
1981 /****************************************************************************/
1832 /* Representations */ 1982 /* Representations */
1833 /****************************************************************************/ 1983 /****************************************************************************/
1834 1984
1835 /* allow explicit form of native format */ 1985 /* allow explicit form of native format */
1836 Py_LOCAL_INLINE(const char *) 1986 Py_LOCAL_INLINE(const char *)
1837 adjust_fmt(const Py_buffer *view) 1987 adjust_fmt(const Py_buffer *view)
1838 { 1988 {
1839 const char *fmt; 1989 const char *fmt;
1840 1990
1841 fmt = (view->format[0] == '@') ? view->format+1 : view->format; 1991 fmt = (view->format[0] == '@') ? view->format+1 : view->format;
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
2255 0, /* sq_concat */ 2405 0, /* sq_concat */
2256 0, /* sq_repeat */ 2406 0, /* sq_repeat */
2257 (ssizeargfunc)memory_item, /* sq_item */ 2407 (ssizeargfunc)memory_item, /* sq_item */
2258 }; 2408 };
2259 2409
2260 2410
2261 /**************************************************************************/ 2411 /**************************************************************************/
2262 /* Comparisons */ 2412 /* Comparisons */
2263 /**************************************************************************/ 2413 /**************************************************************************/
2264 2414
2415 #define MV_COMPARE_EX -1 /* exception */
2416 #define MV_COMPARE_NOT_IMPL -2 /* not implemented */
2417
2418 /* Translate a StructError to "not equal". Preserve other exceptions. */
2419 static int
2420 fix_struct_error_int(void)
2421 {
2422 assert(PyErr_Occurred());
2423 /* XXX Cannot get at StructError directly? */
2424 if (PyErr_ExceptionMatches(PyExc_ImportError) ||
2425 PyErr_ExceptionMatches(PyExc_MemoryError)) {
2426 return MV_COMPARE_EX;
2427 }
2428 /* StructError: invalid or unknown format -> not equal */
2429 PyErr_Clear();
2430 return 0;
2431 }
2432
2433 /* Unpack and compare single items of p and q using the struct module. */
2434 static int
2435 struct_unpack_cmp(const char *p, const char *q,
2436 struct unpacker *unpack_p, struct unpacker *unpack_q)
2437 {
2438 PyObject *v, *w;
2439 int ret;
2440
2441 /* At this point any exception from the struct module should not be
2442 StructError, since both formats have been accepted already. */
2443 v = struct_unpack_single(p, unpack_p);
2444 if (v == NULL)
2445 return MV_COMPARE_EX;
2446
2447 w = struct_unpack_single(q, unpack_q);
2448 if (w == NULL) {
2449 Py_DECREF(v);
2450 return MV_COMPARE_EX;
2451 }
2452
2453 /* MV_COMPARE_EX == -1: exceptions are preserved */
2454 ret = PyObject_RichCompareBool(v, w, Py_EQ);
2455 Py_DECREF(v);
2456 Py_DECREF(w);
2457
2458 return ret;
2459 }
2460
2461 /* Unpack and compare single items of p and q. If both p and q have the same
2462 single element native format, the comparison uses a fast path (gcc creates
2463 a jump table and converts memcpy into simple assignments on x86/x64).
2464
2465 Otherwise, the comparison is delegated to the struct module, which is
2466 30-60x slower. */
2265 #define CMP_SINGLE(p, q, type) \ 2467 #define CMP_SINGLE(p, q, type) \
2266 do { \ 2468 do { \
2267 type x; \ 2469 type x; \
2268 type y; \ 2470 type y; \
2269 memcpy((char *)&x, p, sizeof x); \ 2471 memcpy((char *)&x, p, sizeof x); \
2270 memcpy((char *)&y, q, sizeof y); \ 2472 memcpy((char *)&y, q, sizeof y); \
2271 equal = (x == y); \ 2473 equal = (x == y); \
2272 } while (0) 2474 } while (0)
2273 2475
2274 Py_LOCAL_INLINE(int) 2476 Py_LOCAL_INLINE(int)
2275 unpack_cmp(const char *p, const char *q, const char *fmt) 2477 unpack_cmp(const char *p, const char *q, char fmt,
2478 struct unpacker *unpack_p, struct unpacker *unpack_q)
2276 { 2479 {
2277 int equal; 2480 int equal;
2278 2481
2279 switch (fmt[0]) { 2482 switch (fmt) {
2280 2483
2281 /* signed integers and fast path for 'B' */ 2484 /* signed integers and fast path for 'B' */
2282 case 'B': return *((unsigned char *)p) == *((unsigned char *)q); 2485 case 'B': return *((unsigned char *)p) == *((unsigned char *)q);
2283 case 'b': return *((signed char *)p) == *((signed char *)q); 2486 case 'b': return *((signed char *)p) == *((signed char *)q);
2284 case 'h': CMP_SINGLE(p, q, short); return equal; 2487 case 'h': CMP_SINGLE(p, q, short); return equal;
2285 case 'i': CMP_SINGLE(p, q, int); return equal; 2488 case 'i': CMP_SINGLE(p, q, int); return equal;
2286 case 'l': CMP_SINGLE(p, q, long); return equal; 2489 case 'l': CMP_SINGLE(p, q, long); return equal;
2287 2490
2288 /* boolean */ 2491 /* boolean */
2289 #ifdef HAVE_C99_BOOL 2492 #ifdef HAVE_C99_BOOL
(...skipping 21 matching lines...) Expand all
2311 /* XXX DBL_EPSILON? */ 2514 /* XXX DBL_EPSILON? */
2312 case 'f': CMP_SINGLE(p, q, float); return equal; 2515 case 'f': CMP_SINGLE(p, q, float); return equal;
2313 case 'd': CMP_SINGLE(p, q, double); return equal; 2516 case 'd': CMP_SINGLE(p, q, double); return equal;
2314 2517
2315 /* bytes object */ 2518 /* bytes object */
2316 case 'c': return *p == *q; 2519 case 'c': return *p == *q;
2317 2520
2318 /* pointer */ 2521 /* pointer */
2319 case 'P': CMP_SINGLE(p, q, void *); return equal; 2522 case 'P': CMP_SINGLE(p, q, void *); return equal;
2320 2523
2321 /* Py_NotImplemented */ 2524 /* use the struct module */
2322 default: return -1; 2525 case '_':
2323 } 2526 assert(unpack_p);
2527 assert(unpack_q);
2528 return struct_unpack_cmp(p, q, unpack_p, unpack_q);
2529 }
2530
2531 /* NOT REACHED */
2532 PyErr_SetString(PyExc_RuntimeError,
2533 "memoryview: internal error in richcompare");
2534 return MV_COMPARE_EX;
2324 } 2535 }
2325 2536
2326 /* Base case for recursive array comparisons. Assumption: ndim == 1. */ 2537 /* Base case for recursive array comparisons. Assumption: ndim == 1. */
2327 static int 2538 static int
2328 cmp_base(const char *p, const char *q, const Py_ssize_t *shape, 2539 cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
2329 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2540 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2330 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2541 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2331 const char *fmt) 2542 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2332 { 2543 {
2333 Py_ssize_t i; 2544 Py_ssize_t i;
2334 int equal; 2545 int equal;
2335 2546
2336 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) { 2547 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2337 const char *xp = ADJUST_PTR(p, psuboffsets); 2548 const char *xp = ADJUST_PTR(p, psuboffsets);
2338 const char *xq = ADJUST_PTR(q, qsuboffsets); 2549 const char *xq = ADJUST_PTR(q, qsuboffsets);
2339 equal = unpack_cmp(xp, xq, fmt); 2550 equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
2340 if (equal <= 0) 2551 if (equal <= 0)
2341 return equal; 2552 return equal;
2342 } 2553 }
2343 2554
2344 return 1; 2555 return 1;
2345 } 2556 }
2346 2557
2347 /* Recursively compare two multi-dimensional arrays that have the same 2558 /* Recursively compare two multi-dimensional arrays that have the same
2348 logical structure. Assumption: ndim >= 1. */ 2559 logical structure. Assumption: ndim >= 1. */
2349 static int 2560 static int
2350 cmp_rec(const char *p, const char *q, 2561 cmp_rec(const char *p, const char *q,
2351 Py_ssize_t ndim, const Py_ssize_t *shape, 2562 Py_ssize_t ndim, const Py_ssize_t *shape,
2352 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2563 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2353 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2564 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2354 const char *fmt) 2565 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2355 { 2566 {
2356 Py_ssize_t i; 2567 Py_ssize_t i;
2357 int equal; 2568 int equal;
2358 2569
2359 assert(ndim >= 1); 2570 assert(ndim >= 1);
2360 assert(shape != NULL); 2571 assert(shape != NULL);
2361 assert(pstrides != NULL); 2572 assert(pstrides != NULL);
2362 assert(qstrides != NULL); 2573 assert(qstrides != NULL);
2363 2574
2364 if (ndim == 1) { 2575 if (ndim == 1) {
2365 return cmp_base(p, q, shape, 2576 return cmp_base(p, q, shape,
2366 pstrides, psuboffsets, 2577 pstrides, psuboffsets,
2367 qstrides, qsuboffsets, 2578 qstrides, qsuboffsets,
2368 fmt); 2579 fmt, unpack_p, unpack_q);
2369 } 2580 }
2370 2581
2371 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) { 2582 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2372 const char *xp = ADJUST_PTR(p, psuboffsets); 2583 const char *xp = ADJUST_PTR(p, psuboffsets);
2373 const char *xq = ADJUST_PTR(q, qsuboffsets); 2584 const char *xq = ADJUST_PTR(q, qsuboffsets);
2374 equal = cmp_rec(xp, xq, ndim-1, shape+1, 2585 equal = cmp_rec(xp, xq, ndim-1, shape+1,
2375 pstrides+1, psuboffsets ? psuboffsets+1 : NULL, 2586 pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
2376 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL, 2587 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
2377 fmt); 2588 fmt, unpack_p, unpack_q);
2378 if (equal <= 0) 2589 if (equal <= 0)
2379 return equal; 2590 return equal;
2380 } 2591 }
2381 2592
2382 return 1; 2593 return 1;
2383 } 2594 }
2384 2595
2385 static PyObject * 2596 static PyObject *
2386 memory_richcompare(PyObject *v, PyObject *w, int op) 2597 memory_richcompare(PyObject *v, PyObject *w, int op)
2387 { 2598 {
2388 PyObject *res, *vval, *wval; 2599 PyObject *res;
2389 Py_buffer wbuf, *vv, *ww = NULL; 2600 Py_buffer wbuf, *vv;
2390 const char *vfmt, *wfmt; 2601 Py_buffer *ww = NULL;
2391 int equal = -1; /* Py_NotImplemented */ 2602 struct unpacker *unpack_v = NULL;
2392 2603 struct unpacker *unpack_w = NULL;
2393 vval = wval = NULL; 2604 char vfmt, wfmt;
2605 int equal = MV_COMPARE_NOT_IMPL;
2606
2394 if (op != Py_EQ && op != Py_NE) 2607 if (op != Py_EQ && op != Py_NE)
2395 goto result; /* Py_NotImplemented */ 2608 goto result; /* Py_NotImplemented */
2396 2609
2397 assert(PyMemoryView_Check(v)); 2610 assert(PyMemoryView_Check(v));
2398 if (BASE_INACCESSIBLE(v)) { 2611 if (BASE_INACCESSIBLE(v)) {
2399 equal = (v == w); 2612 equal = (v == w);
2400 goto result; 2613 goto result;
2401 } 2614 }
2402 vv = VIEW_ADDR(v); 2615 vv = VIEW_ADDR(v);
2403 2616
2404 if (PyMemoryView_Check(w)) { 2617 if (PyMemoryView_Check(w)) {
2405 if (BASE_INACCESSIBLE(w)) { 2618 if (BASE_INACCESSIBLE(w)) {
2406 equal = (v == w); 2619 equal = (v == w);
2407 goto result; 2620 goto result;
2408 } 2621 }
2409 ww = VIEW_ADDR(w); 2622 ww = VIEW_ADDR(w);
2410 } 2623 }
2411 else { 2624 else {
2412 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) { 2625 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
2413 PyErr_Clear(); 2626 PyErr_Clear();
2414 goto result; /* Py_NotImplemented */ 2627 goto result; /* Py_NotImplemented */
2415 } 2628 }
2416 ww = &wbuf; 2629 ww = &wbuf;
2417 } 2630 }
2418 2631
2419 vfmt = adjust_fmt(vv); 2632 if (!equiv_shape(vv, ww)) {
2420 wfmt = adjust_fmt(ww);
2421 if (vfmt == NULL || wfmt == NULL) {
2422 PyErr_Clear(); 2633 PyErr_Clear();
2423 goto result; /* Py_NotImplemented */ 2634 equal = 0;
2424 } 2635 goto result;
2425 2636 }
2426 if (cmp_structure(vv, ww) < 0) { 2637
2427 » /* Different structures. Compare tolist representations. */ 2638 /* Use fast unpacking for identical primitive C type formats. */
2428 PyErr_Clear(); 2639 if (get_native_fmtchar(&vfmt, vv->format) < 0)
2429 » equal = -1; 2640 vfmt = '_';
2430 » wval = 0; 2641 if (get_native_fmtchar(&wfmt, ww->format) < 0)
2431 » vval = _IntTupleFromSsizet(vv->ndim, vv->shape); 2642 wfmt = '_';
2432 » if (!vval) 2643 if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
2433 » goto result; 2644 /* Use struct module unpacking. NOTE: Even for equal format strings,
2434 » wval = _IntTupleFromSsizet(ww->ndim, ww->shape); 2645 memcmp() cannot be used for item comparison since it would give
2435 » if (!wval) 2646 incorrect results in the case of NaNs or uninitialized padding
2436 » goto result; 2647 bytes. */
2437 » equal = PyObject_RichCompareBool(vval, wval, Py_EQ); 2648 vfmt = '_';
2438 » if (equal != 1) 2649 unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
2439 » goto result; 2650 if (unpack_v == NULL) {
2440 » Py_CLEAR(vval); 2651 equal = fix_struct_error_int();
2441 » Py_CLEAR(wval); 2652 goto result;
2442 » vval = memory_tolist((PyMemoryViewObject*)v, NULL); 2653 }
2443 » if (!vval) 2654 unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
2444 » goto result; 2655 if (unpack_w == NULL) {
2445 » wval = memory_tolist((PyMemoryViewObject*)w, NULL); 2656 equal = fix_struct_error_int();
2446 » if (!wval) 2657 goto result;
2447 » goto result; 2658 }
2448 » equal = PyObject_RichCompareBool(vval, wval, Py_EQ);
2449 » goto result;
2450 } 2659 }
2451 2660
2452 if (vv->ndim == 0) { 2661 if (vv->ndim == 0) {
2453 equal = unpack_cmp(vv->buf, ww->buf, vfmt); 2662 equal = unpack_cmp(vv->buf, ww->buf,
2663 vfmt, unpack_v, unpack_w);
2454 } 2664 }
2455 else if (vv->ndim == 1) { 2665 else if (vv->ndim == 1) {
2456 equal = cmp_base(vv->buf, ww->buf, vv->shape, 2666 equal = cmp_base(vv->buf, ww->buf, vv->shape,
2457 vv->strides, vv->suboffsets, 2667 vv->strides, vv->suboffsets,
2458 ww->strides, ww->suboffsets, 2668 ww->strides, ww->suboffsets,
2459 vfmt); 2669 vfmt, unpack_v, unpack_w);
2460 } 2670 }
2461 else { 2671 else {
2462 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape, 2672 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
2463 vv->strides, vv->suboffsets, 2673 vv->strides, vv->suboffsets,
2464 ww->strides, ww->suboffsets, 2674 ww->strides, ww->suboffsets,
2465 vfmt); 2675 vfmt, unpack_v, unpack_w);
2466 } 2676 }
2467 2677
2468 result: 2678 result:
2469 Py_XDECREF(vval); 2679 if (equal < 0) {
2470 Py_XDECREF(wval); 2680 if (equal == MV_COMPARE_NOT_IMPL)
2471 if (equal < 0) 2681 res = Py_NotImplemented;
2472 res = Py_NotImplemented; 2682 else /* exception */
2683 res = NULL;
2684 }
2473 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) 2685 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
2474 res = Py_True; 2686 res = Py_True;
2475 else 2687 else
2476 res = Py_False; 2688 res = Py_False;
2477 2689
2478 if (ww == &wbuf) 2690 if (ww == &wbuf)
2479 PyBuffer_Release(ww); 2691 PyBuffer_Release(ww);
2480 Py_INCREF(res); 2692
2693 unpacker_free(unpack_v);
2694 unpacker_free(unpack_w);
2695
2696 Py_XINCREF(res);
2481 return res; 2697 return res;
2482 } 2698 }
2483 2699
2484 /**************************************************************************/ 2700 /**************************************************************************/
2485 /* Hash */ 2701 /* Hash */
2486 /**************************************************************************/ 2702 /**************************************************************************/
2487 2703
2488 static Py_hash_t 2704 static Py_hash_t
2489 memory_hash(PyMemoryViewObject *self) 2705 memory_hash(PyMemoryViewObject *self)
2490 { 2706 {
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
2706 memory_getsetlist, /* tp_getset */ 2922 memory_getsetlist, /* tp_getset */
2707 0, /* tp_base */ 2923 0, /* tp_base */
2708 0, /* tp_dict */ 2924 0, /* tp_dict */
2709 0, /* tp_descr_get */ 2925 0, /* tp_descr_get */
2710 0, /* tp_descr_set */ 2926 0, /* tp_descr_set */
2711 0, /* tp_dictoffset */ 2927 0, /* tp_dictoffset */
2712 0, /* tp_init */ 2928 0, /* tp_init */
2713 0, /* tp_alloc */ 2929 0, /* tp_alloc */
2714 memory_new, /* tp_new */ 2930 memory_new, /* tp_new */
2715 }; 2931 };
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+