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

Side by Side Diff: Objects/memoryobject.c

Issue 15573: Support unknown formats in memoryview comparisons
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:
View unified diff | Download patch
« Doc/whatsnew/3.3.rst ('K') | « 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 Py_LOCAL_INLINE(int)
259 is identical. */ 259 cmp_format(const Py_buffer *dest, const Py_buffer *src)
Nick Coghlan 2012/08/14 15:12:38 This doesn't appear to be used anywhere at the mom
skrah 2012/08/14 16:31:58 OK, perhaps equiv_format() is appropriate since th
260 static int
261 cmp_structure(Py_buffer *dest, Py_buffer *src)
262 { 260 {
263 const char *dfmt, *sfmt; 261 const char *dfmt, *sfmt;
264 int i;
265 262
266 assert(dest->format && src->format); 263 assert(dest->format && src->format);
267 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format; 264 dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
268 sfmt = src->format[0] == '@' ? src->format+1 : src->format; 265 sfmt = src->format[0] == '@' ? src->format+1 : src->format;
269 266
270 if (strcmp(dfmt, sfmt) != 0 || 267 if (strcmp(dfmt, sfmt) != 0 ||
271 dest->itemsize != src->itemsize || 268 dest->itemsize != src->itemsize) {
272 dest->ndim != src->ndim) { 269 return -1;
273 goto value_error;
274 } 270 }
271
272 return 0;
273 }
274
275 Py_LOCAL_INLINE(int)
276 cmp_shape(const Py_buffer *dest, const Py_buffer *src)
Nick Coghlan 2012/08/14 15:12:38 This API is rather confusing, since it is a simple
skrah 2012/08/14 16:31:58 I agree that it doesn't follow the standard patter
Nick Coghlan 2012/08/15 06:13:09 +1, that would be much easier to interpret. It's m
skrah 2012/08/15 16:45:02 OK, done.
277 {
278 int i;
279
280 if (dest->ndim != src->ndim)
281 return -1;
275 282
276 for (i = 0; i < dest->ndim; i++) { 283 for (i = 0; i < dest->ndim; i++) {
277 if (dest->shape[i] != src->shape[i]) 284 if (dest->shape[i] != src->shape[i])
278 goto value_error; 285 return -1;
279 if (dest->shape[i] == 0) 286 if (dest->shape[i] == 0)
280 break; 287 break;
281 } 288 }
282 289
283 return 0; 290 return 0;
291 }
284 292
285 value_error: 293 /* Check that the logical structure of the destination and source buffers
286 PyErr_SetString(PyExc_ValueError, 294 is identical. */
287 "ndarray assignment: lvalue and rvalue have different structures"); 295 static int
288 return -1; 296 cmp_structure(const Py_buffer *dest, const Py_buffer *src)
Nick Coghlan 2012/08/14 15:12:38 This appears to be unused now. Why not just delete
skrah 2012/08/14 16:31:58 It's still used in copy_single() and copy_buffer()
Nick Coghlan 2012/08/15 06:13:09 Yeah, this was a silly comment born of searching f
297 {
298 if (cmp_format(dest, src) < 0 ||
299 cmp_shape(dest, src) < 0) {
300 PyErr_SetString(PyExc_ValueError,
301 "ndarray assignment: lvalue and rvalue have different structures");
302 return -1;
303 }
304
305 return 0;
289 } 306 }
290 307
291 /* Base case for recursive multi-dimensional copying. Contiguous arrays are 308 /* Base case for recursive multi-dimensional copying. Contiguous arrays are
292 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or 309 copied with very little overhead. Assumptions: ndim == 1, mem == NULL or
293 sizeof(mem) == shape[0] * itemsize. */ 310 sizeof(mem) == shape[0] * itemsize. */
294 static void 311 static void
295 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize, 312 copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize,
296 char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets, 313 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, 314 char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
298 char *mem) 315 char *mem)
(...skipping 1519 matching lines...) Expand 10 before | Expand all | Expand 10 after
1818 1835
1819 err_occurred: 1836 err_occurred:
1820 return fix_error_int(fmt); 1837 return fix_error_int(fmt);
1821 err_range: 1838 err_range:
1822 return value_error_int(fmt); 1839 return value_error_int(fmt);
1823 err_format: 1840 err_format:
1824 PyErr_Format(PyExc_NotImplementedError, 1841 PyErr_Format(PyExc_NotImplementedError,
1825 "memoryview: format %s not supported", fmt); 1842 "memoryview: format %s not supported", fmt);
1826 return -1; 1843 return -1;
1827 } 1844 }
1845
1846
1847 /****************************************************************************/
1848 /* unpack using the struct module */
1849 /****************************************************************************/
1850
1851 /* For reasonable performance it is necessary to cache all objects required
1852 for unpacking. An unpacker can handle the format passed to unpack_from().
1853 Invariant: All pointer fields of the struct should either be NULL or valid
1854 pointers. */
1855 struct unpacker {
1856 PyObject *unpack_from; /* Struct.unpack_from(format) */
1857 PyObject *mview; /* cached memoryview */
1858 char *item; /* buffer for mview */
1859 Py_ssize_t itemsize; /* len(item) */
1860 };
1861
1862 static struct unpacker *
1863 unpacker_new(void)
1864 {
1865 struct unpacker *x = PyMem_Malloc(sizeof *x);
1866
1867 if (x == NULL) {
1868 PyErr_NoMemory();
1869 return NULL;
1870 }
1871
1872 x->unpack_from = NULL;
1873 x->mview = NULL;
1874 x->item = NULL;
1875 x->itemsize = 0;
1876
1877 return x;
1878 }
1879
1880 static void
1881 unpacker_free(struct unpacker *x)
1882 {
1883 if (x) {
1884 Py_XDECREF(x->unpack_from);
1885 Py_XDECREF(x->mview);
1886 PyMem_Free(x->item);
1887 PyMem_Free(x);
1888 }
1889 }
1890
1891 /* Return a new unpacker for the given format. */
1892 static struct unpacker *
1893 struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
1894 {
1895 PyObject *structmodule; /* XXX cache these two */
1896 PyObject *Struct = NULL; /* XXX in globals? */
1897 PyObject *structobj = NULL;
1898 PyObject *format = NULL;
1899 struct unpacker *x = NULL;
1900
1901 structmodule = PyImport_ImportModule("struct");
1902 if (structmodule == NULL)
1903 return NULL;
1904
1905 Struct = PyObject_GetAttrString(structmodule, "Struct");
1906 Py_DECREF(structmodule);
1907 if (Struct == NULL)
1908 return NULL;
1909
1910 x = unpacker_new();
1911 if (x == NULL)
1912 goto error;
1913
1914 format = PyBytes_FromString(fmt);
1915 if (format == NULL)
1916 goto error;
1917
1918 structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
1919 if (structobj == NULL)
1920 goto error;
1921
1922 x->unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
1923 if (x->unpack_from == NULL)
1924 goto error;
1925
1926 x->item = PyMem_Malloc(itemsize);
1927 if (x->item == NULL) {
1928 PyErr_NoMemory();
1929 goto error;
1930 }
1931 x->itemsize = itemsize;
1932
1933 x->mview = PyMemoryView_FromMemory(x->item, itemsize, PyBUF_WRITE);
1934 if (x->mview == NULL)
1935 goto error;
1936
1937
1938 out:
1939 Py_XDECREF(Struct);
1940 Py_XDECREF(format);
1941 Py_XDECREF(structobj);
1942 return x;
1943
1944 error:
1945 unpacker_free(x);
1946 x = NULL;
1947 goto out;
1948 }
1949
1950 static PyObject *
1951 struct_unpack_single(const char *ptr, struct unpacker *x)
1952 {
1953 PyObject *v;
1954
1955 memcpy(x->item, ptr, x->itemsize);
1956 v = PyObject_CallFunctionObjArgs(x->unpack_from, x->mview, NULL);
1957 if (v == NULL)
1958 return NULL;
1959
1960 if (PyTuple_GET_SIZE(v) == 1) {
1961 PyObject *tmp = PyTuple_GET_ITEM(v, 0);
1962 Py_INCREF(tmp);
1963 Py_DECREF(v);
1964 return tmp;
1965 }
1966
1967 return v;
1968 }
1828 1969
1829 1970
1830 /****************************************************************************/ 1971 /****************************************************************************/
1831 /* Representations */ 1972 /* Representations */
1832 /****************************************************************************/ 1973 /****************************************************************************/
1833 1974
1834 /* allow explicit form of native format */ 1975 /* allow explicit form of native format */
1835 Py_LOCAL_INLINE(const char *) 1976 Py_LOCAL_INLINE(const char *)
1836 adjust_fmt(const Py_buffer *view) 1977 adjust_fmt(const Py_buffer *view)
1837 { 1978 {
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
2254 0, /* sq_concat */ 2395 0, /* sq_concat */
2255 0, /* sq_repeat */ 2396 0, /* sq_repeat */
2256 (ssizeargfunc)memory_item, /* sq_item */ 2397 (ssizeargfunc)memory_item, /* sq_item */
2257 }; 2398 };
2258 2399
2259 2400
2260 /**************************************************************************/ 2401 /**************************************************************************/
2261 /* Comparisons */ 2402 /* Comparisons */
2262 /**************************************************************************/ 2403 /**************************************************************************/
2263 2404
2405 #define MV_COMPARE_EX -1 /* exception */
2406 #define MV_COMPARE_NOT_IMPL -2 /* not implemented */
2407
2408 /* Translate a StructError to "not equal". Preserve other exceptions. */
2409 static int
2410 fix_struct_error_int(void)
2411 {
2412 assert(PyErr_Occurred());
2413 /* XXX Cannot get at StructError directly? */
2414 if (PyErr_ExceptionMatches(PyExc_ImportError) ||
2415 PyErr_ExceptionMatches(PyExc_MemoryError)) {
2416 return MV_COMPARE_EX;
2417 }
2418 /* StructError: invalid or unknown format -> not equal */
2419 PyErr_Clear();
2420 return 0;
2421 }
2422
2423 /* Unpack and compare single items of p and q using the struct module. */
2424 static int
2425 struct_unpack_cmp(const char *p, const char *q,
2426 struct unpacker *unpack_p, struct unpacker *unpack_q)
2427 {
2428 PyObject *v, *w;
2429 int ret;
2430
2431 /* At this point any exception from the struct module should not be
2432 StructError, since both formats have been accepted already. */
2433 v = struct_unpack_single(p, unpack_p);
2434 if (v == NULL)
2435 return MV_COMPARE_EX;
2436
2437 w = struct_unpack_single(q, unpack_q);
2438 if (w == NULL) {
2439 Py_DECREF(v);
2440 return MV_COMPARE_EX;
2441 }
2442
2443 /* MV_COMPARE_EX == -1: exceptions are preserved */
2444 ret = PyObject_RichCompareBool(v, w, Py_EQ);
2445 Py_DECREF(v);
2446 Py_DECREF(w);
2447
2448 return ret;
2449 }
2450
2451 /* Unpack and compare single items of p and q. If both p and q have the same
2452 single element native format, the comparison uses a fast path (gcc creates
2453 a jump table and converts memcpy into simple assignments on x86/x64).
2454
2455 Otherwise, the comparison is delegated to the struct module, which is
2456 30-60x slower. */
2264 #define CMP_SINGLE(p, q, type) \ 2457 #define CMP_SINGLE(p, q, type) \
2265 do { \ 2458 do { \
2266 type x; \ 2459 type x; \
2267 type y; \ 2460 type y; \
2268 memcpy((char *)&x, p, sizeof x); \ 2461 memcpy((char *)&x, p, sizeof x); \
2269 memcpy((char *)&y, q, sizeof y); \ 2462 memcpy((char *)&y, q, sizeof y); \
2270 equal = (x == y); \ 2463 equal = (x == y); \
2271 } while (0) 2464 } while (0)
2272 2465
2273 Py_LOCAL_INLINE(int) 2466 Py_LOCAL_INLINE(int)
2274 unpack_cmp(const char *p, const char *q, const char *fmt) 2467 unpack_cmp(const char *p, const char *q, char fmt,
2468 struct unpacker *unpack_p, struct unpacker *unpack_q)
2275 { 2469 {
2276 int equal; 2470 int equal;
2277 2471
2278 switch (fmt[0]) { 2472 switch (fmt) {
2279 2473
2280 /* signed integers and fast path for 'B' */ 2474 /* signed integers and fast path for 'B' */
2281 case 'B': return *((unsigned char *)p) == *((unsigned char *)q); 2475 case 'B': return *((unsigned char *)p) == *((unsigned char *)q);
2282 case 'b': return *((signed char *)p) == *((signed char *)q); 2476 case 'b': return *((signed char *)p) == *((signed char *)q);
2283 case 'h': CMP_SINGLE(p, q, short); return equal; 2477 case 'h': CMP_SINGLE(p, q, short); return equal;
2284 case 'i': CMP_SINGLE(p, q, int); return equal; 2478 case 'i': CMP_SINGLE(p, q, int); return equal;
2285 case 'l': CMP_SINGLE(p, q, long); return equal; 2479 case 'l': CMP_SINGLE(p, q, long); return equal;
2286 2480
2287 /* boolean */ 2481 /* boolean */
2288 #ifdef HAVE_C99_BOOL 2482 #ifdef HAVE_C99_BOOL
(...skipping 21 matching lines...) Expand all
2310 /* XXX DBL_EPSILON? */ 2504 /* XXX DBL_EPSILON? */
2311 case 'f': CMP_SINGLE(p, q, float); return equal; 2505 case 'f': CMP_SINGLE(p, q, float); return equal;
2312 case 'd': CMP_SINGLE(p, q, double); return equal; 2506 case 'd': CMP_SINGLE(p, q, double); return equal;
2313 2507
2314 /* bytes object */ 2508 /* bytes object */
2315 case 'c': return *p == *q; 2509 case 'c': return *p == *q;
2316 2510
2317 /* pointer */ 2511 /* pointer */
2318 case 'P': CMP_SINGLE(p, q, void *); return equal; 2512 case 'P': CMP_SINGLE(p, q, void *); return equal;
2319 2513
2320 /* Py_NotImplemented */ 2514 /* use the struct module */
2321 default: return -1; 2515 case '_':
2516 assert(unpack_p);
2517 assert(unpack_q);
2518 return struct_unpack_cmp(p, q, unpack_p, unpack_q);
2322 } 2519 }
2520
2521 /* NOT REACHED */
2522 PyErr_SetString(PyExc_RuntimeError,
2523 "memoryview: internal error in richcompare");
2524 return MV_COMPARE_EX;
2323 } 2525 }
2324 2526
2325 /* Base case for recursive array comparisons. Assumption: ndim == 1. */ 2527 /* Base case for recursive array comparisons. Assumption: ndim == 1. */
2326 static int 2528 static int
2327 cmp_base(const char *p, const char *q, const Py_ssize_t *shape, 2529 cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
2328 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2530 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2329 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2531 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2330 const char *fmt) 2532 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2331 { 2533 {
2332 Py_ssize_t i; 2534 Py_ssize_t i;
2333 int equal; 2535 int equal;
2334 2536
2335 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) { 2537 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2336 const char *xp = ADJUST_PTR(p, psuboffsets); 2538 const char *xp = ADJUST_PTR(p, psuboffsets);
2337 const char *xq = ADJUST_PTR(q, qsuboffsets); 2539 const char *xq = ADJUST_PTR(q, qsuboffsets);
2338 equal = unpack_cmp(xp, xq, fmt); 2540 equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
2339 if (equal <= 0) 2541 if (equal <= 0)
2340 return equal; 2542 return equal;
2341 } 2543 }
2342 2544
2343 return 1; 2545 return 1;
2344 } 2546 }
2345 2547
2346 /* Recursively compare two multi-dimensional arrays that have the same 2548 /* Recursively compare two multi-dimensional arrays that have the same
2347 logical structure. Assumption: ndim >= 1. */ 2549 logical structure. Assumption: ndim >= 1. */
2348 static int 2550 static int
2349 cmp_rec(const char *p, const char *q, 2551 cmp_rec(const char *p, const char *q,
2350 Py_ssize_t ndim, const Py_ssize_t *shape, 2552 Py_ssize_t ndim, const Py_ssize_t *shape,
2351 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, 2553 const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2352 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, 2554 const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2353 const char *fmt) 2555 char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2354 { 2556 {
2355 Py_ssize_t i; 2557 Py_ssize_t i;
2356 int equal; 2558 int equal;
2357 2559
2358 assert(ndim >= 1); 2560 assert(ndim >= 1);
2359 assert(shape != NULL); 2561 assert(shape != NULL);
2360 assert(pstrides != NULL); 2562 assert(pstrides != NULL);
2361 assert(qstrides != NULL); 2563 assert(qstrides != NULL);
2362 2564
2363 if (ndim == 1) { 2565 if (ndim == 1) {
2364 return cmp_base(p, q, shape, 2566 return cmp_base(p, q, shape,
2365 pstrides, psuboffsets, 2567 pstrides, psuboffsets,
2366 qstrides, qsuboffsets, 2568 qstrides, qsuboffsets,
2367 fmt); 2569 fmt, unpack_p, unpack_q);
2368 } 2570 }
2369 2571
2370 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) { 2572 for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2371 const char *xp = ADJUST_PTR(p, psuboffsets); 2573 const char *xp = ADJUST_PTR(p, psuboffsets);
2372 const char *xq = ADJUST_PTR(q, qsuboffsets); 2574 const char *xq = ADJUST_PTR(q, qsuboffsets);
2373 equal = cmp_rec(xp, xq, ndim-1, shape+1, 2575 equal = cmp_rec(xp, xq, ndim-1, shape+1,
2374 pstrides+1, psuboffsets ? psuboffsets+1 : NULL, 2576 pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
2375 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL, 2577 qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
2376 fmt); 2578 fmt, unpack_p, unpack_q);
2377 if (equal <= 0) 2579 if (equal <= 0)
2378 return equal; 2580 return equal;
2379 } 2581 }
2380 2582
2381 return 1; 2583 return 1;
2382 } 2584 }
2383 2585
2384 static PyObject * 2586 static PyObject *
2385 memory_richcompare(PyObject *v, PyObject *w, int op) 2587 memory_richcompare(PyObject *v, PyObject *w, int op)
2386 { 2588 {
2387 PyObject *res; 2589 PyObject *res;
2388 Py_buffer wbuf, *vv, *ww = NULL; 2590 Py_buffer wbuf, *vv;
2389 const char *vfmt, *wfmt; 2591 Py_buffer *ww = NULL;
2390 int equal = -1; /* Py_NotImplemented */ 2592 struct unpacker *unpack_v = NULL;
2593 struct unpacker *unpack_w = NULL;
2594 char vfmt, wfmt;
2595 int equal = MV_COMPARE_NOT_IMPL;
2391 2596
2392 if (op != Py_EQ && op != Py_NE) 2597 if (op != Py_EQ && op != Py_NE)
2393 goto result; /* Py_NotImplemented */ 2598 goto result; /* Py_NotImplemented */
2394 2599
2395 assert(PyMemoryView_Check(v)); 2600 assert(PyMemoryView_Check(v));
2396 if (BASE_INACCESSIBLE(v)) { 2601 if (BASE_INACCESSIBLE(v)) {
2397 equal = (v == w); 2602 equal = (v == w);
2398 goto result; 2603 goto result;
2399 } 2604 }
2400 vv = VIEW_ADDR(v); 2605 vv = VIEW_ADDR(v);
2401 2606
2402 if (PyMemoryView_Check(w)) { 2607 if (PyMemoryView_Check(w)) {
2403 if (BASE_INACCESSIBLE(w)) { 2608 if (BASE_INACCESSIBLE(w)) {
2404 equal = (v == w); 2609 equal = (v == w);
2405 goto result; 2610 goto result;
2406 } 2611 }
2407 ww = VIEW_ADDR(w); 2612 ww = VIEW_ADDR(w);
2408 } 2613 }
2409 else { 2614 else {
2410 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) { 2615 if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
2411 PyErr_Clear(); 2616 PyErr_Clear();
2412 goto result; /* Py_NotImplemented */ 2617 goto result; /* Py_NotImplemented */
2413 } 2618 }
2414 ww = &wbuf; 2619 ww = &wbuf;
2415 } 2620 }
2416 2621
2417 vfmt = adjust_fmt(vv); 2622 if (cmp_shape(vv, ww) < 0) {
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(); 2623 PyErr_Clear();
2426 equal = 0; 2624 equal = 0;
2427 goto result; 2625 goto result;
2428 } 2626 }
2429 2627
Nick Coghlan 2012/08/14 15:12:38 This is where I would have expected to see a fast
skrah 2012/08/14 16:31:58 The NaN test case wouldn't pass memcpy(). Also, Ma
Nick Coghlan 2012/08/15 06:13:09 A comment here explaining why a memcpy() fast path
skrah 2012/08/15 16:45:02 Also done.
2628 if (get_native_fmtchar(&vfmt, vv->format) < 0)
2629 vfmt = '_';
2630 if (get_native_fmtchar(&wfmt, ww->format) < 0)
2631 wfmt = '_';
2632 if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
2633 vfmt = '_';
2634 unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
2635 if (unpack_v == NULL) {
2636 equal = fix_struct_error_int();
2637 goto result;
2638 }
2639 unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
2640 if (unpack_w == NULL) {
2641 equal = fix_struct_error_int();
2642 goto result;
2643 }
2644 }
2645
2430 if (vv->ndim == 0) { 2646 if (vv->ndim == 0) {
2431 equal = unpack_cmp(vv->buf, ww->buf, vfmt); 2647 equal = unpack_cmp(vv->buf, ww->buf,
2648 vfmt, unpack_v, unpack_w);
2432 } 2649 }
2433 else if (vv->ndim == 1) { 2650 else if (vv->ndim == 1) {
2434 equal = cmp_base(vv->buf, ww->buf, vv->shape, 2651 equal = cmp_base(vv->buf, ww->buf, vv->shape,
2435 vv->strides, vv->suboffsets, 2652 vv->strides, vv->suboffsets,
2436 ww->strides, ww->suboffsets, 2653 ww->strides, ww->suboffsets,
2437 vfmt); 2654 vfmt, unpack_v, unpack_w);
2438 } 2655 }
2439 else { 2656 else {
2440 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape, 2657 equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
2441 vv->strides, vv->suboffsets, 2658 vv->strides, vv->suboffsets,
2442 ww->strides, ww->suboffsets, 2659 ww->strides, ww->suboffsets,
2443 vfmt); 2660 vfmt, unpack_v, unpack_w);
2444 } 2661 }
2445 2662
2446 result: 2663 result:
2447 if (equal < 0) 2664 if (equal < 0) {
2448 res = Py_NotImplemented; 2665 if (equal == MV_COMPARE_NOT_IMPL)
2666 res = Py_NotImplemented;
2667 else /* exception */
2668 res = NULL;
2669 }
2449 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) 2670 else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
2450 res = Py_True; 2671 res = Py_True;
2451 else 2672 else
2452 res = Py_False; 2673 res = Py_False;
2453 2674
2454 if (ww == &wbuf) 2675 if (ww == &wbuf)
2455 PyBuffer_Release(ww); 2676 PyBuffer_Release(ww);
2456 Py_INCREF(res); 2677
2678 unpacker_free(unpack_v);
2679 unpacker_free(unpack_w);
2680
2681 Py_XINCREF(res);
2457 return res; 2682 return res;
2458 } 2683 }
2459 2684
2460 /**************************************************************************/ 2685 /**************************************************************************/
2461 /* Hash */ 2686 /* Hash */
2462 /**************************************************************************/ 2687 /**************************************************************************/
2463 2688
2464 static Py_hash_t 2689 static Py_hash_t
2465 memory_hash(PyMemoryViewObject *self) 2690 memory_hash(PyMemoryViewObject *self)
2466 { 2691 {
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
2682 memory_getsetlist, /* tp_getset */ 2907 memory_getsetlist, /* tp_getset */
2683 0, /* tp_base */ 2908 0, /* tp_base */
2684 0, /* tp_dict */ 2909 0, /* tp_dict */
2685 0, /* tp_descr_get */ 2910 0, /* tp_descr_get */
2686 0, /* tp_descr_set */ 2911 0, /* tp_descr_set */
2687 0, /* tp_dictoffset */ 2912 0, /* tp_dictoffset */
2688 0, /* tp_init */ 2913 0, /* tp_init */
2689 0, /* tp_alloc */ 2914 0, /* tp_alloc */
2690 memory_new, /* tp_new */ 2915 memory_new, /* tp_new */
2691 }; 2916 };
OLDNEW
« Doc/whatsnew/3.3.rst ('K') | « Lib/test/test_buffer.py ('k') | no next file » | no next file with comments »

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