Index: Include/setobject.h =================================================================== --- Include/setobject.h (Revision 75729) +++ Include/setobject.h (Arbeitskopie) @@ -91,6 +91,7 @@ PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); +PyAPI_FUNC(PyObject *) PySet_Get(PyObject *set); PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); #ifdef __cplusplus Index: Objects/setobject.c =================================================================== --- Objects/setobject.c (Revision 75729) +++ Objects/setobject.c (Arbeitskopie) @@ -757,6 +757,49 @@ PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element.\n\ Raises KeyError if the set is empty."); +static PyObject * +set_get(PySetObject *so) +{ + register Py_ssize_t i = 0; + register setentry *entry; + PyObject *key; + + assert (PyAnySet_Check(so)); + if (so->used == 0) { + PyErr_SetString(PyExc_KeyError, "get from an empty set"); + return NULL; + } + + /* Set entry to "the first" unused or dummy set entry. We abuse + * the hash field of slot 0 to hold a search finger: + * If slot 0 has a value, use slot 0. + * Else slot 0 is being used to hold a search finger, + * and we use its hash value as the first index to look. + */ + entry = &so->table[0]; + if (entry->key == NULL || entry->key == dummy) { + i = entry->hash; + /* The hash field may be a real hash value, or it may be a + * legit search finger, or it may be a once-legit search + * finger that's out of bounds now because it wrapped around + * or the table shrunk -- simply make sure it's in bounds now. + */ + if (i > so->mask || i < 1) + i = 1; /* skip slot 0 */ + while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { + i++; + if (i > so->mask) + i = 1; + } + } + key = entry->key; + Py_INCREF(key); + return key; +} + +PyDoc_STRVAR(get_doc, "Return an arbitrary set element without removing it.\n\ +Raises KeyError if the set is empty."); + static int set_traverse(PySetObject *so, visitproc visit, void *arg) { @@ -2043,6 +2086,8 @@ issuperset_doc}, {"pop", (PyCFunction)set_pop, METH_NOARGS, pop_doc}, + {"get", (PyCFunction)set_get, METH_NOARGS, + get_doc}, {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, reduce_doc}, {"remove", (PyCFunction)set_remove, METH_O, @@ -2355,6 +2400,16 @@ return set_pop((PySetObject *)set); } +PyObject * +PySet_Get(PyObject *set) +{ + if (!PySet_Check(set)) { + PyErr_BadInternalCall(); + return NULL; + } + return set_get((PySetObject *)set); +} + int _PySet_Update(PyObject *set, PyObject *iterable) { Index: Lib/test/test_set.py =================================================================== --- Lib/test/test_set.py (Revision 75729) +++ Lib/test/test_set.py (Arbeitskopie) @@ -427,6 +427,13 @@ self.assertTrue(elem not in self.s) self.assertRaises(KeyError, self.s.pop) + def test_get(self): + s_copy = self.s.copy() + for i in xrange(3*len(self.s)): + elem = self.s.get() + self.assertTrue(elem in self.s) + self.assertEquals(s_copy, self.s) + def test_update(self): retval = self.s.update(self.otherword) self.assertEqual(retval, None)