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

Side by Side Diff: Objects/memoryobject.c

Issue 15573: Support unknown formats in memoryview comparisons
Patch Set: Created 7 years, 9 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:
View unified diff | Download patch
« no previous file with comments | « Lib/test/test_buffer.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 NOTE: All buffers are assumed to have PyBUF_FULL information, which 239 NOTE: All buffers are assumed to have PyBUF_FULL information, which
240 is the case for memoryviews! */ 240 is the case for memoryviews! */
241 241
242 242
243 /* 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
244 perhaps be explicitly forbidden in the PEP. */ 244 perhaps be explicitly forbidden in the PEP. */
245 #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \ 245 #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \
246 (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0) 246 (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0)
247 247
248 Py_LOCAL_INLINE(int) 248 Py_LOCAL_INLINE(int)
249 last_dim_is_contiguous(Py_buffer *dest, Py_buffer *src) 249 last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src)
250 { 250 {
251 assert(dest->ndim > 0 && src->ndim > 0); 251 assert(dest->ndim > 0 && src->ndim > 0);
252 return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) && 252 return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) &&
253 !HAVE_SUBOFFSETS_IN_LAST_DIM(src) && 253 !HAVE_SUBOFFSETS_IN_LAST_DIM(src) &&
254 dest->strides[dest->ndim-1] == dest->itemsize && 254 dest->strides[dest->ndim-1] == dest->itemsize &&
255 src->strides[src->ndim-1] == src->itemsize); 255 src->strides[src->ndim-1] == src->itemsize);
256 } 256 }
257 257
258 /* Check that the logical structure of the destination and source buffers 258 /* This is not a general function for determining format equivalence.
259 is identical. */ 259 It is used in copy_single() and copy_buffer() to weed out non-matching
260 static int 260 formats. Skipping the '@' character is specifically used in slice
261 cmp_structure(Py_buffer *dest, Py_buffer *src) 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)
262 { 266 {
263 const char *dfmt, *sfmt; 267 const char *dfmt, *sfmt;
264 int i;
265 268
266 assert(dest->format && src->format); 269 assert(dest->format && src->format);
267 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format; 270 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
268 sfmt = src->format[0] == '@' ? src->format+1 : src->format; 271 sfmt = src->format[0] == '@' ? src->format+1 : src->format;
269 272
270 if (strcmp(dfmt, sfmt) != 0 || 273 if (strcmp(dfmt, sfmt) != 0 ||
271 dest->itemsize != src->itemsize || 274 dest->itemsize != src->itemsize) {
272 dest->ndim != src->ndim) { 275 return 0;
273 goto value_error;
274 } 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;
275 291
276 for (i = 0; i < dest->ndim; i++) { 292 for (i = 0; i < dest->ndim; i++) {
277 if (dest->shape[i] != src->shape[i]) 293 if (dest->shape[i] != src->shape[i])
278 goto value_error; 294 return 0;
279 if (dest->shape[i] == 0) 295 if (dest->shape[i] == 0)
280 break; 296 break;
281 } 297 }
282 298
283 return 0; 299 return 1;
300 }
284 301
285 value_error: 302 /* Check that the logical structure of the destination and source buffers
286 PyErr_SetString(PyExc_ValueError, 303 is identical. */
287 "ndarray assignment: lvalue and rvalue have different structures"); 304 static int
288 return -1; 305 equiv_structure(const Py_buffer *dest, const Py_buffer *src)
306 {
307 if (!equiv_format(dest, src) ||
308 !equiv_shape(dest, src)) {
309 PyErr_SetString(PyExc_ValueError,
310 "ndarray assignment: lvalue and rvalue have different structures");
311 return 0;
312 }
313
314 return 1;
289 } 315 }
290 316
291 /* Base case for recursive multi-dimensional copying. Contiguous arrays are 317 /* Base case for recursive multi-dimensional copying. Contiguous arrays are
292 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or 318 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or
293 sizeof(mem) == shape[0] * itemsize. */ 319 sizeof(mem) == shape[0] * itemsize. */
294 static void 320 static void
295 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize, 321 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize,
296 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,
297 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,
298 char *mem) 324 char *mem)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 } 377 }
352 378
353 /* Faster copying of one-dimensional arrays. */ 379 /* Faster copying of one-dimensional arrays. */
354 static int 380 static int
355 copy_single(Py_buffer *dest, Py_buffer *src) 381 copy_single(Py_buffer *dest, Py_buffer *src)
356 { 382 {
357 char *mem = NULL; 383 char *mem = NULL;
358 384
359 assert(dest->ndim == 1); 385 assert(dest->ndim == 1);
360 386
361 if (cmp_structure(dest, src) < 0) 387 if (!equiv_structure(dest, src))
362 return -1; 388 return -1;
363 389
364 if (!last_dim_is_contiguous(dest, src)) { 390 if (!last_dim_is_contiguous(dest, src)) {
365 mem = PyMem_Malloc(dest->shape[0] * dest->itemsize); 391 mem = PyMem_Malloc(dest->shape[0] * dest->itemsize);
366 if (mem == NULL) { 392 if (mem == NULL) {
367 PyErr_NoMemory(); 393 PyErr_NoMemory();
368 return -1; 394 return -1;
369 } 395 }
370 } 396 }
371 397
(...skipping 11 matching lines...) Expand all
383 /* 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
384 structure. Copying is atomic, the function never fails with a partial 410 structure. Copying is atomic, the function never fails with a partial
385 copy. */ 411 copy. */
386 static int 412 static int
387 copy_buffer(Py_buffer *dest, Py_buffer *src) 413 copy_buffer(Py_buffer *dest, Py_buffer *src)
388 { 414 {
389 char *mem = NULL; 415 char *mem = NULL;
390 416
391 assert(dest->ndim > 0); 417 assert(dest->ndim > 0);
392 418
393 if (cmp_structure(dest, src) < 0) 419 if (!equiv_structure(dest, src))
394 return -1; 420 return -1;
395 421
396 if (!last_dim_is_contiguous(dest, src)) { 422 if (!last_dim_is_contiguous(dest, src)) {
397 mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize); 423 mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
398 if (mem == NULL) { 424 if (mem == NULL) {
399 PyErr_NoMemory(); 425 PyErr_NoMemory();
400 return -1; 426 return -1;
401 } 427 }
402 } 428 }
403 429
(...skipping 1414 matching lines...) Expand 10 before | Expand all | Expand 10 after
1818 1844
1819 err_occurred: 1845 err_occurred:
1820 return fix_error_int(fmt); 1846 return fix_error_int(fmt);
1821 err_range: 1847 err_range:
1822 return value_error_int(fmt); 1848 return value_error_int(fmt);
1823 err_format: 1849 err_format:
1824 PyErr_Format(PyExc_NotImplementedError, 1850 PyErr_Format(PyExc_NotImplementedError,
1825 "memoryview: format %s not supported", fmt); 1851 "memoryview: format %s not supported", fmt);
1826 return -1; 1852 return -1;
1827 } 1853 }
1854
1855
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 }
1828 1979
1829 1980
1830 /****************************************************************************/ 1981 /****************************************************************************/
1831 /* Representations */ 1982 /* Representations */
1832 /****************************************************************************/ 1983 /****************************************************************************/
1833 1984
1834 /* allow explicit form of native format */ 1985 /* allow explicit form of native format */
1835 Py_LOCAL_INLINE(const char *) 1986 Py_LOCAL_INLINE(const char *)
1836 adjust_fmt(const Py_buffer *view) 1987 adjust_fmt(const Py_buffer *view)
1837 { 1988 {
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
2254 0, /* sq_concat */ 2405 0, /* sq_concat */
2255 0, /* sq_repeat */ 2406 0, /* sq_repeat */
2256 (ssizeargfunc)memory_item, /* sq_item */ 2407 (ssizeargfunc)memory_item, /* sq_item */
2257 }; 2408 };
2258 2409
2259 2410
2260 /**************************************************************************/ 2411 /**************************************************************************/
2261 /* Comparisons */ 2412 /* Comparisons */
2262 /**************************************************************************/ 2413 /**************************************************************************/
2263 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. */
2264 #define CMP_SINGLE(p, q, type) \ 2467 #define CMP_SINGLE(p, q, type) \
2265 do { \ 2468 do { \
2266 type x; \ 2469 type x; \
2267 type y; \ 2470 type y; \
2268 memcpy((char *)&x, p, sizeof x); \ 2471 memcpy((char *)&x, p, sizeof x); \
2269 memcpy((char *)&y, q, sizeof y); \ 2472 memcpy((char *)&y, q, sizeof y); \
2270 equal = (x == y); \ 2473 equal = (x == y); \
2271 } while (0) 2474 } while (0)
2272 2475
2273 Py_LOCAL_INLINE(int) 2476 Py_LOCAL_INLINE(int)
2274 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)
2275 { 2479 {
2276 int equal; 2480 int equal;
2277 2481
2278 switch (fmt[0]) { 2482 switch (fmt) {
2279 2483
2280 /* signed integers and fast path for 'B' */ 2484 /* signed integers and fast path for 'B' */
2281 case 'B': return *((unsigned char *)p) == *((unsigned char *)q); 2485 case 'B': return *((unsigned char *)p) == *((unsigned char *)q);
2282 case 'b': return *((signed char *)p) == *((signed char *)q); 2486 case 'b': return *((signed char *)p) == *((signed char *)q);
2283 case 'h': CMP_SINGLE(p, q, short); return equal; 2487 case 'h': CMP_SINGLE(p, q, short); return equal;
2284 case 'i': CMP_SINGLE(p, q, int); return equal; 2488 case 'i': CMP_SINGLE(p, q, int); return equal;
2285 case 'l': CMP_SINGLE(p, q, long); return equal; 2489 case 'l': CMP_SINGLE(p, q, long); return equal;
2286 2490
2287 /* boolean */ 2491 /* boolean */
2288 #ifdef HAVE_C99_BOOL 2492 #ifdef HAVE_C99_BOOL
(...skipping 21 matching lines...) Expand all
2310 /* XXX DBL_EPSILON? */ 2514 /* XXX DBL_EPSILON? */
2311 case 'f': CMP_SINGLE(p, q, float); return equal; 2515 case 'f': CMP_SINGLE(p, q, float); return equal;
2312 case 'd': CMP_SINGLE(p, q, double); return equal; 2516 case 'd': CMP_SINGLE(p, q, double); return equal;
2313 2517
2314 /* bytes object */ 2518 /* bytes object */
2315 case 'c': return *p == *q; 2519 case 'c': return *p == *q;
2316 2520
2317 /* pointer */ 2521 /* pointer */
2318 case 'P': CMP_SINGLE(p, q, void *); return equal; 2522 case 'P': CMP_SINGLE(p, q, void *); return equal;
2319 2523
2320 /* Py_NotImplemented */ 2524 /* use the struct module */
2321 default: return -1; 2525 case '_':
2526 assert(unpack_p);
2527 assert(unpack_q);
2528 return struct_unpack_cmp(p, q, unpack_p, unpack_q);
2322 } 2529 }
2530
2531 /* NOT REACHED */
2532 PyErr_SetString(PyExc_RuntimeError,
2533 "memoryview: internal error in richcompare");
2534 return MV_COMPARE_EX;
2323 } 2535 }
2324 2536
2325 /* Base case for recursive array comparisons. Assumption: ndim == 1. */ 2537 /* Base case for recursive array comparisons. Assumption: ndim == 1. */
2326 static int 2538 static int
2327 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,
2328 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2540 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2329 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2541 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2330 const char *fmt) 2542 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2331 { 2543 {
2332 Py_ssize_t i; 2544 Py_ssize_t i;
2333 int equal; 2545 int equal;
2334 2546
2335 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++) {
2336 const char *xp = ADJUST_PTR(p, psuboffsets); 2548 const char *xp = ADJUST_PTR(p, psuboffsets);
2337 const char *xq = ADJUST_PTR(q, qsuboffsets); 2549 const char *xq = ADJUST_PTR(q, qsuboffsets);
2338 equal = unpack_cmp(xp, xq, fmt); 2550 equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
2339 if (equal <= 0) 2551 if (equal <= 0)
2340 return equal; 2552 return equal;
2341 } 2553 }
2342 2554
2343 return 1; 2555 return 1;
2344 } 2556 }
2345 2557
2346 /* Recursively compare two multi-dimensional arrays that have the same 2558 /* Recursively compare two multi-dimensional arrays that have the same
2347 logical structure. Assumption: ndim >= 1. */ 2559 logical structure. Assumption: ndim >= 1. */
2348 static int 2560 static int
2349 cmp_rec(const char *p, const char *q, 2561 cmp_rec(const char *p, const char *q,
2350 Py_ssize_t ndim, const Py_ssize_t *shape, 2562 Py_ssize_t ndim, const Py_ssize_t *shape,
2351 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2563 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2352 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2564 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2353 const char *fmt) 2565 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2354 { 2566 {
2355 Py_ssize_t i; 2567 Py_ssize_t i;
2356 int equal; 2568 int equal;
2357 2569
2358 assert(ndim >= 1); 2570 assert(ndim >= 1);
2359 assert(shape != NULL); 2571 assert(shape != NULL);
2360 assert(pstrides != NULL); 2572 assert(pstrides != NULL);
2361 assert(qstrides != NULL); 2573 assert(qstrides != NULL);
2362 2574
2363 if (ndim == 1) { 2575 if (ndim == 1) {
2364 return cmp_base(p, q, shape, 2576 return cmp_base(p, q, shape,
2365 pstrides, psuboffsets, 2577 pstrides, psuboffsets,
2366 qstrides, qsuboffsets, 2578 qstrides, qsuboffsets,
2367 fmt); 2579 fmt, unpack_p, unpack_q);
2368 } 2580 }
2369 2581
2370 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++) {
2371 const char *xp = ADJUST_PTR(p, psuboffsets); 2583 const char *xp = ADJUST_PTR(p, psuboffsets);
2372 const char *xq = ADJUST_PTR(q, qsuboffsets); 2584 const char *xq = ADJUST_PTR(q, qsuboffsets);
2373 equal = cmp_rec(xp, xq, ndim-1, shape+1, 2585 equal = cmp_rec(xp, xq, ndim-1, shape+1,
2374 pstrides+1, psuboffsets ? psuboffsets+1 : NULL, 2586 pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
2375 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL, 2587 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
2376 fmt); 2588 fmt, unpack_p, unpack_q);
2377 if (equal <= 0) 2589 if (equal <= 0)
2378 return equal; 2590 return equal;
2379 } 2591 }
2380 2592
2381 return 1; 2593 return 1;
2382 } 2594 }
2383 2595
2384 static PyObject * 2596 static PyObject *
2385 memory_richcompare(PyObject *v, PyObject *w, int op) 2597 memory_richcompare(PyObject *v, PyObject *w, int op)
2386 { 2598 {
2387 PyObject *res; 2599 PyObject *res;
2388 Py_buffer wbuf, *vv, *ww = NULL; 2600 Py_buffer wbuf, *vv;
2389 const char *vfmt, *wfmt; 2601 Py_buffer *ww = NULL;
2390 int equal = -1; /* Py_NotImplemented */ 2602 struct unpacker *unpack_v = NULL;
2603 struct unpacker *unpack_w = NULL;
2604 char vfmt, wfmt;
2605 int equal = MV_COMPARE_NOT_IMPL;
2391 2606
2392 if (op != Py_EQ && op != Py_NE) 2607 if (op != Py_EQ && op != Py_NE)
2393 goto result; /* Py_NotImplemented */ 2608 goto result; /* Py_NotImplemented */
2394 2609
2395 assert(PyMemoryView_Check(v)); 2610 assert(PyMemoryView_Check(v));
2396 if (BASE_INACCESSIBLE(v)) { 2611 if (BASE_INACCESSIBLE(v)) {
2397 equal = (v == w); 2612 equal = (v == w);
2398 goto result; 2613 goto result;
2399 } 2614 }
2400 vv = VIEW_ADDR(v); 2615 vv = VIEW_ADDR(v);
2401 2616
2402 if (PyMemoryView_Check(w)) { 2617 if (PyMemoryView_Check(w)) {
2403 if (BASE_INACCESSIBLE(w)) { 2618 if (BASE_INACCESSIBLE(w)) {
2404 equal = (v == w); 2619 equal = (v == w);
2405 goto result; 2620 goto result;
2406 } 2621 }
2407 ww = VIEW_ADDR(w); 2622 ww = VIEW_ADDR(w);
2408 } 2623 }
2409 else { 2624 else {
2410 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) { 2625 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
2411 PyErr_Clear(); 2626 PyErr_Clear();
2412 goto result; /* Py_NotImplemented */ 2627 goto result; /* Py_NotImplemented */
2413 } 2628 }
2414 ww = &wbuf; 2629 ww = &wbuf;
2415 } 2630 }
2416 2631
2417 vfmt = adjust_fmt(vv); 2632 if (!equiv_shape(vv, ww)) {
2418 wfmt = adjust_fmt(ww);
2419 if (vfmt == NULL || wfmt == NULL) {
2420 PyErr_Clear();
2421 goto result; /* Py_NotImplemented */
2422 }
2423
2424 if (cmp_structure(vv, ww) < 0) {
2425 PyErr_Clear(); 2633 PyErr_Clear();
2426 equal = 0; 2634 equal = 0;
2427 goto result; 2635 goto result;
2428 } 2636 }
2429 2637
2638 /* Use fast unpacking for identical primitive C type formats. */
2639 if (get_native_fmtchar(&vfmt, vv->format) < 0)
2640 vfmt = '_';
2641 if (get_native_fmtchar(&wfmt, ww->format) < 0)
2642 wfmt = '_';
2643 if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
2644 /* Use struct module unpacking. NOTE: Even for equal format strings,
2645 memcmp() cannot be used for item comparison since it would give
2646 incorrect results in the case of NaNs or uninitialized padding
2647 bytes. */
2648 vfmt = '_';
2649 unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
2650 if (unpack_v == NULL) {
2651 equal = fix_struct_error_int();
2652 goto result;
2653 }
2654 unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
2655 if (unpack_w == NULL) {
2656 equal = fix_struct_error_int();
2657 goto result;
2658 }
2659 }
2660
2430 if (vv->ndim == 0) { 2661 if (vv->ndim == 0) {
2431 equal = unpack_cmp(vv->buf, ww->buf, vfmt); 2662 equal = unpack_cmp(vv->buf, ww->buf,
2663 vfmt, unpack_v, unpack_w);
2432 } 2664 }
2433 else if (vv->ndim == 1) { 2665 else if (vv->ndim == 1) {
2434 equal = cmp_base(vv->buf, ww->buf, vv->shape, 2666 equal = cmp_base(vv->buf, ww->buf, vv->shape,
2435 vv->strides, vv->suboffsets, 2667 vv->strides, vv->suboffsets,
2436 ww->strides, ww->suboffsets, 2668 ww->strides, ww->suboffsets,
2437 vfmt); 2669 vfmt, unpack_v, unpack_w);
2438 } 2670 }
2439 else { 2671 else {
2440 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape, 2672 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
2441 vv->strides, vv->suboffsets, 2673 vv->strides, vv->suboffsets,
2442 ww->strides, ww->suboffsets, 2674 ww->strides, ww->suboffsets,
2443 vfmt); 2675 vfmt, unpack_v, unpack_w);
2444 } 2676 }
2445 2677
2446 result: 2678 result:
2447 if (equal < 0) 2679 if (equal < 0) {
2448 res = Py_NotImplemented; 2680 if (equal == MV_COMPARE_NOT_IMPL)
2681 res = Py_NotImplemented;
2682 else /* exception */
2683 res = NULL;
2684 }
2449 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) 2685 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
2450 res = Py_True; 2686 res = Py_True;
2451 else 2687 else
2452 res = Py_False; 2688 res = Py_False;
2453 2689
2454 if (ww == &wbuf) 2690 if (ww == &wbuf)
2455 PyBuffer_Release(ww); 2691 PyBuffer_Release(ww);
2456 Py_INCREF(res); 2692
2693 unpacker_free(unpack_v);
2694 unpacker_free(unpack_w);
2695
2696 Py_XINCREF(res);
2457 return res; 2697 return res;
2458 } 2698 }
2459 2699
2460 /**************************************************************************/ 2700 /**************************************************************************/
2461 /* Hash */ 2701 /* Hash */
2462 /**************************************************************************/ 2702 /**************************************************************************/
2463 2703
2464 static Py_hash_t 2704 static Py_hash_t
2465 memory_hash(PyMemoryViewObject *self) 2705 memory_hash(PyMemoryViewObject *self)
2466 { 2706 {
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
2682 memory_getsetlist, /* tp_getset */ 2922 memory_getsetlist, /* tp_getset */
2683 0, /* tp_base */ 2923 0, /* tp_base */
2684 0, /* tp_dict */ 2924 0, /* tp_dict */
2685 0, /* tp_descr_get */ 2925 0, /* tp_descr_get */
2686 0, /* tp_descr_set */ 2926 0, /* tp_descr_set */
2687 0, /* tp_dictoffset */ 2927 0, /* tp_dictoffset */
2688 0, /* tp_init */ 2928 0, /* tp_init */
2689 0, /* tp_alloc */ 2929 0, /* tp_alloc */
2690 memory_new, /* tp_new */ 2930 memory_new, /* tp_new */
2691 }; 2931 };
OLDNEW
« no previous file with comments | « Lib/test/test_buffer.py ('k') | no next file » | no next file with comments »

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