#include "_pair_list.h" #include // fix for VisualC complier used by Python 3.4 #ifdef __GNUC__ #define INLINE inline #else #define INLINE #endif static PyTypeObject multidict_items_iter_type; static PyTypeObject multidict_values_iter_type; static PyTypeObject multidict_keys_iter_type; typedef struct multidict_iter { PyObject_HEAD PyObject *impl; Py_ssize_t current; uint64_t version; } MultidictIter; static INLINE void _init_iter(MultidictIter *it, PyObject *impl) { Py_INCREF(impl); it->impl = impl; it->current = 0; it->version = pair_list_version(impl); } PyObject * multidict_items_iter_new(PyObject *impl) { MultidictIter *it = PyObject_GC_New( MultidictIter, &multidict_items_iter_type); if (it == NULL) { return NULL; } _init_iter(it, impl); return (PyObject *)it; } PyObject * multidict_keys_iter_new(PyObject *impl) { MultidictIter *it = PyObject_GC_New( MultidictIter, &multidict_keys_iter_type); if (it == NULL) { return NULL; } _init_iter(it, impl); return (PyObject *)it; } PyObject * multidict_values_iter_new(PyObject *impl) { MultidictIter *it = PyObject_GC_New( MultidictIter, &multidict_values_iter_type); if (it == NULL) { return NULL; } _init_iter(it, impl); return (PyObject *)it; } static PyObject * multidict_items_iter_iternext(MultidictIter *self) { PyObject *key = NULL; PyObject *value = NULL; PyObject *ret = NULL; if (self->version != pair_list_version(self->impl)) { PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); return NULL; } if (!_pair_list_next(self->impl, &self->current, NULL, &key, &value, NULL)) { PyErr_SetNone(PyExc_StopIteration); return NULL; } ret = PyTuple_Pack(2, key, value); if (ret == NULL) { return NULL; } return ret; } static PyObject * multidict_values_iter_iternext(MultidictIter *self) { PyObject *value = NULL; if (self->version != pair_list_version(self->impl)) { PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); return NULL; } if (!pair_list_next(self->impl, &self->current, NULL, NULL, &value)) { PyErr_SetNone(PyExc_StopIteration); return NULL; } Py_INCREF(value); return value; } static PyObject * multidict_keys_iter_iternext(MultidictIter *self) { PyObject *key = NULL; if (self->version != pair_list_version(self->impl)) { PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration"); return NULL; } if (!pair_list_next(self->impl, &self->current, NULL, &key, NULL)) { PyErr_SetNone(PyExc_StopIteration); return NULL; } Py_INCREF(key); return key; } static void multidict_iter_dealloc(MultidictIter *self) { PyObject_GC_UnTrack(self); Py_XDECREF(self->impl); PyObject_GC_Del(self); } static int multidict_iter_traverse(MultidictIter *self, visitproc visit, void *arg) { Py_VISIT(self->impl); return 0; } static int multidict_iter_clear(MultidictIter *self) { Py_CLEAR(self->impl); return 0; } /***********************************************************************/ /* We link this module statically for convenience. If compiled as a shared library instead, some compilers don't allow addresses of Python objects defined in other libraries to be used in static initializers here. The DEFERRED_ADDRESS macro is used to tag the slots where such addresses appear; the module init function must fill in the tagged slots at runtime. The argument is for documentation -- the macro ignores it. */ #define DEFERRED_ADDRESS(ADDR) 0 static PyTypeObject multidict_items_iter_type = { PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) "multidict._multidict_iter._itemsiter", /* tp_name */ sizeof(MultidictIter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)multidict_iter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)multidict_iter_traverse, /* tp_traverse */ (inquiry)multidict_iter_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)multidict_items_iter_iternext, /* tp_iternext */ }; static PyTypeObject multidict_values_iter_type = { PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) "multidict._multidict_iter._valuesiter", /* tp_name */ sizeof(MultidictIter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)multidict_iter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)multidict_iter_traverse, /* tp_traverse */ (inquiry)multidict_iter_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)multidict_values_iter_iternext, /* tp_iternext */ }; static PyTypeObject multidict_keys_iter_type = { PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) "multidict._multidict_iter._keysiter", /* tp_name */ sizeof(MultidictIter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)multidict_iter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)multidict_iter_traverse, /* tp_traverse */ (inquiry)multidict_iter_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)multidict_keys_iter_iternext, /* tp_iternext */ }; int multidict_iter_init() { if (PyType_Ready(&multidict_items_iter_type) < 0 || PyType_Ready(&multidict_values_iter_type) < 0 || PyType_Ready(&multidict_keys_iter_type) < 0) { return -1; } return 0; }