pointerToArray_ext.I 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file pointerToArray_ext.I
  10. * @author rdb
  11. * @date 2015-02-08
  12. */
  13. /**
  14. * This special constructor accepts a Python list of elements, or a Python
  15. * string (or a bytes object, in Python 3), or any object that supports the
  16. * Python buffer protocol.
  17. */
  18. template<class Element>
  19. INLINE void Extension<PointerToArray<Element> >::
  20. __init__(PyObject *self, PyObject *source) {
  21. #if PY_VERSION_HEX >= 0x02060000
  22. if (PyObject_CheckBuffer(source)) {
  23. // User passed a buffer object.
  24. Py_buffer view;
  25. if (PyObject_GetBuffer(source, &view, PyBUF_CONTIG_RO) == -1) {
  26. PyErr_SetString(PyExc_TypeError,
  27. "PointerToArray constructor requires a contiguous buffer");
  28. return;
  29. }
  30. if (view.itemsize != 1 && view.itemsize != sizeof(Element)) {
  31. PyErr_SetString(PyExc_TypeError,
  32. "buffer.itemsize does not match PointerToArray element size");
  33. return;
  34. }
  35. if (view.len % sizeof(Element) != 0) {
  36. PyErr_Format(PyExc_ValueError,
  37. "byte buffer is not a multiple of %zu bytes",
  38. sizeof(Element));
  39. return;
  40. }
  41. if (view.len > 0) {
  42. this->_this->resize(view.len / sizeof(Element));
  43. memcpy(this->_this->p(), view.buf, view.len);
  44. }
  45. PyBuffer_Release(&view);
  46. return;
  47. }
  48. #endif
  49. if (!PySequence_Check(source)) {
  50. // If passed with a non-sequence, this isn't the right constructor.
  51. PyErr_SetString(PyExc_TypeError,
  52. "PointerToArray constructor requires a sequence or buffer object");
  53. return;
  54. }
  55. // If we were passed a Python string, then instead of storing it character-
  56. // at-a-time, just load the whole string as a data buffer. Not sure if this
  57. // case is still necessary - don't Python strbytes objects export the buffer
  58. // protocol, as above?
  59. #if PY_MAJOR_VERSION >= 3
  60. if (PyBytes_Check(source)) {
  61. int size = PyBytes_Size(source);
  62. if (size % sizeof(Element) != 0) {
  63. PyErr_Format(PyExc_ValueError,
  64. "bytes object is not a multiple of %zu bytes",
  65. sizeof(Element));
  66. return;
  67. }
  68. int num_elements = size / sizeof(Element);
  69. this->_this->insert(this->_this->begin(), num_elements, Element());
  70. // Hope there aren't any constructors or destructors involved here.
  71. if (size != 0) {
  72. const char *data = PyBytes_AsString(source);
  73. memcpy(this->_this->p(), data, size);
  74. }
  75. return;
  76. }
  77. #else
  78. if (PyString_CheckExact(source)) {
  79. int size = PyString_Size(source);
  80. if (size % sizeof(Element) != 0) {
  81. PyErr_Format(PyExc_ValueError,
  82. "str object is not a multiple of %zu bytes",
  83. sizeof(Element));
  84. return;
  85. }
  86. int num_elements = size / sizeof(Element);
  87. this->_this->insert(this->_this->begin(), num_elements, Element());
  88. // Hope there aren't any constructors or destructors involved here.
  89. if (size != 0) {
  90. const char *data = PyString_AsString(source);
  91. memcpy(this->_this->p(), data, size);
  92. }
  93. return;
  94. }
  95. #endif
  96. // Now construct the internal list by copying the elements one-at-a-time
  97. // from Python.
  98. PyObject *push_back = PyObject_GetAttrString(self, "push_back");
  99. if (push_back == NULL) {
  100. PyErr_BadArgument();
  101. return;
  102. }
  103. // We need to initialize the this pointer before we can call push_back.
  104. ((Dtool_PyInstDef *)self)->_ptr_to_object = (void *)this->_this;
  105. int size = PySequence_Size(source);
  106. for (int i = 0; i < size; ++i) {
  107. PyObject *item = PySequence_GetItem(source, i);
  108. if (item == NULL) {
  109. return;
  110. }
  111. PyObject *result = PyObject_CallFunctionObjArgs(push_back, item, NULL);
  112. Py_DECREF(item);
  113. if (result == NULL) {
  114. // Unable to add item--probably it wasn't of the appropriate type.
  115. PyErr_Print();
  116. PyErr_Format(PyExc_TypeError,
  117. "Element %d in sequence passed to PointerToArray "
  118. "constructor could not be added", i);
  119. return;
  120. }
  121. Py_DECREF(result);
  122. }
  123. }
  124. /**
  125. * Same as get_element(), this returns the nth element of the array.
  126. */
  127. template<class Element>
  128. INLINE const Element &Extension<PointerToArray<Element> >::
  129. __getitem__(size_t n) const {
  130. return this->_this->get_element(n);
  131. }
  132. /**
  133. * Same as set_element(), this replaces the nth element of the array.
  134. */
  135. template<class Element>
  136. INLINE void Extension<PointerToArray<Element> >::
  137. __setitem__(size_t n, const Element &value) {
  138. this->_this->set_element(n, value);
  139. }
  140. /**
  141. * This special constructor accepts a Python list of elements, or a Python
  142. * string (or a bytes object, in Python 3).
  143. */
  144. template<class Element>
  145. INLINE void Extension<ConstPointerToArray<Element> >::
  146. __init__(PyObject *self, PyObject *source) {
  147. PointerToArray<Element> array;
  148. invoke_extension(&array).__init__(self, source);
  149. *(this->_this) = MOVE(array);
  150. }
  151. /**
  152. * Same as get_element(), this returns the nth element of the array.
  153. */
  154. template<class Element>
  155. INLINE const Element &Extension<ConstPointerToArray<Element> >::
  156. __getitem__(size_t n) const {
  157. return (*this->_this)[n];
  158. }
  159. /**
  160. * This is used to implement the buffer protocol, in order to allow efficient
  161. * access to the array data through a Python multiview object.
  162. */
  163. template<class Element>
  164. INLINE int Extension<PointerToArray<Element> >::
  165. __getbuffer__(PyObject *self, Py_buffer *view, int flags) {
  166. #if PY_VERSION_HEX >= 0x02060000
  167. const char *format = get_format_code(Element);
  168. if (format == NULL) {
  169. // Not supported.
  170. return -1;
  171. }
  172. if (self != NULL) {
  173. Py_INCREF(self);
  174. }
  175. view->obj = self;
  176. view->buf = (void*) this->_this->p();
  177. view->len = this->_this->size() * sizeof(Element);
  178. view->readonly = 0;
  179. view->itemsize = sizeof(Element);
  180. view->format = NULL;
  181. if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
  182. view->format = (char*) format;
  183. }
  184. view->ndim = 1;
  185. view->shape = NULL;
  186. if ((flags & PyBUF_ND) == PyBUF_ND) {
  187. // This leaks, which sucks, but __releasebuffer__ doesn't give us the same
  188. // pointer, so we would need to store it elsewhere if we wanted to delete
  189. // it there. Eh, it's just an int, who cares.
  190. view->shape = new Py_ssize_t(this->_this->size());
  191. }
  192. view->strides = NULL;
  193. if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
  194. view->strides = &(view->itemsize);
  195. }
  196. view->suboffsets = NULL;
  197. // Store a reference to ourselves on the Py_buffer object as a reminder that
  198. // we have increased our refcount.
  199. this->_this->ref();
  200. view->internal = (void*) this->_this;
  201. return 0;
  202. #else
  203. return -1;
  204. #endif
  205. }
  206. /**
  207. * Releases the buffer allocated by __getbuffer__.
  208. */
  209. template<class Element>
  210. INLINE void Extension<PointerToArray<Element> >::
  211. __releasebuffer__(PyObject *self, Py_buffer *view) const {
  212. #if PY_VERSION_HEX >= 0x02060000
  213. // Note: PyBuffer_Release automatically decrements view->obj.
  214. if (view->internal != NULL) {
  215. // Oh, right, let's not forget to unref this.
  216. unref_delete((const PointerToArray<Element> *)view->internal);
  217. view->internal = NULL;
  218. }
  219. #endif
  220. }
  221. /**
  222. * This is used to implement the buffer protocol, in order to allow efficient
  223. * access to the array data through a Python multiview object.
  224. */
  225. template<class Element>
  226. INLINE int Extension<ConstPointerToArray<Element> >::
  227. __getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
  228. #if PY_VERSION_HEX >= 0x02060000
  229. if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) {
  230. PyErr_SetString(PyExc_BufferError,
  231. "Object is not writable.");
  232. return -1;
  233. }
  234. const char *format = get_format_code(Element);
  235. if (format == NULL) {
  236. // Not supported.
  237. return -1;
  238. }
  239. if (self != NULL) {
  240. Py_INCREF(self);
  241. }
  242. view->obj = self;
  243. view->buf = (void*) this->_this->p();
  244. view->len = this->_this->size() * sizeof(Element);
  245. view->readonly = 1;
  246. view->itemsize = sizeof(Element);
  247. view->format = NULL;
  248. if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
  249. view->format = (char*) format;
  250. }
  251. view->ndim = 1;
  252. view->shape = NULL;
  253. if ((flags & PyBUF_ND) == PyBUF_ND) {
  254. // This leaks, which sucks, but __releasebuffer__ doesn't give us the same
  255. // pointer, so we would need to store it elsewhere if we wanted to delete
  256. // it there. Eh, it's just an int, who cares.
  257. view->shape = new Py_ssize_t(this->_this->size());
  258. }
  259. view->strides = NULL;
  260. if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
  261. view->strides = &(view->itemsize);
  262. }
  263. view->suboffsets = NULL;
  264. // Store a reference to ourselves on the Py_buffer object as a reminder that
  265. // we have increased our refcount.
  266. this->_this->ref();
  267. view->internal = (void*) this->_this;
  268. return 0;
  269. #else
  270. return -1;
  271. #endif
  272. }
  273. /**
  274. * Releases the buffer allocated by __getbuffer__.
  275. */
  276. template<class Element>
  277. INLINE void Extension<ConstPointerToArray<Element> >::
  278. __releasebuffer__(PyObject *self, Py_buffer *view) const {
  279. #if PY_VERSION_HEX >= 0x02060000
  280. // Note: PyBuffer_Release automatically decrements obj->view.
  281. if (view->internal != NULL) {
  282. // Oh, right, let's not forget to unref this.
  283. unref_delete((const PointerToArray<Element> *)view->internal);
  284. view->internal = NULL;
  285. }
  286. #endif
  287. }