Index: Objects/dictobject.c =================================================================== --- Objects/dictobject.c (revision 43333) +++ Objects/dictobject.c (working copy) @@ -2081,8 +2081,69 @@ PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); +PyDoc_STRVAR( dictiter_delete_doc, "Mutable iter.delete" ); + +static PyObject * +dictiter_delete( dictiterobject *di ) +{ + register int i; + register dictentry *ep; + PyObject *old_value, *old_key; + + dictobject *d = di->di_dict; + + if (d==NULL) + return NULL; + assert( PyDict_Check( d ) ); + + i = di->di_pos - 1; + + if (i == -1 ) { + PyErr_SetString( PyExc_RuntimeError, + "Attempted to call iter.delete() before first call to iter.next()" ); + return NULL; + } + + if ( i> d->ma_mask ) { + PyErr_SetString( PyExc_RuntimeError, + "Attempted to call iter.delete() after iteration exhaustion." ); + return NULL; + } + + ep = d->ma_table+i; + + if ( ep->me_key == dummy ) { + PyErr_SetString( PyExc_RuntimeError, + "Attempted to call iter.delete for already deleted item" ); + return NULL; + } + + /* Things can change when I decref, so I'm going to put the + dict back into a sane state first.*/ + + old_value = ep->me_value; + old_key = ep->me_key; + + d->ma_used--; + di->di_used--; + + ep->me_value = NULL; + ep->me_key = dummy; + + Py_INCREF( dummy ); + Py_INCREF( di ); + + Py_DECREF( old_value ); + Py_DECREF( old_key ); + return (PyObject*)di; +} + + static PyMethodDef dictiter_methods[] = { {"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS, length_hint_doc}, + {"delete", (PyCFunction)dictiter_delete, METH_NOARGS, + dictiter_delete_doc }, + {NULL, NULL} /* sentinel */ }; @@ -2125,6 +2186,8 @@ return NULL; } + + PyTypeObject PyDictIterKey_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ Index: Objects/listobject.c =================================================================== --- Objects/listobject.c (revision 43333) +++ Objects/listobject.c (working copy) @@ -2695,6 +2695,7 @@ typedef struct { PyObject_HEAD long it_index; + int delete_finish; PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ } listiterobject; @@ -2713,6 +2714,7 @@ if (it == NULL) return NULL; it->it_index = 0; + it->delete_finish = 0; Py_INCREF(seq); it->it_seq = (PyListObject *)seq; _PyObject_GC_TRACK(it); @@ -2735,7 +2737,47 @@ return visit((PyObject *)it->it_seq, arg); } + +PyDoc_STRVAR(listiter_delete_doc, +"Deletes the last next from the otherlying data store." ); + + static PyObject * +listiter_delete(listiterobject *it) +{ + if ( it == NULL ) + return NULL; + + if ( it->delete_finish ) + { + PyErr_SetString(PyExc_RuntimeError, + "iter.delete() called more than once per call to iter.next()" ); + return NULL; + } + + if ( it->it_index==0 ) + { + PyErr_SetString( PyExc_RuntimeError, + "iter.delete() called before first call to iter.next()"); + return NULL; + } + + if ( it->it_seq == NULL ) + { + PyErr_SetString( PyExc_RuntimeError, + "iter.delete() called after iteration exhausted." ); + return NULL; + } + + it->delete_finish = -1; + list_ass_slice( it->it_seq, it->it_index-1, it->it_index, NULL ); + + Py_INCREF( it ); + return (PyObject*)it; +} + + +static PyObject * listiter_next(listiterobject *it) { PyListObject *seq; @@ -2749,7 +2791,8 @@ if (it->it_index < PyList_GET_SIZE(seq)) { item = PyList_GET_ITEM(seq, it->it_index); - ++it->it_index; + it->it_index+=1+it->delete_finish; + it->delete_finish=0; Py_INCREF(item); return item; } @@ -2775,9 +2818,14 @@ static PyMethodDef listiter_methods[] = { {"__length_hint__", (PyCFunction)listiter_len, METH_NOARGS, length_hint_doc}, + {"delete", (PyCFunction)listiter_delete, METH_NOARGS, listiter_delete_doc}, + {NULL, NULL} /* sentinel */ }; + + + PyTypeObject PyListIter_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ Index: Lib/test/test_dict.py =================================================================== --- Lib/test/test_dict.py (revision 43333) +++ Lib/test/test_dict.py (working copy) @@ -445,6 +445,38 @@ self.fail_("g[42] didn't raise KeyError") + + def test_newiter( self ): + orig = dict( a='a', b='b', c='c', d='d', e='e' ) + + d = dict( orig ) + + i = d.iterkeys() + victim = i.next() + i.delete() + del( orig[ victim ] ) + + i = d.itervalues() + victim = i.next() + i.delete() + del( orig[ victim ] ) + + i = d.iteritems() + victim = i.next()[0] + i.delete() + del( orig[ victim ] ) + + self.assert_( d == orig ) + + + + + + + + + + import mapping_tests class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): Index: Lib/test/list_tests.py =================================================================== --- Lib/test/list_tests.py (revision 43333) +++ Lib/test/list_tests.py (working copy) @@ -523,3 +523,21 @@ def __len__(self): raise KeyboardInterrupt self.assertRaises(KeyboardInterrupt, list, F()) + + + def test_iter( self ): + + orig = list( "abcdef" ) + + l = list( orig ) + + i = iter( l ) + + victim = i.next() + i.delete() + orig.remove( victim ) + + self.assert_( orig == l ) + + +

AltStyle によって変換されたページ (->オリジナル) /