iter.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #ifndef _MULTIDICT_ITER_H
  2. #define _MULTIDICT_ITER_H
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. static PyTypeObject multidict_items_iter_type;
  7. static PyTypeObject multidict_values_iter_type;
  8. static PyTypeObject multidict_keys_iter_type;
  9. typedef struct multidict_iter {
  10. PyObject_HEAD
  11. MultiDictObject *md; // MultiDict or CIMultiDict
  12. Py_ssize_t current;
  13. uint64_t version;
  14. } MultidictIter;
  15. static inline void
  16. _init_iter(MultidictIter *it, MultiDictObject *md)
  17. {
  18. Py_INCREF(md);
  19. it->md = md;
  20. it->current = 0;
  21. it->version = pair_list_version(&md->pairs);
  22. }
  23. static inline PyObject *
  24. multidict_items_iter_new(MultiDictObject *md)
  25. {
  26. MultidictIter *it = PyObject_GC_New(
  27. MultidictIter, &multidict_items_iter_type);
  28. if (it == NULL) {
  29. return NULL;
  30. }
  31. _init_iter(it, md);
  32. PyObject_GC_Track(it);
  33. return (PyObject *)it;
  34. }
  35. static inline PyObject *
  36. multidict_keys_iter_new(MultiDictObject *md)
  37. {
  38. MultidictIter *it = PyObject_GC_New(
  39. MultidictIter, &multidict_keys_iter_type);
  40. if (it == NULL) {
  41. return NULL;
  42. }
  43. _init_iter(it, md);
  44. PyObject_GC_Track(it);
  45. return (PyObject *)it;
  46. }
  47. static inline PyObject *
  48. multidict_values_iter_new(MultiDictObject *md)
  49. {
  50. MultidictIter *it = PyObject_GC_New(
  51. MultidictIter, &multidict_values_iter_type);
  52. if (it == NULL) {
  53. return NULL;
  54. }
  55. _init_iter(it, md);
  56. PyObject_GC_Track(it);
  57. return (PyObject *)it;
  58. }
  59. static inline 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->md->pairs)) {
  66. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  67. return NULL;
  68. }
  69. if (!_pair_list_next(&self->md->pairs, &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 inline PyObject *
  80. multidict_values_iter_iternext(MultidictIter *self)
  81. {
  82. PyObject *value = NULL;
  83. if (self->version != pair_list_version(&self->md->pairs)) {
  84. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  85. return NULL;
  86. }
  87. if (!pair_list_next(&self->md->pairs, &self->current, NULL, NULL, &value)) {
  88. PyErr_SetNone(PyExc_StopIteration);
  89. return NULL;
  90. }
  91. Py_INCREF(value);
  92. return value;
  93. }
  94. static inline PyObject *
  95. multidict_keys_iter_iternext(MultidictIter *self)
  96. {
  97. PyObject *key = NULL;
  98. if (self->version != pair_list_version(&self->md->pairs)) {
  99. PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
  100. return NULL;
  101. }
  102. if (!pair_list_next(&self->md->pairs, &self->current, NULL, &key, NULL)) {
  103. PyErr_SetNone(PyExc_StopIteration);
  104. return NULL;
  105. }
  106. Py_INCREF(key);
  107. return key;
  108. }
  109. static inline void
  110. multidict_iter_dealloc(MultidictIter *self)
  111. {
  112. PyObject_GC_UnTrack(self);
  113. Py_XDECREF(self->md);
  114. PyObject_GC_Del(self);
  115. }
  116. static inline int
  117. multidict_iter_traverse(MultidictIter *self, visitproc visit, void *arg)
  118. {
  119. Py_VISIT(self->md);
  120. return 0;
  121. }
  122. static inline int
  123. multidict_iter_clear(MultidictIter *self)
  124. {
  125. Py_CLEAR(self->md);
  126. return 0;
  127. }
  128. static inline PyObject *
  129. multidict_iter_len(MultidictIter *self)
  130. {
  131. return PyLong_FromLong(pair_list_len(&self->md->pairs));
  132. }
  133. PyDoc_STRVAR(length_hint_doc,
  134. "Private method returning an estimate of len(list(it)).");
  135. static PyMethodDef multidict_iter_methods[] = {
  136. {
  137. "__length_hint__",
  138. (PyCFunction)(void(*)(void))multidict_iter_len,
  139. METH_NOARGS,
  140. length_hint_doc
  141. },
  142. {
  143. NULL,
  144. NULL
  145. } /* sentinel */
  146. };
  147. /***********************************************************************/
  148. static PyTypeObject multidict_items_iter_type = {
  149. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  150. "multidict._multidict._itemsiter", /* tp_name */
  151. sizeof(MultidictIter), /* tp_basicsize */
  152. .tp_dealloc = (destructor)multidict_iter_dealloc,
  153. .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
  154. .tp_traverse = (traverseproc)multidict_iter_traverse,
  155. .tp_clear = (inquiry)multidict_iter_clear,
  156. .tp_iter = PyObject_SelfIter,
  157. .tp_iternext = (iternextfunc)multidict_items_iter_iternext,
  158. .tp_methods = multidict_iter_methods,
  159. };
  160. static PyTypeObject multidict_values_iter_type = {
  161. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  162. "multidict._multidict._valuesiter", /* tp_name */
  163. sizeof(MultidictIter), /* tp_basicsize */
  164. .tp_dealloc = (destructor)multidict_iter_dealloc,
  165. .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
  166. .tp_traverse = (traverseproc)multidict_iter_traverse,
  167. .tp_clear = (inquiry)multidict_iter_clear,
  168. .tp_iter = PyObject_SelfIter,
  169. .tp_iternext = (iternextfunc)multidict_values_iter_iternext,
  170. .tp_methods = multidict_iter_methods,
  171. };
  172. static PyTypeObject multidict_keys_iter_type = {
  173. PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
  174. "multidict._multidict._keysiter", /* tp_name */
  175. sizeof(MultidictIter), /* tp_basicsize */
  176. .tp_dealloc = (destructor)multidict_iter_dealloc,
  177. .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
  178. .tp_traverse = (traverseproc)multidict_iter_traverse,
  179. .tp_clear = (inquiry)multidict_iter_clear,
  180. .tp_iter = PyObject_SelfIter,
  181. .tp_iternext = (iternextfunc)multidict_keys_iter_iternext,
  182. .tp_methods = multidict_iter_methods,
  183. };
  184. static inline int
  185. multidict_iter_init()
  186. {
  187. if (PyType_Ready(&multidict_items_iter_type) < 0 ||
  188. PyType_Ready(&multidict_values_iter_type) < 0 ||
  189. PyType_Ready(&multidict_keys_iter_type) < 0) {
  190. return -1;
  191. }
  192. return 0;
  193. }
  194. #ifdef __cplusplus
  195. }
  196. #endif
  197. #endif