PageRenderTime 75ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/libndarray/src/npy_arrayobject.c

http://github.com/teoliphant/numpy-refactor
C | 542 lines | 411 code | 57 blank | 74 comment | 96 complexity | b82c09d3ab7dfe2814cfc33274f9cf7a MD5 | raw file
  1. /* npy_arrayobject.c */
  2. #include <stdlib.h>
  3. #include "npy_config.h"
  4. #include "npy_api.h"
  5. #include "npy_arrayobject.h"
  6. #include "npy_iterators.h"
  7. #include "npy_internal.h"
  8. /* TODO: Make these into interface functions */
  9. extern int PyArray_INCREF(void *);
  10. extern int PyArray_XDECREF(void *);
  11. /*
  12. * Compute the size of an array (in number of items)
  13. */
  14. NDARRAY_API npy_intp
  15. NpyArray_Size(NpyArray *op)
  16. {
  17. return NpyArray_SIZE(op);
  18. }
  19. NDARRAY_API int
  20. NpyArray_CompareUCS4(npy_ucs4 *s1, npy_ucs4 *s2, size_t len)
  21. {
  22. npy_ucs4 c1, c2;
  23. while(len-- > 0) {
  24. c1 = *s1++;
  25. c2 = *s2++;
  26. if (c1 != c2) {
  27. return (c1 < c2) ? -1 : 1;
  28. }
  29. }
  30. return 0;
  31. }
  32. NDARRAY_API int
  33. NpyArray_CompareString(char *s1, char *s2, size_t len)
  34. {
  35. const unsigned char *c1 = (unsigned char *)s1;
  36. const unsigned char *c2 = (unsigned char *)s2;
  37. size_t i;
  38. for(i = 0; i < len; ++i) {
  39. if (c1[i] != c2[i]) {
  40. return (c1[i] > c2[i]) ? 1 : -1;
  41. }
  42. }
  43. return 0;
  44. }
  45. NDARRAY_API int
  46. NpyArray_ElementStrides(NpyArray *arr)
  47. {
  48. int itemsize = NpyArray_ITEMSIZE(arr);
  49. int i, N = NpyArray_NDIM(arr);
  50. npy_intp *strides = NpyArray_STRIDES(arr);
  51. for (i = 0; i < N; i++) {
  52. if ((strides[i] % itemsize) != 0) {
  53. return 0;
  54. }
  55. }
  56. return 1;
  57. }
  58. /*
  59. * This routine checks to see if newstrides (of length nd) will not
  60. * ever be able to walk outside of the memory implied numbytes and offset.
  61. *
  62. * The available memory is assumed to start at -offset and proceed
  63. * to numbytes-offset. The strides are checked to ensure
  64. * that accessing memory using striding will not try to reach beyond
  65. * this memory for any of the axes.
  66. *
  67. * If numbytes is 0 it will be calculated using the dimensions and
  68. * element-size.
  69. *
  70. * This function checks for walking beyond the beginning and right-end
  71. * of the buffer and therefore works for any integer stride (positive
  72. * or negative).
  73. */
  74. NDARRAY_API npy_bool
  75. NpyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp offset,
  76. npy_intp *dims, npy_intp *newstrides)
  77. {
  78. int i;
  79. npy_intp byte_begin;
  80. npy_intp begin;
  81. npy_intp end;
  82. if (numbytes == 0) {
  83. numbytes = NpyArray_MultiplyList(dims, nd) * elsize;
  84. }
  85. begin = -offset;
  86. end = numbytes - offset - elsize;
  87. for (i = 0; i < nd; i++) {
  88. byte_begin = newstrides[i]*(dims[i] - 1);
  89. if ((byte_begin < begin) || (byte_begin > end)) {
  90. return NPY_FALSE;
  91. }
  92. }
  93. return NPY_TRUE;
  94. }
  95. NDARRAY_API void
  96. NpyArray_ForceUpdate(NpyArray* self)
  97. {
  98. if ((self->flags&NPY_UPDATEIFCOPY) && self->base_arr != NULL) {
  99. /*
  100. * UPDATEIFCOPY means that base points to an
  101. * array that should be updated with the contents
  102. * of this array upon destruction.
  103. * self->base->flags must have been WRITEABLE
  104. * (checked previously) and it was locked here
  105. * thus, unlock it.
  106. */
  107. if (self->flags & NPY_UPDATEIFCOPY) {
  108. self->flags &= ~NPY_UPDATEIFCOPY;
  109. self->base_arr->flags |= NPY_WRITEABLE;
  110. Npy_INCREF(self); /* hold on to self in next call */
  111. if (NpyArray_CopyAnyInto(self->base_arr, self) < 0) {
  112. /* NpyErr_Print(); */
  113. NpyErr_Clear();
  114. }
  115. Npy_DECREF(self);
  116. Npy_DECREF(self->base_arr);
  117. self->base_arr = NULL;
  118. }
  119. }
  120. }
  121. /* This also handles possibly mis-aligned data */
  122. /* Compare s1 and s2 which are not necessarily NULL-terminated.
  123. s1 is of length len1
  124. s2 is of length len2
  125. If they are NULL terminated, then stop comparison.
  126. */
  127. static int
  128. _myunincmp(NpyArray_UCS4 *s1, NpyArray_UCS4 *s2, int len1, int len2)
  129. {
  130. NpyArray_UCS4 *sptr;
  131. NpyArray_UCS4 *s1t=s1, *s2t=s2;
  132. int val;
  133. npy_intp size;
  134. int diff;
  135. if ((npy_intp)s1 % sizeof(NpyArray_UCS4) != 0) {
  136. size = len1*sizeof(NpyArray_UCS4);
  137. s1t = malloc(size);
  138. memcpy(s1t, s1, size);
  139. }
  140. if ((npy_intp)s2 % sizeof(NpyArray_UCS4) != 0) {
  141. size = len2*sizeof(NpyArray_UCS4);
  142. s2t = malloc(size);
  143. memcpy(s2t, s2, size);
  144. }
  145. val = NpyArray_CompareUCS4(s1t, s2t, NpyArray_MIN(len1,len2));
  146. if ((val != 0) || (len1 == len2)) {
  147. goto finish;
  148. }
  149. if (len2 > len1) {
  150. sptr = s2t+len1;
  151. val = -1;
  152. diff = len2-len1;
  153. }
  154. else {
  155. sptr = s1t+len2;
  156. val = 1;
  157. diff=len1-len2;
  158. }
  159. while (diff--) {
  160. if (*sptr != 0) {
  161. goto finish;
  162. }
  163. sptr++;
  164. }
  165. val = 0;
  166. finish:
  167. if (s1t != s1) {
  168. free(s1t);
  169. }
  170. if (s2t != s2) {
  171. free(s2t);
  172. }
  173. return val;
  174. }
  175. /*
  176. * Compare s1 and s2 which are not necessarily NULL-terminated.
  177. * s1 is of length len1
  178. * s2 is of length len2
  179. * If they are NULL terminated, then stop comparison.
  180. */
  181. static int
  182. _mystrncmp(char *s1, char *s2, int len1, int len2)
  183. {
  184. char *sptr;
  185. int val;
  186. int diff;
  187. val = memcmp(s1, s2, NpyArray_MIN(len1, len2));
  188. if ((val != 0) || (len1 == len2)) {
  189. return val;
  190. }
  191. if (len2 > len1) {
  192. sptr = s2 + len1;
  193. val = -1;
  194. diff = len2 - len1;
  195. }
  196. else {
  197. sptr = s1 + len2;
  198. val = 1;
  199. diff = len1 - len2;
  200. }
  201. while (diff--) {
  202. if (*sptr != 0) {
  203. return val;
  204. }
  205. sptr++;
  206. }
  207. return 0; /* Only happens if NULLs are everywhere */
  208. }
  209. /* Borrowed from Numarray */
  210. #define SMALL_STRING 2048
  211. #if defined(isspace)
  212. #undef isspace
  213. #define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')||(c=='\v')||(c=='\f'))
  214. #endif
  215. static void _rstripw(char *s, int n)
  216. {
  217. int i;
  218. for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */
  219. int c = s[i];
  220. if (!c || isspace(c)) {
  221. s[i] = 0;
  222. }
  223. else {
  224. break;
  225. }
  226. }
  227. }
  228. static void _unistripw(NpyArray_UCS4 *s, int n)
  229. {
  230. int i;
  231. for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */
  232. NpyArray_UCS4 c = s[i];
  233. if (!c || isspace(c)) {
  234. s[i] = 0;
  235. }
  236. else {
  237. break;
  238. }
  239. }
  240. }
  241. static char *
  242. _char_copy_n_strip(char *original, char *temp, int nc)
  243. {
  244. if (nc > SMALL_STRING) {
  245. temp = (char*)malloc(nc);
  246. if (!temp) {
  247. NpyErr_MEMORY;
  248. return NULL;
  249. }
  250. }
  251. memcpy(temp, original, nc);
  252. _rstripw(temp, nc);
  253. return temp;
  254. }
  255. static void
  256. _char_release(char *ptr, int nc)
  257. {
  258. if (nc > SMALL_STRING) {
  259. free(ptr);
  260. }
  261. }
  262. static char *
  263. _uni_copy_n_strip(char *original, char *temp, int nc)
  264. {
  265. if (nc*sizeof(NpyArray_UCS4) > SMALL_STRING) {
  266. temp = (char*)malloc(nc*sizeof(NpyArray_UCS4));
  267. if (!temp) {
  268. NpyErr_MEMORY;
  269. return NULL;
  270. }
  271. }
  272. memcpy(temp, original, nc*sizeof(NpyArray_UCS4));
  273. _unistripw((NpyArray_UCS4 *)temp, nc);
  274. return temp;
  275. }
  276. static void
  277. _uni_release(char *ptr, int nc)
  278. {
  279. if (nc*sizeof(NpyArray_UCS4) > SMALL_STRING) {
  280. free(ptr);
  281. }
  282. }
  283. /* End borrowed from numarray */
  284. #define _rstrip_loop(CMP) { \
  285. void *aptr, *bptr; \
  286. char atemp[SMALL_STRING], btemp[SMALL_STRING]; \
  287. while(size--) { \
  288. aptr = stripfunc(iself->dataptr, atemp, N1); \
  289. if (!aptr) return -1; \
  290. bptr = stripfunc(iother->dataptr, btemp, N2); \
  291. if (!bptr) { \
  292. relfunc(aptr, N1); \
  293. return -1; \
  294. } \
  295. val = cmpfunc(aptr, bptr, N1, N2); \
  296. *dptr = (val CMP 0); \
  297. NpyArray_ITER_NEXT(iself); \
  298. NpyArray_ITER_NEXT(iother); \
  299. dptr += 1; \
  300. relfunc(aptr, N1); \
  301. relfunc(bptr, N2); \
  302. } \
  303. }
  304. #define _reg_loop(CMP) { \
  305. while(size--) { \
  306. val = cmpfunc((void *)iself->dataptr, \
  307. (void *)iother->dataptr, \
  308. N1, N2); \
  309. *dptr = (val CMP 0); \
  310. NpyArray_ITER_NEXT(iself); \
  311. NpyArray_ITER_NEXT(iother); \
  312. dptr += 1; \
  313. } \
  314. }
  315. #define _loop(CMP) if (rstrip) _rstrip_loop(CMP) \
  316. else _reg_loop(CMP)
  317. static int
  318. _compare_strings(NpyArray *result, NpyArrayMultiIterObject *multi,
  319. int cmp_op, void *func, int rstrip)
  320. {
  321. NpyArrayIterObject *iself, *iother;
  322. npy_bool *dptr;
  323. npy_intp size;
  324. int val;
  325. int N1, N2;
  326. int (*cmpfunc)(void *, void *, int, int);
  327. void (*relfunc)(char *, int);
  328. char* (*stripfunc)(char *, char *, int);
  329. cmpfunc = func;
  330. dptr = (npy_bool *)NpyArray_DATA(result);
  331. iself = multi->iters[0];
  332. iother = multi->iters[1];
  333. size = multi->size;
  334. N1 = iself->ao->descr->elsize;
  335. N2 = iother->ao->descr->elsize;
  336. if ((void *)cmpfunc == (void *)_myunincmp) {
  337. N1 >>= 2;
  338. N2 >>= 2;
  339. stripfunc = _uni_copy_n_strip;
  340. relfunc = _uni_release;
  341. }
  342. else {
  343. stripfunc = _char_copy_n_strip;
  344. relfunc = _char_release;
  345. }
  346. switch (cmp_op) {
  347. case NPY_EQ:
  348. _loop(==)
  349. break;
  350. case NPY_NE:
  351. _loop(!=)
  352. break;
  353. case NPY_LT:
  354. _loop(<)
  355. break;
  356. case NPY_LE:
  357. _loop(<=)
  358. break;
  359. case NPY_GT:
  360. _loop(>)
  361. break;
  362. case NPY_GE:
  363. _loop(>=)
  364. break;
  365. default:
  366. NpyErr_SetString(NpyExc_RuntimeError, "bad comparison operator");
  367. return -1;
  368. }
  369. return 0;
  370. }
  371. #undef _loop
  372. #undef _reg_loop
  373. #undef _rstrip_loop
  374. #undef SMALL_STRING
  375. NDARRAY_API NpyArray*
  376. NpyArray_CompareStringArrays(NpyArray* a1, NpyArray* a2, int cmp_op, int rstrip)
  377. {
  378. NpyArray* result;
  379. int val;
  380. NpyArrayMultiIterObject* mit;
  381. int t1 = NpyArray_TYPE(a1);
  382. int t2 = NpyArray_TYPE(a2);
  383. if (NpyArray_TYPE(a1) != NpyArray_TYPE(a2) ||
  384. (t1 != NPY_UNICODE && t1 != NPY_STRING && t1 != NPY_VOID)) {
  385. NpyErr_SetString(NpyExc_ValueError,
  386. "Arrays must be of the same string type.");
  387. return NULL;
  388. }
  389. /* Broad-cast the arrays to a common shape */
  390. mit = NpyArray_MultiIterFromArrays(NULL, 0, 2, a1, a2);
  391. if (mit == NULL) {
  392. return NULL;
  393. }
  394. result = NpyArray_NewFromDescr(NpyArray_DescrFromType(NPY_BOOL),
  395. mit->nd,
  396. mit->dimensions, NULL,
  397. NULL, 0, NPY_TRUE, NULL, NULL);
  398. if (result == NULL) {
  399. goto finish;
  400. }
  401. if (t1 == NPY_UNICODE) {
  402. val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip);
  403. }
  404. else {
  405. val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip);
  406. }
  407. if (val < 0) {
  408. Npy_DECREF(result);
  409. result = NULL;
  410. }
  411. finish:
  412. Npy_DECREF(mit);
  413. return result;
  414. }
  415. /* Deallocs & destroy's the array object.
  416. * Returns whether or not we did an artificial incref
  417. * so we can keep track of the total refcount for debugging.
  418. */
  419. /* TODO: For now caller is expected to call _array_dealloc_buffer_info
  420. and clear weak refs. Need to revisit. */
  421. NDARRAY_API int
  422. NpyArray_dealloc(NpyArray *self)
  423. {
  424. int result = 0;
  425. assert(NPY_VALID_MAGIC == self->nob_magic_number);
  426. assert(NULL == self->base_arr ||
  427. NPY_VALID_MAGIC == self->base_arr->nob_magic_number);
  428. if (self->base_arr) {
  429. /*
  430. * UPDATEIFCOPY means that base points to an
  431. * array that should be updated with the contents
  432. * of this array upon destruction.
  433. * self->base->flags must have been WRITEABLE
  434. * (checked previously) and it was locked here
  435. * thus, unlock it.
  436. */
  437. if (self->flags & NPY_UPDATEIFCOPY) {
  438. self->base_arr->flags |= NPY_WRITEABLE;
  439. Npy_INCREF(self); /* hold on to self in next call */
  440. if (NpyArray_CopyAnyInto(self->base_arr, self) < 0) {
  441. /* NpyErr_Print(); */
  442. NpyErr_Clear();
  443. }
  444. /*
  445. * Don't need to DECREF -- because we are deleting
  446. *self already...
  447. */
  448. result = 1;
  449. }
  450. /*
  451. * In any case base is pointing to something that we need
  452. * to DECREF -- either a view or a buffer object
  453. */
  454. Npy_DECREF(self->base_arr);
  455. self->base_arr = NULL;
  456. } else if (NULL != self->base_obj) {
  457. NpyInterface_DECREF(self->base_obj);
  458. self->base_obj = NULL;
  459. }
  460. if ((self->flags & NPY_OWNDATA) && self->data) {
  461. /* Free internal references if an Object array */
  462. if (NpyDataType_FLAGCHK(self->descr, NPY_ITEM_REFCOUNT)) {
  463. Npy_INCREF(self); /* hold on to self in next call */
  464. NpyArray_XDECREF(self);
  465. /*
  466. * Don't need to DECREF -- because we are deleting
  467. * self already...
  468. */
  469. if (self->nob_refcnt == 1) {
  470. result = 1;
  471. }
  472. }
  473. NpyDataMem_FREE(self->data);
  474. }
  475. NpyDimMem_FREE(self->dimensions);
  476. Npy_DECREF(self->descr);
  477. /* Flag that this object is now deallocated. */
  478. self->nob_magic_number = NPY_INVALID_MAGIC;
  479. NpyArray_free(self);
  480. return result;
  481. }
  482. NpyTypeObject NpyArray_Type = {
  483. (npy_destructor)NpyArray_dealloc,
  484. NULL
  485. };