diff options
Diffstat (limited to 'src/if_py_both.h')
-rw-r--r-- | src/if_py_both.h | 251 |
1 files changed, 208 insertions, 43 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h index b4d074bf1..6370bd18a 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -531,66 +531,62 @@ static struct PyMethodDef VimMethods[] = { }; /* - * Buffer list object - Implementation + * Generic iterator object */ -static PyTypeObject BufMapType; +static PyTypeObject IterType; + +typedef PyObject *(*nextfun)(void **); +typedef void (*destructorfun)(void *); + +/* Main purpose of this object is removing the need for do python initialization + * (i.e. PyType_Ready and setting type attributes) for a big bunch of objects. + */ typedef struct { PyObject_HEAD -} BufMapObject; + void *cur; + nextfun next; + destructorfun destruct; +} IterObject; - static PyInt -BufMapLength(PyObject *self UNUSED) + static PyObject * +IterNew(void *start, destructorfun destruct, nextfun next) { - buf_T *b = firstbuf; - PyInt n = 0; + IterObject *self; - while (b) - { - ++n; - b = b->b_next; - } + self = PyObject_NEW(IterObject, &IterType); + self->cur = start; + self->next = next; + self->destruct = destruct; - return n; + return (PyObject *)(self); } - static PyObject * -BufMapItem(PyObject *self UNUSED, PyObject *keyObject) + static void +IterDestructor(PyObject *self) { - buf_T *b; - int bnr; + IterObject *this = (IterObject *)(self); -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(keyObject)) - bnr = PyInt_AsLong(keyObject); - else -#endif - if (PyLong_Check(keyObject)) - bnr = PyLong_AsLong(keyObject); - else - { - PyErr_SetString(PyExc_ValueError, _("key must be integer")); - return NULL; - } + this->destruct(this->cur); - b = buflist_findnr(bnr); + DESTRUCTOR_FINISH(self); +} - if (b) - return BufferNew(b); - else - { - PyErr_SetString(PyExc_KeyError, _("no such buffer")); - return NULL; - } + static PyObject * +IterNext(PyObject *self) +{ + IterObject *this = (IterObject *)(self); + + return this->next(&this->cur); } -static PyMappingMethods BufMapAsMapping = { - (lenfunc) BufMapLength, - (binaryfunc) BufMapItem, - (objobjargproc) 0, -}; + static PyObject * +IterIter(PyObject *self) +{ + return self; +} typedef struct pylinkedlist_S { struct pylinkedlist_S *pll_next; @@ -990,6 +986,55 @@ ListSlice(PyObject *self, Py_ssize_t first, Py_ssize_t last) return list; } +typedef struct +{ + listwatch_T lw; + list_T *list; +} listiterinfo_T; + + static void +ListIterDestruct(listiterinfo_T *lii) +{ + list_rem_watch(lii->list, &lii->lw); + PyMem_Free(lii); +} + + static PyObject * +ListIterNext(listiterinfo_T **lii) +{ + PyObject *r; + + if (!((*lii)->lw.lw_item)) + return NULL; + + if (!(r = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) + return NULL; + + (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next; + + return r; +} + + static PyObject * +ListIter(PyObject *self) +{ + listiterinfo_T *lii; + list_T *l = ((ListObject *) (self))->list; + + if (!(lii = PyMem_New(listiterinfo_T, 1))) + { + PyErr_NoMemory(); + return NULL; + } + + list_add_watch(l, &lii->lw); + lii->lw.lw_item = l->lv_first; + lii->list = l; + + return IterNew(lii, + (destructorfun) ListIterDestruct, (nextfun) ListIterNext); +} + static int ListAssItem(PyObject *self, Py_ssize_t index, PyObject *obj) { @@ -2869,6 +2914,116 @@ static struct PyMethodDef BufferMethods[] = { { NULL, NULL, 0, NULL } }; +/* + * Buffer list object - Implementation + */ + +static PyTypeObject BufMapType; + +typedef struct +{ + PyObject_HEAD +} BufMapObject; + + static PyInt +BufMapLength(PyObject *self UNUSED) +{ + buf_T *b = firstbuf; + PyInt n = 0; + + while (b) + { + ++n; + b = b->b_next; + } + + return n; +} + + static PyObject * +BufMapItem(PyObject *self UNUSED, PyObject *keyObject) +{ + buf_T *b; + int bnr; + +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(keyObject)) + bnr = PyInt_AsLong(keyObject); + else +#endif + if (PyLong_Check(keyObject)) + bnr = PyLong_AsLong(keyObject); + else + { + PyErr_SetString(PyExc_ValueError, _("key must be integer")); + return NULL; + } + + b = buflist_findnr(bnr); + + if (b) + return BufferNew(b); + else + { + PyErr_SetString(PyExc_KeyError, _("no such buffer")); + return NULL; + } +} + + static void +BufMapIterDestruct(PyObject *buffer) +{ + /* Iteration was stopped before all buffers were processed */ + if (buffer) + { + Py_DECREF(buffer); + } +} + + static PyObject * +BufMapIterNext(PyObject **buffer) +{ + PyObject *next; + PyObject *r; + + if (!*buffer) + return NULL; + + r = *buffer; + + if (CheckBuffer((BufferObject *)(r))) + { + *buffer = NULL; + return NULL; + } + + if (!((BufferObject *)(r))->buf->b_next) + next = NULL; + else if (!(next = BufferNew(((BufferObject *)(r))->buf->b_next))) + return NULL; + *buffer = next; + /* Do not increment reference: we no longer hold it (decref), but whoever on + * other side will hold (incref). Decref+incref = nothing. + */ + return r; +} + + static PyObject * +BufMapIter(PyObject *self UNUSED) +{ + PyObject *buffer; + + buffer = BufferNew(firstbuf); + return IterNew(buffer, + (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext); +} + +static PyMappingMethods BufMapAsMapping = { + (lenfunc) BufMapLength, + (binaryfunc) BufMapItem, + (objobjargproc) 0, +}; + /* Current items object */ @@ -3383,6 +3538,14 @@ init_structs(void) OutputType.tp_setattr = OutputSetattr; #endif + vim_memset(&IterType, 0, sizeof(IterType)); + IterType.tp_name = "vim.iter"; + IterType.tp_basicsize = sizeof(IterObject); + IterType.tp_flags = Py_TPFLAGS_DEFAULT; + IterType.tp_doc = "generic iterator object"; + IterType.tp_iter = IterIter; + IterType.tp_iternext = IterNext; + vim_memset(&BufferType, 0, sizeof(BufferType)); BufferType.tp_name = "vim.buffer"; BufferType.tp_basicsize = sizeof(BufferType); @@ -3426,6 +3589,7 @@ init_structs(void) BufMapType.tp_basicsize = sizeof(BufMapObject); BufMapType.tp_as_mapping = &BufMapAsMapping; BufMapType.tp_flags = Py_TPFLAGS_DEFAULT; + BufMapType.tp_iter = BufMapIter; BufferType.tp_doc = "vim buffer list"; vim_memset(&WinListType, 0, sizeof(WinListType)); @@ -3492,6 +3656,7 @@ init_structs(void) ListType.tp_flags = Py_TPFLAGS_DEFAULT; ListType.tp_doc = "list pushing modifications to vim structure"; ListType.tp_methods = ListMethods; + ListType.tp_iter = ListIter; #if PY_MAJOR_VERSION >= 3 ListType.tp_getattro = ListGetattro; ListType.tp_setattro = ListSetattro; @@ -3501,7 +3666,7 @@ init_structs(void) #endif vim_memset(&FunctionType, 0, sizeof(FunctionType)); - FunctionType.tp_name = "vim.list"; + FunctionType.tp_name = "vim.function"; FunctionType.tp_basicsize = sizeof(FunctionObject); FunctionType.tp_dealloc = FunctionDestructor; FunctionType.tp_call = FunctionCall; |