1
#define PY_SSIZE_T_CLEAN
3
#define _MULTIARRAYMODULE
4
#include <numpy/ndarrayobject.h>
6
#include "npy_config.h"
11
* How does this work ? The hash is computed from a list which contains all the
12
* information specific to a type. The hard work is to build the list
13
* (_array_descr_walk). The list is built as follows:
14
* * If the dtype is builtin (no fields, no subarray), then the list
15
* contains 6 items which uniquely define one dtype (_array_descr_builtin)
16
* * If the dtype is a compound array, one walk on each field. For each
17
* field, we append title, names, offset to the final list used for
18
* hashing, and then append the list recursively built for each
19
* corresponding dtype (_array_descr_walk_fields)
20
* * If the dtype is a subarray, one adds the shape tuple to the list, and
21
* then append the list recursively built for each corresponding dtype
22
* (_array_descr_walk_subarray)
26
static int _is_array_descr_builtin(PyArray_Descr* descr);
27
static int _array_descr_walk(PyArray_Descr* descr, PyObject *l);
28
static int _array_descr_walk_fields(PyObject* fields, PyObject* l);
29
static int _array_descr_builtin(PyArray_Descr* descr, PyObject *l);
32
* Return true if descr is a builtin type
34
static int _is_array_descr_builtin(PyArray_Descr* descr)
36
if (descr->fields != NULL && descr->fields != Py_None) {
39
if (descr->subarray != NULL) {
46
* Add to l all the items which uniquely define a builtin type
48
static int _array_descr_builtin(PyArray_Descr* descr, PyObject *l)
54
* For builtin type, hash relies on : kind + byteorder + hasobject +
55
* type_num + elsize + alignment
57
t = Py_BuildValue("(ccciii)", descr->kind, descr->byteorder,
58
descr->hasobject, descr->type_num, descr->elsize,
61
for(i = 0; i < PyTuple_Size(t); ++i) {
62
item = PyTuple_GetItem(t, i);
64
PyErr_SetString(PyExc_SystemError,
65
"(Hash) Error while computing builting hash");
69
PyList_Append(l, item);
81
* Walk inside the fields and add every item which will be used for hashing
86
static int _array_descr_walk_fields(PyObject* fields, PyObject* l)
88
PyObject *key, *value, *foffset, *fdescr;
92
while (PyDict_Next(fields, &pos, &key, &value)) {
94
* For each field, add the key + descr + offset to l
97
/* XXX: are those checks necessary ? */
98
if (!PyString_Check(key)) {
99
PyErr_SetString(PyExc_SystemError,
100
"(Hash) key of dtype dict not a string ???");
103
if (!PyTuple_Check(value)) {
104
PyErr_SetString(PyExc_SystemError,
105
"(Hash) value of dtype dict not a dtype ???");
108
if (PyTuple_Size(value) < 2) {
109
PyErr_SetString(PyExc_SystemError,
110
"(Hash) Less than 2 items in dtype dict ???");
114
PyList_Append(l, key);
116
fdescr = PyTuple_GetItem(value, 0);
117
if (!PyArray_DescrCheck(fdescr)) {
118
PyErr_SetString(PyExc_SystemError,
119
"(Hash) First item in compound dtype tuple not a descr ???");
123
st = _array_descr_walk((PyArray_Descr*)fdescr, l);
130
foffset = PyTuple_GetItem(value, 1);
131
if (!PyInt_Check(foffset)) {
132
PyErr_SetString(PyExc_SystemError,
133
"(Hash) Second item in compound dtype tuple not an int ???");
137
PyList_Append(l, foffset);
145
* Walk into subarray, and add items for hashing in l
147
* Return 0 on success
149
static int _array_descr_walk_subarray(PyArray_ArrayDescr* adescr, PyObject *l)
156
* Add shape and descr itself to the list of object to hash
158
if (PyTuple_Check(adescr->shape)) {
159
for(i = 0; i < PyTuple_Size(adescr->shape); ++i) {
160
item = PyTuple_GetItem(adescr->shape, i);
162
PyErr_SetString(PyExc_SystemError,
163
"(Hash) Error while getting shape item of subarray dtype ???");
167
PyList_Append(l, item);
169
} else if (PyInt_Check(adescr->shape)) {
170
Py_INCREF(adescr->shape);
171
PyList_Append(l, adescr->shape);
173
PyErr_SetString(PyExc_SystemError,
174
"(Hash) Shape of subarray dtype neither a tuple or int ???");
178
Py_INCREF(adescr->base);
179
st = _array_descr_walk(adescr->base, l);
180
Py_DECREF(adescr->base);
186
* 'Root' function to walk into a dtype. May be called recursively
188
static int _array_descr_walk(PyArray_Descr* descr, PyObject *l)
192
if (_is_array_descr_builtin(descr)) {
193
return _array_descr_builtin(descr, l);
195
if(descr->fields != NULL && descr->fields != Py_None) {
196
if (!PyDict_Check(descr->fields)) {
197
PyErr_SetString(PyExc_SystemError,
198
"(Hash) fields is not a dict ???");
201
st = _array_descr_walk_fields(descr->fields, l);
206
if(descr->subarray != NULL) {
207
st = _array_descr_walk_subarray(descr->subarray, l);
218
* Return 0 if successfull
220
static int _PyArray_DescrHashImp(PyArray_Descr *descr, long *hash)
222
PyObject *l, *tl, *item;
231
st = _array_descr_walk(descr, l);
237
* Convert the list to tuple and compute the tuple hash using python
240
tl = PyTuple_New(PyList_Size(l));
241
for(i = 0; i < PyList_Size(l); ++i) {
242
item = PyList_GetItem(l, i);
244
PyErr_SetString(PyExc_SystemError,
245
"(Hash) Error while translating the list into a tuple " \
249
PyTuple_SetItem(tl, i, item);
252
*hash = PyObject_Hash(tl);
254
/* XXX: does PyObject_Hash set an exception on failure ? */
256
PyErr_SetString(PyExc_SystemError,
257
"(Hash) Error while hashing final tuple");
274
PyArray_DescrHash(PyObject* odescr)
276
PyArray_Descr *descr;
280
if (!PyArray_DescrCheck(odescr)) {
281
PyErr_SetString(PyExc_ValueError,
282
"PyArray_DescrHash argument must be a type descriptor");
285
descr = (PyArray_Descr*)odescr;
287
st = _PyArray_DescrHashImp(descr, &hash);