diff options
author | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:36:51 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:36:51 +0100 |
commit | 063a46ba77c3251f0b5245e872dcbad003c71024 (patch) | |
tree | e85d7ca1c040ef4ecbef8f7bbbf7d92fe4ce823c /src/if_py_both.h | |
parent | 14177b77bf7bb9c3f1c7c8805bc6cff1b651c136 (diff) | |
download | vim-063a46ba77c3251f0b5245e872dcbad003c71024.zip |
updated for version 7.4.151
Problem: Python: slices with steps are not supported.
Solution: Support slices in Python vim.List. (ZyX)
Diffstat (limited to 'src/if_py_both.h')
-rw-r--r-- | src/if_py_both.h | 454 |
1 files changed, 329 insertions, 125 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h index 17c02a9ec..6e3939abe 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -36,8 +36,9 @@ static const char *vim_special_path = "_vim_path_"; #define PyErr_SET_STRING(exc, str) PyErr_SetString(exc, _(str)) #define PyErr_SetVim(str) PyErr_SetString(VimError, str) #define PyErr_SET_VIM(str) PyErr_SET_STRING(VimError, str) -#define PyErr_FORMAT(exc, str, tail) PyErr_Format(exc, _(str), tail) -#define PyErr_VIM_FORMAT(str, tail) PyErr_FORMAT(VimError, str, tail) +#define PyErr_FORMAT(exc, str, arg) PyErr_Format(exc, _(str), arg) +#define PyErr_FORMAT2(exc, str, arg1, arg2) PyErr_Format(exc, _(str), arg1,arg2) +#define PyErr_VIM_FORMAT(str, arg) PyErr_FORMAT(VimError, str, arg) #define Py_TYPE_NAME(obj) (obj->ob_type->tp_name == NULL \ ? "(NULL)" \ @@ -2108,8 +2109,6 @@ static struct PyMethodDef DictionaryMethods[] = { }; static PyTypeObject ListType; -static PySequenceMethods ListAsSeq; -static PyMappingMethods ListAsMapping; typedef struct { @@ -2253,7 +2252,7 @@ ListLength(ListObject *self) } static PyObject * -ListItem(ListObject *self, Py_ssize_t index) +ListIndex(ListObject *self, Py_ssize_t index) { listitem_T *li; @@ -2273,164 +2272,110 @@ ListItem(ListObject *self, Py_ssize_t index) return ConvertToPyObject(&li->li_tv); } -#define PROC_RANGE \ - if (last < 0) {\ - if (last < -size) \ - last = 0; \ - else \ - last += size; \ - } \ - if (first < 0) \ - first = 0; \ - if (first > size) \ - first = size; \ - if (last > size) \ - last = size; - static PyObject * -ListSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last) +ListSlice(ListObject *self, Py_ssize_t first, Py_ssize_t step, + Py_ssize_t slicelen) { PyInt i; - PyInt size = ListLength(self); - PyInt n; PyObject *list; - int reversed = 0; - PROC_RANGE - if (first >= last) - first = last; + if (step == 0) + { + PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero")); + return NULL; + } - n = last-first; - list = PyList_New(n); + list = PyList_New(slicelen); if (list == NULL) return NULL; - for (i = 0; i < n; ++i) + for (i = 0; i < slicelen; ++i) { - PyObject *item = ListItem(self, first + i); + PyObject *item; + + item = ListIndex(self, first + i*step); if (item == NULL) { Py_DECREF(list); return NULL; } - PyList_SET_ITEM(list, ((reversed)?(n-i-1):(i)), item); + PyList_SET_ITEM(list, i, item); } 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) +ListItem(ListObject *self, PyObject* idx) { - PyObject *ret; - - if (!((*lii)->lw.lw_item)) - return NULL; - - if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) - return NULL; - - (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next; - - return ret; -} - - static PyObject * -ListIter(ListObject *self) -{ - listiterinfo_T *lii; - list_T *l = self->list; - - if (!(lii = PyMem_New(listiterinfo_T, 1))) +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(idx)) { - PyErr_NoMemory(); - return NULL; + long _idx = PyInt_AsLong(idx); + return ListIndex(self, _idx); } - - list_add_watch(l, &lii->lw); - lii->lw.lw_item = l->lv_first; - lii->list = l; - - return IterNew(lii, - (destructorfun) ListIterDestruct, (nextfun) ListIterNext, - NULL, NULL); -} - - static int -ListAssItem(ListObject *self, Py_ssize_t index, PyObject *obj) -{ - typval_T tv; - list_T *l = self->list; - listitem_T *li; - Py_ssize_t length = ListLength(self); - - if (l->lv_lock) + else +#endif + if (PyLong_Check(idx)) { - RAISE_LOCKED_LIST; - return -1; + long _idx = PyLong_AsLong(idx); + return ListIndex(self, _idx); } - if (index > length || (index == length && obj == NULL)) + else if (PySlice_Check(idx)) { - PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range")); - return -1; - } + Py_ssize_t start, stop, step, slicelen; - if (obj == NULL) + if (PySlice_GetIndicesEx(idx, ListLength(self), + &start, &stop, &step, &slicelen) < 0) + return NULL; + return ListSlice(self, start, step, slicelen); + } + else { - li = list_find(l, (long) index); - list_remove(l, li, li); - clear_tv(&li->li_tv); - vim_free(li); - return 0; + RAISE_INVALID_INDEX_TYPE(idx); + return NULL; } +} - if (ConvertFromPyObject(obj, &tv) == -1) - return -1; - - if (index == length) + static void +list_restore(Py_ssize_t numadded, Py_ssize_t numreplaced, Py_ssize_t slicelen, + list_T *l, listitem_T **lis, listitem_T *lastaddedli) +{ + while (numreplaced--) { - if (list_append_tv(l, &tv) == FAIL) - { - clear_tv(&tv); - PyErr_SET_VIM(N_("failed to add item to list")); - return -1; - } + list_insert(l, lis[numreplaced], lis[slicelen + numreplaced]); + listitem_remove(l, lis[slicelen + numreplaced]); } - else + while (numadded--) { - li = list_find(l, (long) index); - clear_tv(&li->li_tv); - copy_tv(&tv, &li->li_tv); - clear_tv(&tv); + listitem_T *next; + + next = lastaddedli->li_prev; + listitem_remove(l, lastaddedli); + lastaddedli = next; } - return 0; } static int -ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) +ListAssSlice(ListObject *self, Py_ssize_t first, + Py_ssize_t step, Py_ssize_t slicelen, PyObject *obj) { - PyInt size = ListLength(self); PyObject *iterator; PyObject *item; listitem_T *li; + listitem_T *lastaddedli = NULL; listitem_T *next; typval_T v; list_T *l = self->list; PyInt i; + PyInt j; + PyInt numreplaced = 0; + PyInt numadded = 0; + PyInt size; + listitem_T **lis; + + size = ListLength(self); if (l->lv_lock) { @@ -2438,7 +2383,42 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) return -1; } - PROC_RANGE + if (step == 0) + { + PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero")); + return -1; + } + + if (step != 1 && slicelen == 0) + { + /* Nothing to do. Only error out if obj has some items. */ + int ret = 0; + + if (obj == NULL) + return 0; + + if (!(iterator = PyObject_GetIter(obj))) + return -1; + + if ((item = PyIter_Next(iterator))) + { + PyErr_FORMAT(PyExc_ValueError, + N_("attempt to assign sequence of size greater then %d " + "to extended slice"), 0); + Py_DECREF(item); + ret = -1; + } + Py_DECREF(iterator); + return ret; + } + + if (obj != NULL) + /* XXX May allocate zero bytes. */ + if (!(lis = PyMem_New(listitem_T *, slicelen * 2))) + { + PyErr_NoMemory(); + return -1; + } if (first == size) li = NULL; @@ -2449,17 +2429,33 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) { PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), (int)first); + if (obj != NULL) + PyMem_Free(lis); return -1; } - if (last > first) + i = slicelen; + while (i-- && li != NULL) { - i = last - first; - while (i-- && li != NULL) - { - next = li->li_next; + j = step; + next = li; + if (step > 0) + while (next != NULL && ((next = next->li_next) != NULL) && --j); + else + while (next != NULL && ((next = next->li_prev) != NULL) && ++j); + + if (obj == NULL) listitem_remove(l, li); - li = next; - } + else + lis[slicelen - i - 1] = li; + + li = next; + } + if (li == NULL && i != -1) + { + PyErr_SET_VIM(N_("internal error: not enough list items")); + if (obj != NULL) + PyMem_Free(lis); + return -1; } } @@ -2467,33 +2463,172 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) return 0; if (!(iterator = PyObject_GetIter(obj))) + { + PyMem_Free(lis); return -1; + } + i = 0; while ((item = PyIter_Next(iterator))) { if (ConvertFromPyObject(item, &v) == -1) { Py_DECREF(iterator); Py_DECREF(item); + PyMem_Free(lis); return -1; } Py_DECREF(item); - if (list_insert_tv(l, &v, li) == FAIL) + if (list_insert_tv(l, &v, numreplaced < slicelen + ? lis[numreplaced] + : li) == FAIL) { clear_tv(&v); PyErr_SET_VIM(N_("internal error: failed to add item to list")); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); return -1; } + if (numreplaced < slicelen) + { + lis[slicelen + numreplaced] = lis[numreplaced]->li_prev; + list_remove(l, lis[numreplaced], lis[numreplaced]); + numreplaced++; + } + else + { + if (li) + lastaddedli = li->li_prev; + else + lastaddedli = l->lv_last; + numadded++; + } clear_tv(&v); + if (step != 1 && i >= slicelen) + { + Py_DECREF(iterator); + PyErr_FORMAT(PyExc_ValueError, + N_("attempt to assign sequence of size greater then %d " + "to extended slice"), slicelen); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + ++i; } Py_DECREF(iterator); + if (step != 1 && i != slicelen) + { + PyErr_FORMAT2(PyExc_ValueError, + N_("attempt to assign sequence of size %d to extended slice " + "of size %d"), i, slicelen); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + if (PyErr_Occurred()) + { + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + + for (i = 0; i < numreplaced; i++) + listitem_free(lis[i]); + if (step == 1) + for (i = numreplaced; i < slicelen; i++) + listitem_remove(l, lis[i]); + + PyMem_Free(lis); + + return 0; +} + + static int +ListAssIndex(ListObject *self, Py_ssize_t index, PyObject *obj) +{ + typval_T tv; + list_T *l = self->list; + listitem_T *li; + Py_ssize_t length = ListLength(self); + + if (l->lv_lock) + { + RAISE_LOCKED_LIST; + return -1; + } + if (index > length || (index == length && obj == NULL)) + { + PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range")); return -1; + } + if (obj == NULL) + { + li = list_find(l, (long) index); + list_remove(l, li, li); + clear_tv(&li->li_tv); + vim_free(li); + return 0; + } + + if (ConvertFromPyObject(obj, &tv) == -1) + return -1; + + if (index == length) + { + if (list_append_tv(l, &tv) == FAIL) + { + clear_tv(&tv); + PyErr_SET_VIM(N_("failed to add item to list")); + return -1; + } + } + else + { + li = list_find(l, (long) index); + clear_tv(&li->li_tv); + copy_tv(&tv, &li->li_tv); + clear_tv(&tv); + } return 0; } + static Py_ssize_t +ListAssItem(ListObject *self, PyObject *idx, PyObject *obj) +{ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(idx)) + { + long _idx = PyInt_AsLong(idx); + return ListAssIndex(self, _idx, obj); + } + else +#endif + if (PyLong_Check(idx)) + { + long _idx = PyLong_AsLong(idx); + return ListAssIndex(self, _idx, obj); + } + else if (PySlice_Check(idx)) + { + Py_ssize_t start, stop, step, slicelen; + + if (PySlice_GetIndicesEx(idx, ListLength(self), + &start, &stop, &step, &slicelen) < 0) + return -1; + return ListAssSlice(self, start, step, slicelen, + obj); + } + else + { + RAISE_INVALID_INDEX_TYPE(idx); + return -1; + } +} + static PyObject * ListConcatInPlace(ListObject *self, PyObject *obj) { @@ -2520,6 +2655,56 @@ ListConcatInPlace(ListObject *self, PyObject *obj) return (PyObject *)(self); } +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 *ret; + + if (!((*lii)->lw.lw_item)) + return NULL; + + if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) + return NULL; + + (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next; + + return ret; +} + + static PyObject * +ListIter(ListObject *self) +{ + listiterinfo_T *lii; + list_T *l = 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, + NULL, NULL); +} + static char *ListAttrs[] = { "locked", NULL @@ -2567,6 +2752,25 @@ ListSetattr(ListObject *self, char *name, PyObject *valObject) } } +static PySequenceMethods ListAsSeq = { + (lenfunc) ListLength, /* sq_length, len(x) */ + (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */ + 0, /* RangeRepeat, sq_repeat, x*n */ + (PyIntArgFunc) ListIndex, /* sq_item, x[i] */ + 0, /* was_sq_slice, x[i:j] */ + (PyIntObjArgProc) ListAssIndex, /* sq_as_item, x[i]=v */ + 0, /* was_sq_ass_slice, x[i:j]=v */ + 0, /* sq_contains */ + (binaryfunc) ListConcatInPlace,/* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyMappingMethods ListAsMapping = { + /* mp_length */ (lenfunc) ListLength, + /* mp_subscript */ (binaryfunc) ListItem, + /* mp_ass_subscript */ (objobjargproc) ListAssItem, +}; + static struct PyMethodDef ListMethods[] = { {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""}, {"__dir__", (PyCFunction)ListDir, METH_NOARGS, ""}, |