Mercurial > pytave
comparison oct-py-types.cc @ 402:c4b78e449c62
maint: indent functions declared in the pytave namespace
* oct-py-eval.cc, oct-py-eval.h, oct-py-types.cc, oct-py-types.h,
oct-py-util.cc, oct-py-util.h: Indent functions declared in the pytave
namespace, adjust line wrap where necessary.
author | Mike Miller <mtmiller@octave.org> |
---|---|
date | Fri, 28 Apr 2017 14:07:57 -0700 |
parents | 6c316b5f30f7 |
children | 3644df6564bc |
comparison
equal
deleted
inserted
replaced
401:3a64a336d214 | 402:c4b78e449c62 |
---|---|
38 #include "python_to_octave.h" | 38 #include "python_to_octave.h" |
39 | 39 |
40 namespace pytave | 40 namespace pytave |
41 { | 41 { |
42 | 42 |
43 PyObject * | 43 PyObject * |
44 make_py_bool (bool value) | 44 make_py_bool (bool value) |
45 { | 45 { |
46 if (value) | 46 if (value) |
47 Py_RETURN_TRUE; | 47 Py_RETURN_TRUE; |
48 else | 48 else |
49 Py_RETURN_FALSE; | 49 Py_RETURN_FALSE; |
50 } | 50 } |
51 | 51 |
52 PyObject * | 52 PyObject * |
53 make_py_complex (std::complex<double> value) | 53 make_py_complex (std::complex<double> value) |
54 { | 54 { |
55 Py_complex& py_complex_value = reinterpret_cast<Py_complex&> (value); | 55 Py_complex& py_complex_value = reinterpret_cast<Py_complex&> (value); |
56 return PyComplex_FromCComplex (py_complex_value); | 56 return PyComplex_FromCComplex (py_complex_value); |
57 } | 57 } |
58 | 58 |
59 PyObject * | 59 PyObject * |
60 make_py_float (double value) | 60 make_py_float (double value) |
61 { | 61 { |
62 return PyFloat_FromDouble (value); | 62 return PyFloat_FromDouble (value); |
63 } | 63 } |
64 | 64 |
65 bool | 65 bool |
66 extract_py_bool (PyObject *obj) | 66 extract_py_bool (PyObject *obj) |
67 { | 67 { |
68 if (! obj) | 68 if (! obj) |
69 throw object_convert_exception ("failed to extract boolean: null object"); | 69 throw object_convert_exception ("failed to extract boolean: null object"); |
70 | 70 |
71 if (! PyBool_Check (obj)) | 71 if (! PyBool_Check (obj)) |
72 throw object_convert_exception ("failed to extract boolean: wrong type"); | 72 throw object_convert_exception ("failed to extract boolean: wrong type"); |
73 | 73 |
74 return (obj == Py_True); | 74 return (obj == Py_True); |
75 } | 75 } |
76 | 76 |
77 std::complex<double> | 77 std::complex<double> |
78 extract_py_complex (PyObject *obj) | 78 extract_py_complex (PyObject *obj) |
79 { | 79 { |
80 if (! obj) | 80 if (! obj) |
81 throw object_convert_exception ("failed to extract complex: null object"); | 81 throw object_convert_exception ("failed to extract complex: null object"); |
82 | 82 |
83 if (! PyComplex_Check (obj)) | 83 if (! PyComplex_Check (obj)) |
84 throw object_convert_exception ("failed to extract complex: wrong type"); | 84 throw object_convert_exception ("failed to extract complex: wrong type"); |
85 | 85 |
86 Py_complex value = PyComplex_AsCComplex (obj); | 86 Py_complex value = PyComplex_AsCComplex (obj); |
87 return reinterpret_cast<std::complex<double>&> (value); | 87 return reinterpret_cast<std::complex<double>&> (value); |
88 } | 88 } |
89 | 89 |
90 double | 90 double |
91 extract_py_float (PyObject *obj) | 91 extract_py_float (PyObject *obj) |
92 { | 92 { |
93 if (! obj) | 93 if (! obj) |
94 throw object_convert_exception ("failed to extract float: null object"); | 94 throw object_convert_exception ("failed to extract float: null object"); |
95 | 95 |
96 if (! PyFloat_Check (obj)) | 96 if (! PyFloat_Check (obj)) |
97 throw object_convert_exception ("failed to extract float: wrong type"); | 97 throw object_convert_exception ("failed to extract float: wrong type"); |
98 | 98 |
99 return PyFloat_AsDouble (obj); | 99 return PyFloat_AsDouble (obj); |
100 } | 100 } |
101 | 101 |
102 PyObject * | 102 PyObject * |
103 make_py_int (int32_t value) | 103 make_py_int (int32_t value) |
104 { | 104 { |
105 #if PY_VERSION_HEX >= 0x03000000 | 105 #if PY_VERSION_HEX >= 0x03000000 |
106 return PyLong_FromLong (value); | 106 return PyLong_FromLong (value); |
107 #else | 107 #else |
108 return PyInt_FromLong (value); | 108 return PyInt_FromLong (value); |
109 #endif | 109 #endif |
110 } | 110 } |
111 | 111 |
112 PyObject * | 112 PyObject * |
113 make_py_int (uint32_t value) | 113 make_py_int (uint32_t value) |
114 { | 114 { |
115 return PyLong_FromUnsignedLong (value); | 115 return PyLong_FromUnsignedLong (value); |
116 } | 116 } |
117 | 117 |
118 PyObject * | 118 PyObject * |
119 make_py_int (int64_t value) | 119 make_py_int (int64_t value) |
120 { | 120 { |
121 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)) | 121 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)) |
122 return PyLong_FromLongLong (value); | 122 return PyLong_FromLongLong (value); |
123 #else | 123 #else |
124 return PyLong_FromLong (value); | 124 return PyLong_FromLong (value); |
125 #endif | 125 #endif |
126 } | 126 } |
127 | 127 |
128 PyObject * | 128 PyObject * |
129 make_py_int (uint64_t value) | 129 make_py_int (uint64_t value) |
130 { | 130 { |
131 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)) | 131 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)) |
132 return PyLong_FromUnsignedLongLong (value); | 132 return PyLong_FromUnsignedLongLong (value); |
133 #else | 133 #else |
134 return PyLong_FromUnsignedLong (value); | 134 return PyLong_FromUnsignedLong (value); |
135 #endif | 135 #endif |
136 } | 136 } |
137 | 137 |
138 PyObject * | 138 PyObject * |
139 make_py_array (const void *data, size_t len, char typecode) | 139 make_py_array (const void *data, size_t len, char typecode) |
140 { | 140 { |
141 if (! typecode) | 141 if (! typecode) |
142 throw object_convert_exception ("unable to create array from Octave data"); | 142 throw object_convert_exception |
143 | 143 ("unable to create array from Octave data"); |
144 std::string arg { typecode }; | 144 |
145 PyObject *array = py_call_function ("array.array", ovl (arg)); | 145 std::string arg { typecode }; |
146 | 146 PyObject *array = py_call_function ("array.array", ovl (arg)); |
147 if (len > 0) | 147 |
148 { | 148 if (len > 0) |
149 // create a byte buffer containing a copy of the array binary data | 149 { |
150 const char *cdata = reinterpret_cast<const char *> (data); | 150 // create a byte buffer containing a copy of the array binary data |
151 PyObject *buf = PyBytes_FromStringAndSize (cdata, len); | 151 const char *cdata = reinterpret_cast<const char *> (data); |
152 if (! buf) | 152 PyObject *buf = PyBytes_FromStringAndSize (cdata, len); |
153 octave_throw_bad_alloc (); | 153 if (! buf) |
154 | 154 octave_throw_bad_alloc (); |
155 PyObject *frombytes = (PyObject_HasAttrString (array, "frombytes") ? | 155 |
156 PyObject_GetAttrString (array, "frombytes") : | 156 PyObject *frombytes = (PyObject_HasAttrString (array, "frombytes") ? |
157 PyObject_GetAttrString (array, "fromstring")); | 157 PyObject_GetAttrString (array, "frombytes") : |
158 PyObject *args = PyTuple_Pack (1, buf); | 158 PyObject_GetAttrString (array, "fromstring")); |
159 py_call_function (frombytes, args); | 159 PyObject *args = PyTuple_Pack (1, buf); |
160 Py_DECREF (args); | 160 py_call_function (frombytes, args); |
161 Py_DECREF (buf); | 161 Py_DECREF (args); |
162 } | 162 Py_DECREF (buf); |
163 | 163 } |
164 return array; | 164 |
165 } | 165 return array; |
166 | 166 } |
167 // Prefer the 'q' and 'Q' typecodes if they are available (if Python 3 and | 167 |
168 // built with support for long long integers) | 168 // Prefer the 'q' and 'Q' typecodes if they are available (if Python 3 and |
169 // built with support for long long integers) | |
169 | 170 |
170 #if (PY_VERSION_HEX >= 0x03000000) && defined (HAVE_LONG_LONG) | 171 #if (PY_VERSION_HEX >= 0x03000000) && defined (HAVE_LONG_LONG) |
171 # define ARRAY_INT64_TYPECODE 'q' | 172 # define ARRAY_INT64_TYPECODE 'q' |
172 # define ARRAY_UINT64_TYPECODE 'Q' | 173 # define ARRAY_UINT64_TYPECODE 'Q' |
173 #elif (SIZEOF_LONG == 8) | 174 #elif (SIZEOF_LONG == 8) |
176 #else | 177 #else |
177 # define ARRAY_INT64_TYPECODE 0 | 178 # define ARRAY_INT64_TYPECODE 0 |
178 # define ARRAY_UINT64_TYPECODE 0 | 179 # define ARRAY_UINT64_TYPECODE 0 |
179 #endif | 180 #endif |
180 | 181 |
181 template <typename T> | 182 template <typename T> |
182 struct py_array_info { }; | 183 struct py_array_info { }; |
183 | 184 |
184 template <> | 185 template <> |
185 struct py_array_info<octave_int8> { static const char typecode = 'b'; }; | 186 struct py_array_info<octave_int8> { static const char typecode = 'b'; }; |
186 | 187 |
187 template <> | 188 template <> |
188 struct py_array_info<octave_int16> { static const char typecode = 'h'; }; | 189 struct py_array_info<octave_int16> { static const char typecode = 'h'; }; |
189 | 190 |
190 template <> | 191 template <> |
191 struct py_array_info<octave_int32> { static const char typecode = 'i'; }; | 192 struct py_array_info<octave_int32> { static const char typecode = 'i'; }; |
192 | 193 |
193 template <> | 194 template <> |
194 struct py_array_info<octave_int64> | 195 struct py_array_info<octave_int64> |
195 { | 196 { |
196 static const char typecode = ARRAY_INT64_TYPECODE; | 197 static const char typecode = ARRAY_INT64_TYPECODE; |
197 }; | 198 }; |
198 | 199 |
199 template <> | 200 template <> |
200 struct py_array_info<octave_uint8> { static const char typecode = 'B'; }; | 201 struct py_array_info<octave_uint8> { static const char typecode = 'B'; }; |
201 | 202 |
202 template <> | 203 template <> |
203 struct py_array_info<octave_uint16> { static const char typecode = 'H'; }; | 204 struct py_array_info<octave_uint16> { static const char typecode = 'H'; }; |
204 | 205 |
205 template <> | 206 template <> |
206 struct py_array_info<octave_uint32> { static const char typecode = 'I'; }; | 207 struct py_array_info<octave_uint32> { static const char typecode = 'I'; }; |
207 | 208 |
208 template <> | 209 template <> |
209 struct py_array_info<octave_uint64> { | 210 struct py_array_info<octave_uint64> { |
210 static const char typecode = ARRAY_UINT64_TYPECODE; | 211 static const char typecode = ARRAY_UINT64_TYPECODE; |
211 }; | 212 }; |
212 | 213 |
213 PyObject * | 214 PyObject * |
214 make_py_array (const NDArray& nda) | 215 make_py_array (const NDArray& nda) |
215 { | 216 { |
216 return make_py_array (nda.data (), nda.numel () * sizeof (double), 'd'); | 217 return make_py_array (nda.data (), nda.numel () * sizeof (double), 'd'); |
218 } | |
219 | |
220 PyObject * | |
221 make_py_array (const FloatNDArray& nda) | |
222 { | |
223 return make_py_array (nda.data (), nda.numel () * sizeof (float), 'f'); | |
224 } | |
225 | |
226 template <typename T> | |
227 PyObject * | |
228 make_py_array (const intNDArray<T>& nda) | |
229 { | |
230 return make_py_array (nda.data (), nda.numel () * sizeof (T), | |
231 py_array_info<T>::typecode); | |
232 } | |
233 | |
234 // Instantiate all possible integer array template functions needed | |
235 | |
236 template PyObject * make_py_array<octave_int8> (const int8NDArray&); | |
237 template PyObject * make_py_array<octave_int16> (const int16NDArray&); | |
238 template PyObject * make_py_array<octave_int32> (const int32NDArray&); | |
239 template PyObject * make_py_array<octave_int64> (const int64NDArray&); | |
240 template PyObject * make_py_array<octave_uint8> (const uint8NDArray&); | |
241 template PyObject * make_py_array<octave_uint16> (const uint16NDArray&); | |
242 template PyObject * make_py_array<octave_uint32> (const uint32NDArray&); | |
243 template PyObject * make_py_array<octave_uint64> (const uint64NDArray&); | |
244 | |
245 PyObject * | |
246 make_py_numeric_value (const octave_value& value) | |
247 { | |
248 if (value.is_scalar_type ()) | |
249 { | |
250 if (value.is_bool_type ()) | |
251 return make_py_bool (value.bool_value ()); | |
252 | |
253 else if (value.is_int8_type ()) | |
254 return make_py_int (value.int8_scalar_value ().value ()); | |
255 else if (value.is_int16_type ()) | |
256 return make_py_int (value.int16_scalar_value ().value ()); | |
257 else if (value.is_int32_type ()) | |
258 return make_py_int (value.int32_scalar_value ().value ()); | |
259 else if (value.is_int64_type ()) | |
260 return make_py_int (value.int64_scalar_value ().value ()); | |
261 | |
262 else if (value.is_uint8_type ()) | |
263 return make_py_int (value.uint8_scalar_value ().value ()); | |
264 else if (value.is_uint16_type ()) | |
265 return make_py_int (value.uint16_scalar_value ().value ()); | |
266 else if (value.is_uint32_type ()) | |
267 return make_py_int (value.uint32_scalar_value ().value ()); | |
268 else if (value.is_uint64_type ()) | |
269 return make_py_int (value.uint64_scalar_value ().value ()); | |
270 | |
271 else if (value.is_complex_type ()) | |
272 return make_py_complex (value.complex_value ()); | |
273 else if (value.is_float_type ()) | |
274 return make_py_float (value.double_value ()); | |
275 } | |
276 | |
277 throw value_convert_exception ("unhandled scalar type"); | |
278 return 0; | |
279 } | |
280 | |
281 PyObject * | |
282 make_py_array (const octave_value& value) | |
283 { | |
284 if (value.is_numeric_type () && ! value.is_complex_type () | |
285 && value.ndims () == 2 && (value.columns () <= 1 || value.rows () <= 1)) | |
286 { | |
287 if (value.is_double_type ()) | |
288 return make_py_array (value.array_value ()); | |
289 else if (value.is_single_type ()) | |
290 return make_py_array (value.float_array_value ()); | |
291 | |
292 else if (value.is_int8_type ()) | |
293 return make_py_array (value.int8_array_value ()); | |
294 else if (value.is_int16_type ()) | |
295 return make_py_array (value.int16_array_value ()); | |
296 else if (value.is_int32_type ()) | |
297 return make_py_array (value.int32_array_value ()); | |
298 else if (value.is_int64_type ()) | |
299 return make_py_array (value.int64_array_value ()); | |
300 | |
301 else if (value.is_uint8_type ()) | |
302 return make_py_array (value.uint8_array_value ()); | |
303 else if (value.is_uint16_type ()) | |
304 return make_py_array (value.uint16_array_value ()); | |
305 else if (value.is_uint32_type ()) | |
306 return make_py_array (value.uint32_array_value ()); | |
307 else if (value.is_uint64_type ()) | |
308 return make_py_array (value.uint64_array_value ()); | |
309 } | |
310 | |
311 throw value_convert_exception ("unhandled Octave numeric vector type"); | |
312 return 0; | |
313 } | |
314 | |
315 inline PyObject * | |
316 wrap_octvalue_to_pyobj (const octave_value& value) | |
317 { | |
318 boost::python::object obj; | |
319 octvalue_to_pyobj (obj, value); | |
320 PyObject *ptr = obj.ptr (); | |
321 Py_INCREF (ptr); | |
322 return ptr; | |
323 } | |
324 | |
325 inline octave_value | |
326 wrap_pyobj_to_octvalue (PyObject *obj) | |
327 { | |
328 boost::python::object objref | |
329 { boost::python::handle<> (boost::python::borrowed (obj)) }; | |
330 octave_value value; | |
331 pyobj_to_octvalue (value, objref); | |
332 return value; | |
333 } | |
334 | |
335 octave_scalar_map | |
336 extract_py_scalar_map (PyObject *obj) | |
337 { | |
338 if (! obj) | |
339 throw object_convert_exception ("failed to extract map: null object"); | |
340 | |
341 if (! PyDict_Check (obj)) | |
342 throw object_convert_exception ("failed to extract map: wrong type"); | |
343 | |
344 octave_scalar_map map; | |
345 | |
346 Py_ssize_t pos = 0; | |
347 PyObject *py_key = 0; | |
348 PyObject *py_value = 0; | |
349 | |
350 while (PyDict_Next (obj, &pos, &py_key, &py_value)) | |
351 { | |
352 if (! PyBytes_Check (py_key) && ! PyUnicode_Check (py_key)) | |
353 throw object_convert_exception | |
354 ("failed to extract map: bad key type"); | |
355 | |
356 std::string key = extract_py_str (py_key); | |
357 octave_value value = wrap_pyobj_to_octvalue (py_value); | |
358 map.setfield (key, value); | |
359 } | |
360 | |
361 return map; | |
362 } | |
363 | |
364 PyObject * | |
365 make_py_dict (const octave_scalar_map& map) | |
366 { | |
367 PyObject *dict = PyDict_New (); | |
368 if (! dict) | |
369 octave_throw_bad_alloc (); | |
370 | |
371 for (auto p = map.begin (); p != map.end (); ++p) | |
372 { | |
373 PyObject *key = make_py_str (map.key (p)); | |
374 if (! key) | |
375 octave_throw_bad_alloc (); | |
376 | |
377 PyObject *item = wrap_octvalue_to_pyobj (map.contents (p)); | |
378 | |
379 if (PyDict_SetItem (dict, key, item) < 0) | |
380 throw boost::python::error_already_set (); | |
381 } | |
382 | |
383 return dict; | |
384 } | |
385 | |
386 int64_t | |
387 extract_py_int64 (PyObject *obj) | |
388 { | |
389 if (! obj) | |
390 throw object_convert_exception ("failed to extract integer: null object"); | |
391 | |
392 if (PyLong_Check (obj)) | |
393 { | |
394 int overflow = 0; | |
395 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) | |
396 PY_LONG_LONG value = PyLong_AsLongLongAndOverflow (obj, &overflow); | |
397 #else | |
398 long value = PyLong_AsLongAndOverflow (obj, &overflow); | |
399 #endif | |
400 if (overflow) | |
401 if (overflow > 0) | |
402 value = std::numeric_limits<int64_t>::max (); | |
403 else | |
404 value = std::numeric_limits<int64_t>::min (); | |
405 return static_cast<int64_t> (value); | |
406 } | |
407 #if PY_VERSION_HEX < 0x03000000 | |
408 else if (PyInt_Check (obj)) | |
409 return PyInt_AsLong (obj); | |
410 #endif | |
411 else | |
412 throw object_convert_exception ("failed to extract integer: wrong type"); | |
413 | |
414 return 0; | |
415 } | |
416 | |
417 uint64_t | |
418 extract_py_uint64 (PyObject *obj) | |
419 { | |
420 if (! obj) | |
421 throw object_convert_exception ("failed to extract integer: null object"); | |
422 | |
423 if (PyLong_Check (obj)) | |
424 { | |
425 // FIXME: if (value < 0), may be very implementation dependent | |
426 if (Py_SIZE (obj) < 0) | |
427 return 0; | |
428 | |
429 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) | |
430 unsigned PY_LONG_LONG value = PyLong_AsUnsignedLongLong (obj); | |
431 bool overflow = (value == static_cast<unsigned PY_LONG_LONG> (-1)); | |
432 #else | |
433 unsigned long value = PyLong_AsUnsignedLong (obj); | |
434 bool overflow = (value == static_cast<unsigned long> (-1)); | |
435 #endif | |
436 if (overflow) | |
437 { | |
438 value = std::numeric_limits<uint64_t>::max (); | |
439 PyErr_Clear (); | |
440 } | |
441 | |
442 return static_cast<uint64_t> (value); | |
443 } | |
444 #if PY_VERSION_HEX < 0x03000000 | |
445 else if (PyInt_Check (obj)) | |
446 return static_cast<uint64_t> (PyInt_AsLong (obj)); | |
447 #endif | |
448 else | |
449 throw object_convert_exception ("failed to extract integer: wrong type"); | |
450 | |
451 return 0; | |
452 } | |
453 | |
454 PyObject * | |
455 make_py_tuple (const Cell& cell) | |
456 { | |
457 if (! (cell.is_empty () || cell.is_vector ())) | |
458 throw value_convert_exception ( | |
459 "unable to convert multidimensional cell array into Python tuple"); | |
460 | |
461 octave_idx_type size = cell.numel (); | |
462 PyObject *tuple = PyTuple_New (size); | |
463 if (! tuple) | |
464 octave_throw_bad_alloc (); | |
465 | |
466 for (octave_idx_type i = 0; i < size; ++i) | |
467 { | |
468 PyObject *item = wrap_octvalue_to_pyobj (cell.xelem (i)); | |
469 PyTuple_SET_ITEM (tuple, i, item); | |
470 } | |
471 | |
472 return tuple; | |
473 } | |
474 | |
475 std::string | |
476 extract_py_str (PyObject *obj) | |
477 { | |
478 std::string retval; | |
479 | |
480 if (! obj) | |
481 throw object_convert_exception ("failed to extract string: null object"); | |
482 if (PyBytes_Check (obj)) | |
483 { | |
484 retval.assign (PyBytes_AsString (obj), PyBytes_Size (obj)); | |
485 } | |
486 else if (PyUnicode_Check (obj)) | |
487 { | |
488 bool ok = false; | |
489 PyObject *enc = PyUnicode_AsUTF8String (obj); | |
490 if (enc) | |
491 { | |
492 if (PyBytes_Check (enc)) | |
493 { | |
494 ok = true; | |
495 retval.assign (PyBytes_AsString (enc), PyBytes_Size (enc)); | |
496 } | |
497 Py_DECREF (enc); | |
498 } | |
499 if (! ok) | |
500 throw object_convert_exception | |
501 ("failed to extract string: UTF-8 error"); | |
502 } | |
503 else | |
504 throw object_convert_exception ("failed to extract string: wrong type"); | |
505 | |
506 return retval; | |
507 } | |
508 | |
509 PyObject * | |
510 make_py_str (const std::string& str) | |
511 { | |
512 #if PY_VERSION_HEX >= 0x03000000 | |
513 return PyUnicode_FromStringAndSize (str.data (), str.size ()); | |
514 #else | |
515 return PyString_FromStringAndSize (str.data (), str.size ()); | |
516 #endif | |
517 } | |
518 | |
217 } | 519 } |
218 | |
219 PyObject * | |
220 make_py_array (const FloatNDArray& nda) | |
221 { | |
222 return make_py_array (nda.data (), nda.numel () * sizeof (float), 'f'); | |
223 } | |
224 | |
225 template <typename T> | |
226 PyObject * | |
227 make_py_array (const intNDArray<T>& nda) | |
228 { | |
229 return make_py_array (nda.data (), nda.numel () * sizeof (T), | |
230 py_array_info<T>::typecode); | |
231 } | |
232 | |
233 // Instantiate all possible integer array template functions needed | |
234 | |
235 template PyObject * make_py_array<octave_int8> (const int8NDArray&); | |
236 template PyObject * make_py_array<octave_int16> (const int16NDArray&); | |
237 template PyObject * make_py_array<octave_int32> (const int32NDArray&); | |
238 template PyObject * make_py_array<octave_int64> (const int64NDArray&); | |
239 template PyObject * make_py_array<octave_uint8> (const uint8NDArray&); | |
240 template PyObject * make_py_array<octave_uint16> (const uint16NDArray&); | |
241 template PyObject * make_py_array<octave_uint32> (const uint32NDArray&); | |
242 template PyObject * make_py_array<octave_uint64> (const uint64NDArray&); | |
243 | |
244 PyObject * | |
245 make_py_numeric_value (const octave_value& value) | |
246 { | |
247 if (value.is_scalar_type ()) | |
248 { | |
249 if (value.is_bool_type ()) | |
250 return make_py_bool (value.bool_value ()); | |
251 | |
252 else if (value.is_int8_type ()) | |
253 return make_py_int (value.int8_scalar_value ().value ()); | |
254 else if (value.is_int16_type ()) | |
255 return make_py_int (value.int16_scalar_value ().value ()); | |
256 else if (value.is_int32_type ()) | |
257 return make_py_int (value.int32_scalar_value ().value ()); | |
258 else if (value.is_int64_type ()) | |
259 return make_py_int (value.int64_scalar_value ().value ()); | |
260 | |
261 else if (value.is_uint8_type ()) | |
262 return make_py_int (value.uint8_scalar_value ().value ()); | |
263 else if (value.is_uint16_type ()) | |
264 return make_py_int (value.uint16_scalar_value ().value ()); | |
265 else if (value.is_uint32_type ()) | |
266 return make_py_int (value.uint32_scalar_value ().value ()); | |
267 else if (value.is_uint64_type ()) | |
268 return make_py_int (value.uint64_scalar_value ().value ()); | |
269 | |
270 else if (value.is_complex_type ()) | |
271 return make_py_complex (value.complex_value ()); | |
272 else if (value.is_float_type ()) | |
273 return make_py_float (value.double_value ()); | |
274 } | |
275 | |
276 throw value_convert_exception ("unhandled scalar type"); | |
277 return 0; | |
278 } | |
279 | |
280 PyObject * | |
281 make_py_array (const octave_value& value) | |
282 { | |
283 if (value.is_numeric_type () && ! value.is_complex_type () | |
284 && value.ndims () == 2 && (value.columns () <= 1 || value.rows () <= 1)) | |
285 { | |
286 if (value.is_double_type ()) | |
287 return make_py_array (value.array_value ()); | |
288 else if (value.is_single_type ()) | |
289 return make_py_array (value.float_array_value ()); | |
290 | |
291 else if (value.is_int8_type ()) | |
292 return make_py_array (value.int8_array_value ()); | |
293 else if (value.is_int16_type ()) | |
294 return make_py_array (value.int16_array_value ()); | |
295 else if (value.is_int32_type ()) | |
296 return make_py_array (value.int32_array_value ()); | |
297 else if (value.is_int64_type ()) | |
298 return make_py_array (value.int64_array_value ()); | |
299 | |
300 else if (value.is_uint8_type ()) | |
301 return make_py_array (value.uint8_array_value ()); | |
302 else if (value.is_uint16_type ()) | |
303 return make_py_array (value.uint16_array_value ()); | |
304 else if (value.is_uint32_type ()) | |
305 return make_py_array (value.uint32_array_value ()); | |
306 else if (value.is_uint64_type ()) | |
307 return make_py_array (value.uint64_array_value ()); | |
308 } | |
309 | |
310 throw value_convert_exception ("unhandled Octave numeric vector type"); | |
311 return 0; | |
312 } | |
313 | |
314 inline PyObject * | |
315 wrap_octvalue_to_pyobj (const octave_value& value) | |
316 { | |
317 boost::python::object obj; | |
318 octvalue_to_pyobj (obj, value); | |
319 PyObject *ptr = obj.ptr (); | |
320 Py_INCREF (ptr); | |
321 return ptr; | |
322 } | |
323 | |
324 inline octave_value | |
325 wrap_pyobj_to_octvalue (PyObject *obj) | |
326 { | |
327 boost::python::object objref { boost::python::handle<> (boost::python::borrowed (obj)) }; | |
328 octave_value value; | |
329 pyobj_to_octvalue (value, objref); | |
330 return value; | |
331 } | |
332 | |
333 octave_scalar_map | |
334 extract_py_scalar_map (PyObject *obj) | |
335 { | |
336 if (! obj) | |
337 throw object_convert_exception ("failed to extract map: null object"); | |
338 | |
339 if (! PyDict_Check (obj)) | |
340 throw object_convert_exception ("failed to extract map: wrong type"); | |
341 | |
342 octave_scalar_map map; | |
343 | |
344 Py_ssize_t pos = 0; | |
345 PyObject *py_key = 0; | |
346 PyObject *py_value = 0; | |
347 | |
348 while (PyDict_Next (obj, &pos, &py_key, &py_value)) | |
349 { | |
350 if (! PyBytes_Check (py_key) && ! PyUnicode_Check (py_key)) | |
351 throw object_convert_exception ("failed to extract map: bad key type"); | |
352 | |
353 std::string key = extract_py_str (py_key); | |
354 octave_value value = wrap_pyobj_to_octvalue (py_value); | |
355 map.setfield (key, value); | |
356 } | |
357 | |
358 return map; | |
359 } | |
360 | |
361 PyObject * | |
362 make_py_dict (const octave_scalar_map& map) | |
363 { | |
364 PyObject *dict = PyDict_New (); | |
365 if (! dict) | |
366 octave_throw_bad_alloc (); | |
367 | |
368 for (auto p = map.begin (); p != map.end (); ++p) | |
369 { | |
370 PyObject *key = make_py_str (map.key (p)); | |
371 if (! key) | |
372 octave_throw_bad_alloc (); | |
373 | |
374 PyObject *item = wrap_octvalue_to_pyobj (map.contents (p)); | |
375 | |
376 if (PyDict_SetItem (dict, key, item) < 0) | |
377 throw boost::python::error_already_set (); | |
378 } | |
379 | |
380 return dict; | |
381 } | |
382 | |
383 int64_t | |
384 extract_py_int64 (PyObject *obj) | |
385 { | |
386 if (! obj) | |
387 throw object_convert_exception ("failed to extract integer: null object"); | |
388 | |
389 if (PyLong_Check (obj)) | |
390 { | |
391 int overflow = 0; | |
392 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) | |
393 PY_LONG_LONG value = PyLong_AsLongLongAndOverflow (obj, &overflow); | |
394 #else | |
395 long value = PyLong_AsLongAndOverflow (obj, &overflow); | |
396 #endif | |
397 if (overflow) | |
398 if (overflow > 0) | |
399 value = std::numeric_limits<int64_t>::max (); | |
400 else | |
401 value = std::numeric_limits<int64_t>::min (); | |
402 return static_cast<int64_t> (value); | |
403 } | |
404 #if PY_VERSION_HEX < 0x03000000 | |
405 else if (PyInt_Check (obj)) | |
406 return PyInt_AsLong (obj); | |
407 #endif | |
408 else | |
409 throw object_convert_exception ("failed to extract integer: wrong type"); | |
410 | |
411 return 0; | |
412 } | |
413 | |
414 uint64_t | |
415 extract_py_uint64 (PyObject *obj) | |
416 { | |
417 if (! obj) | |
418 throw object_convert_exception ("failed to extract integer: null object"); | |
419 | |
420 if (PyLong_Check (obj)) | |
421 { | |
422 // FIXME: if (value < 0), may be very implementation dependent | |
423 if (Py_SIZE (obj) < 0) | |
424 return 0; | |
425 | |
426 #if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) | |
427 unsigned PY_LONG_LONG value = PyLong_AsUnsignedLongLong (obj); | |
428 bool overflow = (value == static_cast<unsigned PY_LONG_LONG> (-1)); | |
429 #else | |
430 unsigned long value = PyLong_AsUnsignedLong (obj); | |
431 bool overflow = (value == static_cast<unsigned long> (-1)); | |
432 #endif | |
433 if (overflow) | |
434 { | |
435 value = std::numeric_limits<uint64_t>::max (); | |
436 PyErr_Clear (); | |
437 } | |
438 | |
439 return static_cast<uint64_t> (value); | |
440 } | |
441 #if PY_VERSION_HEX < 0x03000000 | |
442 else if (PyInt_Check (obj)) | |
443 return static_cast<uint64_t> (PyInt_AsLong (obj)); | |
444 #endif | |
445 else | |
446 throw object_convert_exception ("failed to extract integer: wrong type"); | |
447 | |
448 return 0; | |
449 } | |
450 | |
451 PyObject * | |
452 make_py_tuple (const Cell& cell) | |
453 { | |
454 if (! (cell.is_empty () || cell.is_vector ())) | |
455 throw value_convert_exception ( | |
456 "unable to convert multidimensional cell array into Python tuple"); | |
457 | |
458 octave_idx_type size = cell.numel (); | |
459 PyObject *tuple = PyTuple_New (size); | |
460 if (! tuple) | |
461 octave_throw_bad_alloc (); | |
462 | |
463 for (octave_idx_type i = 0; i < size; ++i) | |
464 { | |
465 PyObject *item = wrap_octvalue_to_pyobj (cell.xelem (i)); | |
466 PyTuple_SET_ITEM (tuple, i, item); | |
467 } | |
468 | |
469 return tuple; | |
470 } | |
471 | |
472 std::string | |
473 extract_py_str (PyObject *obj) | |
474 { | |
475 std::string retval; | |
476 | |
477 if (! obj) | |
478 throw object_convert_exception ("failed to extract string: null object"); | |
479 if (PyBytes_Check (obj)) | |
480 { | |
481 retval.assign (PyBytes_AsString (obj), PyBytes_Size (obj)); | |
482 } | |
483 else if (PyUnicode_Check (obj)) | |
484 { | |
485 bool ok = false; | |
486 PyObject *enc = PyUnicode_AsUTF8String (obj); | |
487 if (enc) | |
488 { | |
489 if (PyBytes_Check (enc)) | |
490 { | |
491 ok = true; | |
492 retval.assign (PyBytes_AsString (enc), PyBytes_Size (enc)); | |
493 } | |
494 Py_DECREF (enc); | |
495 } | |
496 if (! ok) | |
497 throw object_convert_exception ("failed to extract string: UTF-8 error"); | |
498 } | |
499 else | |
500 throw object_convert_exception ("failed to extract string: wrong type"); | |
501 | |
502 return retval; | |
503 } | |
504 | |
505 PyObject * | |
506 make_py_str (const std::string& str) | |
507 { | |
508 #if PY_VERSION_HEX >= 0x03000000 | |
509 return PyUnicode_FromStringAndSize (str.data (), str.size ()); | |
510 #else | |
511 return PyString_FromStringAndSize (str.data (), str.size ()); | |
512 #endif | |
513 } | |
514 | |
515 } |