You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
9.5 KiB

4 years ago
  1. #include "_pair_list.h"
  2. #include <Python.h>
  3. // fix for VisualC complier used by Python 3.4
  4. #ifdef __GNUC__
  5. #define INLINE inline
  6. #else
  7. #define INLINE
  8. #endif
  9. static PyTypeObject multidict_items_iter_type;
  10. static PyTypeObject multidict_values_iter_type;
  11. static PyTypeObject multidict_keys_iter_type;
  12. typedef struct multidict_iter {
  13. PyObject_HEAD
  14. PyObject *impl;
  15. Py_ssize_t current;
  16. uint64_t version;
  17. } MultidictIter;
  18. static INLINE void
  19. _init_iter(MultidictIter *it, PyObject *impl)
  20. {
  21. Py_INCREF(impl);
  22. it->impl = impl;
  23. it->current = 0;
  24. it->version = pair_list_version(impl);
  25. }
  26. PyObject *
  27. multidict_items_iter_new(PyObject *impl)
  28. {
  29. MultidictIter *it = PyObject_GC_New(
  30. MultidictIter, &multidict_items_iter_type);
  31. if (it == NULL) {
  32. return NULL;
  33. }
  34. _init_iter(it, impl);
  35. return (PyObject *)it;
  36. }
  37. PyObject *
  38. multidict_keys_iter_new(PyObject *impl)
  39. {
  40. MultidictIter *it = PyObject_GC_New(
  41. MultidictIter, &multidict_keys_iter_type);
  42. if (it == NULL) {
  43. return NULL;
  44. }
  45. _init_iter(it, impl);
  46. return (PyObject *)it;
  47. }
  48. PyObject *
  49. multidict_values_iter_new(PyObject *impl)
  50. {
  51. MultidictIter *it = PyObject_GC_New(
  52. MultidictIter, &multidict_values_iter_type);
  53. if (it == NULL) {
  54. return NULL;
  55. }
  56. _init_iter(it, impl);
  57. return (PyObject *)it;
  58. }
  59. static PyObject *
  60. multidict_items_iter_iternext(MultidictIter *self)
  61. {
  62. PyObject *key = NULL;
  63. PyObject *value = NULL;
  64. PyObject *ret = NULL;
  65. if (self->version != pair_list_version(self->impl)) {
  66. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  67. return NULL;
  68. }
  69. if (!_pair_list_next(self->impl, &self->current, NULL, &key, &value, NULL)) {
  70. PyErr_SetNone(PyExc_StopIteration);
  71. return NULL;
  72. }
  73. ret = PyTuple_Pack(2, key, value);
  74. if (ret == NULL) {
  75. return NULL;
  76. }
  77. return ret;
  78. }
  79. static PyObject *
  80. multidict_values_iter_iternext(MultidictIter *self)
  81. {
  82. PyObject *value = NULL;
  83. if (self->version != pair_list_version(self->impl)) {
  84. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  85. return NULL;
  86. }
  87. if (!pair_list_next(self->impl, &self->current, NULL, NULL, &value)) {
  88. PyErr_SetNone(PyExc_StopIteration);
  89. return NULL;
  90. }
  91. Py_INCREF(value);
  92. return value;
  93. }
  94. static PyObject *
  95. multidict_keys_iter_iternext(MultidictIter *self)
  96. {
  97. PyObject *key = NULL;
  98. if (self->version != pair_list_version(self->impl)) {
  99. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  100. return NULL;
  101. }
  102. if (!pair_list_next(self->impl, &self->current, NULL, &key, NULL)) {
  103. PyErr_SetNone(PyExc_StopIteration);
  104. return NULL;
  105. }
  106. Py_INCREF(key);
  107. return key;
  108. }
  109. static void
  110. multidict_iter_dealloc(MultidictIter *self)
  111. {
  112. PyObject_GC_UnTrack(self);
  113. Py_XDECREF(self->impl);
  114. PyObject_GC_Del(self);
  115. }
  116. static int
  117. multidict_iter_traverse(MultidictIter *self, visitproc visit, void *arg)
  118. {
  119. Py_VISIT(self->impl);
  120. return 0;
  121. }
  122. static int
  123. multidict_iter_clear(MultidictIter *self)
  124. {
  125. Py_CLEAR(self->impl);
  126. return 0;
  127. }
  128. /***********************************************************************/
  129. /* We link this module statically for convenience. If compiled as a shared
  130. library instead, some compilers don't allow addresses of Python objects
  131. defined in other libraries to be used in static initializers here. The
  132. DEFERRED_ADDRESS macro is used to tag the slots where such addresses
  133. appear; the module init function must fill in the tagged slots at runtime.
  134. The argument is for documentation -- the macro ignores it.
  135. */
  136. #define DEFERRED_ADDRESS(ADDR) 0
  137. static PyTypeObject multidict_items_iter_type = {
  138. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  139. "multidict._multidict_iter._itemsiter", /* tp_name */
  140. sizeof(MultidictIter), /* tp_basicsize */
  141. 0, /* tp_itemsize */
  142. (destructor)multidict_iter_dealloc, /* tp_dealloc */
  143. 0, /* tp_print */
  144. 0, /* tp_getattr */
  145. 0, /* tp_setattr */
  146. 0, /* tp_reserved */
  147. 0, /* tp_repr */
  148. 0, /* tp_as_number */
  149. 0, /* tp_as_sequence */
  150. 0, /* tp_as_mapping */
  151. 0, /* tp_hash */
  152. 0, /* tp_call */
  153. 0, /* tp_str */
  154. 0, /* tp_getattro */
  155. 0, /* tp_setattro */
  156. 0, /* tp_as_buffer */
  157. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
  158. 0, /* tp_doc */
  159. (traverseproc)multidict_iter_traverse, /* tp_traverse */
  160. (inquiry)multidict_iter_clear, /* tp_clear */
  161. 0, /* tp_richcompare */
  162. 0, /* tp_weaklistoffset */
  163. PyObject_SelfIter, /* tp_iter */
  164. (iternextfunc)multidict_items_iter_iternext, /* tp_iternext */
  165. };
  166. static PyTypeObject multidict_values_iter_type = {
  167. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  168. "multidict._multidict_iter._valuesiter", /* tp_name */
  169. sizeof(MultidictIter), /* tp_basicsize */
  170. 0, /* tp_itemsize */
  171. (destructor)multidict_iter_dealloc, /* tp_dealloc */
  172. 0, /* tp_print */
  173. 0, /* tp_getattr */
  174. 0, /* tp_setattr */
  175. 0, /* tp_reserved */
  176. 0, /* tp_repr */
  177. 0, /* tp_as_number */
  178. 0, /* tp_as_sequence */
  179. 0, /* tp_as_mapping */
  180. 0, /* tp_hash */
  181. 0, /* tp_call */
  182. 0, /* tp_str */
  183. 0, /* tp_getattro */
  184. 0, /* tp_setattro */
  185. 0, /* tp_as_buffer */
  186. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
  187. 0, /* tp_doc */
  188. (traverseproc)multidict_iter_traverse, /* tp_traverse */
  189. (inquiry)multidict_iter_clear, /* tp_clear */
  190. 0, /* tp_richcompare */
  191. 0, /* tp_weaklistoffset */
  192. PyObject_SelfIter, /* tp_iter */
  193. (iternextfunc)multidict_values_iter_iternext, /* tp_iternext */
  194. };
  195. static PyTypeObject multidict_keys_iter_type = {
  196. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  197. "multidict._multidict_iter._keysiter", /* tp_name */
  198. sizeof(MultidictIter), /* tp_basicsize */
  199. 0, /* tp_itemsize */
  200. (destructor)multidict_iter_dealloc, /* tp_dealloc */
  201. 0, /* tp_print */
  202. 0, /* tp_getattr */
  203. 0, /* tp_setattr */
  204. 0, /* tp_reserved */
  205. 0, /* tp_repr */
  206. 0, /* tp_as_number */
  207. 0, /* tp_as_sequence */
  208. 0, /* tp_as_mapping */
  209. 0, /* tp_hash */
  210. 0, /* tp_call */
  211. 0, /* tp_str */
  212. 0, /* tp_getattro */
  213. 0, /* tp_setattro */
  214. 0, /* tp_as_buffer */
  215. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
  216. 0, /* tp_doc */
  217. (traverseproc)multidict_iter_traverse, /* tp_traverse */
  218. (inquiry)multidict_iter_clear, /* tp_clear */
  219. 0, /* tp_richcompare */
  220. 0, /* tp_weaklistoffset */
  221. PyObject_SelfIter, /* tp_iter */
  222. (iternextfunc)multidict_keys_iter_iternext, /* tp_iternext */
  223. };
  224. int
  225. multidict_iter_init()
  226. {
  227. if (PyType_Ready(&multidict_items_iter_type) < 0 ||
  228. PyType_Ready(&multidict_values_iter_type) < 0 ||
  229. PyType_Ready(&multidict_keys_iter_type) < 0) {
  230. return -1;
  231. }
  232. return 0;
  233. }