comparison PyTypeInterface.h @ 37:27bab3a16c9a vampy2final

new branch Vampy2final
author fazekasgy
date Mon, 05 Oct 2009 11:28:00 +0000
parents
children 8b2eddf686da
comparison
equal deleted inserted replaced
-1:000000000000 37:27bab3a16c9a
1 /*
2
3 * Vampy : This plugin is a wrapper around the Vamp plugin API.
4 * It allows for writing Vamp plugins in Python.
5
6 * Centre for Digital Music, Queen Mary University of London.
7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
8 * for licence information.)
9
10 */
11
12 /*
13 PyTypeInterface: Type safe conversion utilities between Python types
14 and basic C/C++ types and Vamp API types.
15 */
16
17 #ifndef _PY_TYPE_INTERFACE_H_
18 #define _PY_TYPE_INTERFACE_H_
19 #include <Python.h>
20 #ifdef HAVE_NUMPY
21 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
22 #define NO_IMPORT_ARRAY
23 #include "numpy/arrayobject.h"
24 #endif
25 #include "PyExtensionModule.h"
26 #include <vector>
27 #include <queue>
28 #include <string>
29 #include <sstream>
30 #include "vamp-sdk/Plugin.h"
31
32 using std::cerr;
33 using std::endl;
34
35 #ifdef HAVE_NUMPY
36 enum eArrayDataType {
37 dtype_float32 = (int) NPY_FLOAT,
38 dtype_complex64 = (int) NPY_CFLOAT
39 };
40 #endif
41
42 namespace o {
43 enum eOutDescriptors {
44 not_found,
45 identifier,
46 name,
47 description,
48 unit,
49 hasFixedBinCount,
50 binCount,
51 binNames,
52 hasKnownExtents,
53 minValue,
54 maxValue,
55 isQuantized,
56 quantizeStep,
57 sampleType,
58 sampleRate,
59 hasDuration,
60 endNode
61 };
62 }
63
64 namespace p {
65 enum eParmDescriptors {
66 not_found,
67 identifier,
68 name,
69 description,
70 unit,
71 minValue,
72 maxValue,
73 defaultValue,
74 isQuantized,
75 quantizeStep
76 };
77 }
78
79 enum eSampleTypes {
80 OneSamplePerStep,
81 FixedSampleRate,
82 VariableSampleRate
83 };
84
85 enum eFeatureFields {
86 unknown,
87 hasTimestamp,
88 timestamp,
89 hasDuration,
90 duration,
91 values,
92 label
93 };
94
95 /* C++ mapping of PyNone Type */
96 struct NoneType {};
97
98 class PyTypeInterface
99 {
100 public:
101 PyTypeInterface();
102 ~PyTypeInterface();
103
104 // Data
105 class ValueError
106 {
107 public:
108 ValueError() {}
109 ValueError(std::string m, bool s) : message(m),strict(s) {}
110 std::string location;
111 std::string message;
112 bool strict;
113 std::string str() const {
114 return (location.empty()) ? message : message + "\nLocation: " + location;}
115 void print() const { cerr << str() << endl; }
116 template<typename V> ValueError &operator<< (const V& v)
117 {
118 std::ostringstream ss;
119 ss << v;
120 location += ss.str();
121 return *this;
122 }
123 };
124
125 // Utilities
126 void setStrictTypingFlag(bool b) {m_strict = b;}
127 ValueError getError() const;
128 std::string PyValue_Get_TypeName(PyObject*) const;
129 bool initMaps() const;
130
131 // Basic type conversion: Python to C++
132 float PyValue_To_Float(PyObject*) const;
133 size_t PyValue_To_Size_t(PyObject*) const;
134 bool PyValue_To_Bool(PyObject*) const;
135 std::string PyValue_To_String(PyObject*) const;
136 long PyValue_To_Long(PyObject*) const;
137 // int PyValue_To_Int(PyObject* pyValue) const;
138
139
140 // C++ to Python
141 PyObject *PyValue_From_CValue(const char*) const;
142 PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
143 PyObject *PyValue_From_CValue(size_t) const;
144 PyObject *PyValue_From_CValue(double) const;
145 PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
146 PyObject *PyValue_From_CValue(bool) const;
147
148 // Sequence types
149 std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
150 std::vector<float> PyValue_To_FloatVector (PyObject*) const;
151 std::vector<float> PyList_To_FloatVector (PyObject*) const;
152
153 // Input buffers to Python
154 PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype);
155 PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize);
156
157 // Numpy types
158 #ifdef HAVE_NUMPY
159 std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const;
160 PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype);
161 #endif
162
163
164
165
166 /* Template functions */
167
168
169 /// Common wrappers to set values in Vamp API structs. (to be used in template functions)
170 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const;
171 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const;
172 bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const;
173 PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const
174 {
175 if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue);
176 if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue);
177 if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue);
178 return NULL;
179 }
180
181 //returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature
182 template<typename RET>
183 RET PyValue_To_VampDescriptor(PyObject* pyValue) const
184 {
185 PyObject* pyDict;
186
187 // Descriptors encoded as dicts
188 pyDict = GetDescriptor_As_Dict(pyValue);
189 if (!pyDict) pyDict = pyValue;
190
191 // TODO: support full mapping protocol as fallback.
192 if (!PyDict_Check(pyDict)) {
193 setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict);
194 #ifdef _DEBUG
195 cerr << "PyTypeInterface::PyValue_To_VampDescriptor failed. Error: Unexpected return type." << endl;
196 #endif
197 return RET();
198 }
199
200 Py_ssize_t pyPos = 0;
201 PyObject *pyKey, *pyDictValue;
202 initMaps();
203 int errors = 0;
204 m_error = false;
205 RET rd;
206
207 //Python Dictionary Iterator:
208 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
209 {
210 std::string key = PyValue_To_String(pyKey);
211 #ifdef _DEBUG_VALUES
212 cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
213 #endif
214 SetValue(rd,key,pyDictValue);
215 if (m_error) {
216 errors++;
217 lastError() << "attribute '" << key << "'";// << " of " << getDescriptorId(rd);
218 }
219 }
220 if (errors) {
221 lastError() << " of " << getDescriptorId(rd);
222 m_error = true;
223 #ifdef _DEBUG
224 cerr << "PyTypeInterface::PyValue_To_VampDescriptor: Warning: Value error in descriptor." << endl;
225 #endif
226 }
227 return rd;
228 }
229
230 /// Convert a sequence (tipically list) of PySomething to
231 /// OutputList,ParameterList or FeatureList
232 /// <OutputList> <OutputDescriptor>
233 template<typename RET,typename ELEM>
234 RET PyValue_To_VampList(PyObject* pyValue) const
235 {
236 RET list; // e.g. Vamp::Plugin::OutputList
237 ELEM element; // e.g. Vamp::Plugin::OutputDescriptor
238
239 /// convert lists (ParameterList, OutputList, FeatureList)
240 if (PyList_Check(pyValue)) {
241 PyObject *pyDict; //This reference will be borrowed
242 m_error = false; int errors = 0;
243 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
244 //Get i-th Vamp output descriptor (Borrowed Reference)
245 pyDict = PyList_GET_ITEM(pyValue,i);
246 element = PyValue_To_VampDescriptor<ELEM>(pyDict);
247 if (m_error) errors++;
248 // Check for empty Feature/Descriptor as before?
249 list.push_back(element);
250 }
251 if (errors) m_error=true;
252 return list;
253 }
254
255 /// convert other types implementing the sequence protocol
256 if (PySequence_Check(pyValue)) {
257 PyObject *pySequence = PySequence_Fast(pyValue,"Returned value can not be converted to list or tuple.");
258 PyObject **pyElements = PySequence_Fast_ITEMS(pySequence);
259 m_error = false; int errors = 0;
260 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(pySequence); ++i)
261 {
262 element = PyValue_To_VampDescriptor<ELEM>(pyElements[i]);
263 if (m_error) errors++;
264 list.push_back(element);
265 }
266 if (errors) m_error=true;
267 Py_XDECREF(pySequence);
268 return list;
269 }
270
271 // accept None as an empty list
272 if (pyValue == Py_None) return list;
273
274 // in strict mode, returning a single value is not allowed
275 if (m_strict) {
276 setValueError("Strict conversion error: object is not list or iterable sequence.",m_strict);
277 return list;
278 }
279
280 /// try to insert single, non-iterable values. i.e. feature <- [feature]
281 element = PyValue_To_VampDescriptor<ELEM>(pyValue);
282 if (m_error) {
283 setValueError("Could not insert returned value to Vamp List.",m_strict);
284 return list;
285 }
286 list.push_back(element);
287 return list;
288
289 #ifdef _DEBUG
290 cerr << "PyTypeInterface::PyValue_To_VampList failed. Expected iterable return type." << endl;
291 #endif
292
293 }
294
295 /// Convert DTYPE type 1D NumpyArray to std::vector<RET>
296 template<typename RET, typename DTYPE>
297 std::vector<RET> PyArray_Convert(char* raw_data_ptr, long length, size_t strides) const
298 {
299 std::vector<RET> rValue;
300
301 /// check if the array is continuous, if not use strides info
302 if (sizeof(DTYPE)!=strides) {
303 #ifdef _DEBUG_VALUES
304 cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl;
305 #endif
306 char* data = (char*) raw_data_ptr;
307 for (long i = 0; i<length; ++i){
308 rValue.push_back((RET)(*((DTYPE*)data)));
309 #ifdef _DEBUG_VALUES
310 cerr << "value: " << (RET)(*((DTYPE*)data)) << endl;
311 #endif
312 data+=strides;
313 }
314 return rValue;
315 }
316
317 DTYPE* data = (DTYPE*) raw_data_ptr;
318 for (long i = 0; i<length; ++i){
319 #ifdef _DEBUG_VALUES
320 cerr << "value: " << (RET)data[i] << endl;
321 #endif
322 rValue.push_back((RET)data[i]);
323 }
324 return rValue;
325 }
326
327 /// this is a special case. numpy.float64 has an array interface but no array descriptor
328 inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const
329 {
330 std::vector<float> rValue;
331 if ((ai->typekind) == *"f")
332 rValue.push_back((float)*(double*)(ai->data));
333 else {
334 setValueError("Unsupported NumPy data type.",m_strict);
335 return rValue;
336 }
337 #ifdef _DEBUG_VALUES
338 cerr << "value: " << rValue[0] << endl;
339 #endif
340 return rValue;
341 }
342
343 //Vamp specific types
344 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
345 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
346 { r = this->PyValue_To_FeatureSet(pyValue); }
347
348 Vamp::RealTime PyValue_To_RealTime(PyObject*) const;
349 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime &r) const
350 { r = this->PyValue_To_RealTime(pyValue); }
351
352 Vamp::Plugin::OutputDescriptor::SampleType PyValue_To_SampleType(PyObject*) const;
353
354 Vamp::Plugin::InputDomain PyValue_To_InputDomain(PyObject*) const;
355 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const
356 { r = this->PyValue_To_InputDomain(pyValue); }
357
358
359 /* Overloaded PyValue_To_rValue() to support generic functions */
360 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const
361 { float tmp = this->PyValue_To_Float(pyValue);
362 if(!m_error) defValue = tmp; }
363 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const
364 { size_t tmp = this->PyValue_To_Size_t(pyValue);
365 if(!m_error) defValue = tmp; }
366 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
367 { bool tmp = this->PyValue_To_Bool(pyValue);
368 if(!m_error) defValue = tmp; }
369 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const
370 { std::string tmp = this->PyValue_To_String(pyValue);
371 if(!m_error) defValue = tmp; }
372 /*used by templates where we expect no return value, if there is one it will be ignored*/
373 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const
374 { if (m_strict && pyValue != Py_None)
375 setValueError("Strict conversion error: Expected 'None' type.",m_strict);
376 }
377
378 /* convert sequence types to Vamp List types */
379 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const
380 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); }
381 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const
382 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); }
383 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const
384 { r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); }
385
386 /// this is only needed for RealTime->Frame conversion
387 void setInputSampleRate(float inputSampleRate)
388 { m_inputSampleRate = (unsigned int) inputSampleRate; }
389
390 private:
391 bool m_strict;
392 mutable bool m_error;
393 mutable std::queue<ValueError> m_errorQueue;
394 unsigned int m_inputSampleRate;
395
396 void setValueError(std::string,bool) const;
397 ValueError& lastError() const;
398
399 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */
400 inline void _convert(PyObject *pyValue,float &r) const
401 { r = PyValue_To_Float(pyValue); }
402 inline void _convert(PyObject *pyValue,size_t &r) const
403 { r = PyValue_To_Size_t(pyValue); }
404 inline void _convert(PyObject *pyValue,bool &r) const
405 { r = PyValue_To_Bool(pyValue); }
406 inline void _convert(PyObject *pyValue,std::string &r) const
407 { r = PyValue_To_String(pyValue); }
408 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
409 { r = PyValue_To_StringVector(pyValue); }
410 inline void _convert(PyObject *pyValue,std::vector<float> &r) const
411 { r = PyValue_To_FloatVector(pyValue); }
412 inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const
413 { r = PyValue_To_RealTime(pyValue); }
414 inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const
415 { r = PyValue_To_SampleType(pyValue); }
416 // inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const
417 // { r = PyValue_To_InputDomain(pyValue); }
418
419
420 /* Identify descriptors for error reporting */
421 inline std::string getDescriptorId(Vamp::Plugin::OutputDescriptor d) const
422 {return std::string("Output Descriptor '") + d.identifier +"' ";}
423 inline std::string getDescriptorId(Vamp::Plugin::ParameterDescriptor d) const
424 {return std::string("Parameter Descriptor '") + d.identifier +"' ";}
425 inline std::string getDescriptorId(Vamp::Plugin::Feature f) const
426 {return std::string("Feature (") + f.label + ")"; }
427
428 public:
429 const bool& error;
430
431 };
432
433 /* Convert Sample Buffers to Python */
434
435 /// passing the sample buffers as buitin python lists
436 /// Optimization: using fast sequence protocol
437 inline PyObject*
438 PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
439 {
440 //create a list of lists (new references)
441 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
442
443 // Pack samples into a Python List Object
444 // pyFloat/pyComplex types will always be new references,
445 // they will be freed when the lists are deallocated.
446
447 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
448 for (size_t i=0; i < channels; ++i) {
449
450 PyObject *pySampleList = PyList_New((Py_ssize_t) blockSize);
451 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList);
452
453 // Note: passing a complex list crashes the C-style plugin
454 // when it tries to convert it to a numpy array directly.
455 // This plugin will be obsolete, but we have to find a way
456 // to prevent such crash.
457
458 switch (Vamp::Plugin::TimeDomain) //(dtype)
459 {
460 case Vamp::Plugin::TimeDomain :
461
462 for (size_t j = 0; j < blockSize; ++j) {
463 PyObject *pyFloat=PyFloat_FromDouble(
464 (double) inputBuffers[i][j]);
465 pySampleListArray[j] = pyFloat;
466 }
467 break;
468
469 case Vamp::Plugin::FrequencyDomain :
470
471 size_t k = 0;
472 for (size_t j = 0; j < blockSize/2; ++j) {
473 PyObject *pyComplex=PyComplex_FromDoubles(
474 (double) inputBuffers[i][k],
475 (double) inputBuffers[i][k+1]);
476 pySampleListArray[j] = pyComplex;
477 k += 2;
478 }
479 break;
480
481 }
482 pyChannelListArray[i] = pySampleList;
483 }
484 return pyChannelList;
485 }
486
487 /// numpy buffer interface: passing the sample buffers as shared memory buffers
488 /// Optimization: using sequence protocol for creating the buffer list
489 inline PyObject*
490 PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize)
491 {
492 //create a list of buffers (returns new references)
493 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
494 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
495
496 // Expose memory using the Buffer Interface.
497 // This will pass a pointer which can be recasted in Python code
498 // as complex or float array using Numpy's frombuffer() method
499 // (this will not copy values just keep the starting adresses
500 // for each channel in a list)
501 Py_ssize_t bufferSize = (Py_ssize_t) sizeof(float) * blockSize;
502
503 for (size_t i=0; i < channels; ++i) {
504 PyObject *pyBuffer = PyBuffer_FromMemory
505 ((void *) (float *) inputBuffers[i],bufferSize);
506 pyChannelListArray[i] = pyBuffer;
507 }
508 return pyChannelList;
509 }
510
511
512 /// numpy array interface: passing the sample buffers as 2D numpy array
513 /// Optimization: using array API (needs numpy headers)
514 #ifdef HAVE_NUMPY
515 inline PyObject*
516 PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
517 {
518 /*
519 NOTE: We create a list of 1D Numpy arrays for each channel instead
520 of a matrix, because the address space of inputBuffers doesn't seem
521 to be continuous. Although the array strides could be calculated for
522 2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure
523 if this can be trusted, especially for more than 2 channels.
524
525 cerr << "First channel: " << inputBuffers[0][0] << " address: " << inputBuffers[0] << endl;
526 if (channels == 2)
527 cerr << "Second channel: " << inputBuffers[1][0] << " address: " << inputBuffers[1] << endl;
528
529 */
530
531 // create a list of arrays (returns new references)
532 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
533 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
534
535 // Expose memory using the Numpy Array Interface.
536 // This will wrap an array objects around the data.
537 // (will not copy values just steal the starting adresses)
538
539 int arraySize, typenum;
540
541 switch (dtype)
542 {
543 case Vamp::Plugin::TimeDomain :
544 typenum = dtype_float32; //NPY_FLOAT;
545 arraySize = (int) blockSize;
546 break;
547
548 case Vamp::Plugin::FrequencyDomain :
549 typenum = dtype_complex64; //NPY_CFLOAT;
550 arraySize = (int) blockSize / 2;
551 break;
552
553 default :
554 cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl;
555 return pyChannelList;
556 }
557
558 // size for each dimension
559 npy_intp ndims[1]={arraySize};
560
561 for (size_t i=0; i < channels; ++i) {
562 PyObject *pyChannelArray =
563 //args: (dimensions, size in each dim, type kind, pointer to continuous array)
564 PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]);
565 // make it read-only: set all flags to false except NPY_C_CONTIGUOUS
566 ((PyArrayObject*)pyChannelArray)->flags = NPY_C_CONTIGUOUS;
567 pyChannelListArray[i] = pyChannelArray;
568 }
569 return pyChannelList;
570 }
571 #endif
572
573
574
575 #ifdef NUMPY_REFERENCE
576 /// This should be all we need to compile without direct dependency,
577 /// but we don't do that. (it may not work on some platforms)
578 typedef struct {
579 int two; /* contains the integer 2 -- simple sanity check */
580 int nd; /* number of dimensions */
581 char typekind; /* kind in array --- character code of typestr */
582 int itemsize; /* size of each element */
583 int flags; /* flags indicating how the data should be interpreted */
584 /* must set ARR_HAS_DESCR bit to validate descr */
585 Py_intptr_t *shape; /* A length-nd array of shape information */
586 Py_intptr_t *strides; /* A length-nd array of stride information */
587 void *data; /* A pointer to the first element of the array */
588 PyObject *descr; /* NULL or data-description (same as descr key */
589 /* of __array_interface__) -- must set ARR_HAS_DESCR */
590 /* flag or this will be ignored. */
591 } PyArrayInterface;
592
593 typedef struct PyArrayObject {
594 PyObject_HEAD
595 char *data; /* pointer to raw data buffer */
596 int nd; /* number of dimensions, also called ndim */
597 npy_intp *dimensions; /* size in each dimension */
598 npy_intp *strides; /* bytes to jump to get to the
599 next element in each dimension */
600 PyObject *base; /* This object should be decref'd
601 upon deletion of array */
602 /* For views it points to the original array */
603 /* For creation from buffer object it points
604 to an object that shold be decref'd on
605 deletion */
606 /* For UPDATEIFCOPY flag this is an array
607 to-be-updated upon deletion of this one */
608 PyArray_Descr *descr; /* Pointer to type structure */
609 int flags; /* Flags describing array -- see below*/
610 PyObject *weakreflist; /* For weakreferences */
611 } PyArrayObject;
612
613 typedef struct _PyArray_Descr {
614 PyObject_HEAD
615 PyTypeObject *typeobj; /* the type object representing an
616 instance of this type -- should not
617 be two type_numbers with the same type
618 object. */
619 char kind; /* kind for this type */
620 char type; /* unique-character representing this type */
621 char byteorder; /* '>' (big), '<' (little), '|'
622 (not-applicable), or '=' (native). */
623 char hasobject; /* non-zero if it has object arrays
624 in fields */
625 int type_num; /* number representing this type */
626 int elsize; /* element size for this type */
627 int alignment; /* alignment needed for this type */
628 struct _arr_descr \
629 *subarray; /* Non-NULL if this type is
630 is an array (C-contiguous)
631 of some other type
632 */
633 PyObject *fields; /* The fields dictionary for this type */
634 /* For statically defined descr this
635 is always Py_None */
636
637 PyObject *names; /* An ordered tuple of field names or NULL
638 if no fields are defined */
639
640 PyArray_ArrFuncs *f; /* a table of functions specific for each
641 basic data descriptor */
642 } PyArray_Descr;
643
644 enum NPY_TYPES { NPY_BOOL=0,
645 NPY_BYTE, NPY_UBYTE,
646 NPY_SHORT, NPY_USHORT,
647 NPY_INT, NPY_UINT,
648 NPY_LONG, NPY_ULONG,
649 NPY_LONGLONG, NPY_ULONGLONG,
650 NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
651 NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
652 NPY_OBJECT=17,
653 NPY_STRING, NPY_UNICODE,
654 NPY_VOID,
655 NPY_NTYPES,
656 NPY_NOTYPE,
657 NPY_CHAR, /* special flag */
658 NPY_USERDEF=256 /* leave room for characters */
659 };
660 #endif /*NUMPY_REFERENCE*/
661 #endif