[Python-checkins] r53953 - in python/branches/twouters-dictviews-backport: Lib/test/test_dict.py Objects/dictobject.c

thomas.wouters python-checkins at python.org
Mon Feb 26 19:22:04 CET 2007


Author: thomas.wouters
Date: Mon Feb 26 19:22:00 2007
New Revision: 53953

Modified:
   python/branches/twouters-dictviews-backport/Lib/test/test_dict.py
   python/branches/twouters-dictviews-backport/Objects/dictobject.c
Log:

Step one of backporting dict.key/items/values from Py3k: the actual
backporting, and renaming to viewkeys/viewitems/viewvalues.



Modified: python/branches/twouters-dictviews-backport/Lib/test/test_dict.py
==============================================================================
--- python/branches/twouters-dictviews-backport/Lib/test/test_dict.py	(original)
+++ python/branches/twouters-dictviews-backport/Lib/test/test_dict.py	Mon Feb 26 19:22:00 2007
@@ -26,6 +26,18 @@
 
         self.assertRaises(TypeError, d.keys, None)
 
+    def test_viewkeys(self):
+        d = {}
+        self.assertEqual(d.viewkeys(), set())
+        d = {'a': 1, 'b': 2}
+        k = d.viewkeys()
+        self.assert_('a' in k)
+        self.assert_('b' in k)
+        self.assertFalse('c' in k)
+        self.assertEquals(k, set(['a', 'b']))
+
+        self.assertRaises(TypeError, d.viewkeys, None)
+
     def test_values(self):
         d = {}
         self.assertEqual(d.values(), [])
@@ -34,15 +46,32 @@
 
         self.assertRaises(TypeError, d.values, None)
 
+    def test_viewvalues(self):
+        d = {}
+        self.assertEqual(list(d.viewvalues()), [])
+        d = {1:2}
+        self.assertEqual(list(d.viewvalues()), [2])
+
+        self.assertRaises(TypeError, d.viewvalues, None)
+
     def test_items(self):
         d = {}
-        self.assertEqual(d.items(), [])
+        self.assertEqual(list(d.items(), [])
 
         d = {1:2}
         self.assertEqual(d.items(), [(1, 2)])
 
         self.assertRaises(TypeError, d.items, None)
 
+    def test_viewitems(self):
+        d = {}
+        self.assertEqual(list(d.viewitems()), [])
+
+        d = {1:2}
+        self.assertEqual(list(d.viewitems()), [(1, 2)])
+
+        self.assertRaises(TypeError, d.viewitems, None)
+
     def test_has_key(self):
         d = {}
         self.assert_(not d.has_key('a'))

Modified: python/branches/twouters-dictviews-backport/Objects/dictobject.c
==============================================================================
--- python/branches/twouters-dictviews-backport/Objects/dictobject.c	(original)
+++ python/branches/twouters-dictviews-backport/Objects/dictobject.c	Mon Feb 26 19:22:00 2007
@@ -1959,6 +1959,15 @@
 PyDoc_STRVAR(iteritems__doc__,
 "D.iteritems() -> an iterator over the (key, value) items of D");
 
+/* Forward */
+static PyObject *dictkeys_new(PyObject *);
+static PyObject *dictitems_new(PyObject *);
+static PyObject *dictvalues_new(PyObject *);
+
+PyDoc_STRVAR(KEYS__doc__, "D.KEYS() -> a set-like object for D's keys");
+PyDoc_STRVAR(ITEMS__doc__, "D.ITEMS() -> a set-like object for D's items");
+PyDoc_STRVAR(VALUES__doc__, "D.VALUES() -> a set-like object for D's values");
+
 static PyMethodDef mapp_methods[] = {
 	{"__contains__",(PyCFunction)dict_has_key,      METH_O | METH_COEXIST,
 	 contains__doc__},
@@ -1980,6 +1989,12 @@
 	 items__doc__},
 	{"values",	(PyCFunction)dict_values,	METH_NOARGS,
 	 values__doc__},
+	{"viewkeys",	(PyCFunction)dictkeys_new,	METH_NOARGS,
+	KEYS__doc__},
+	{"viewitems",	(PyCFunction)dictitems_new,	METH_NOARGS,
+	ITEMS__doc__},
+	{"viewvalues",	(PyCFunction)dictvalues_new,	METH_NOARGS,
+	VALUES__doc__},
 	{"update",	(PyCFunction)dict_update,	METH_VARARGS | METH_KEYWORDS,
 	 update__doc__},
 	{"fromkeys",	(PyCFunction)dict_fromkeys,	METH_VARARGS | METH_CLASS,
@@ -2466,3 +2481,359 @@
 	dictiter_methods,			/* tp_methods */
 	0,
 };
+
+
+/***********************************************/
+/* View objects for keys(), items(), values(). */
+/***********************************************/
+
+/* While this is incomplete, we use KEYS(), ITEMS(), VALUES(). */
+
+/* The instance lay-out is the same for all three; but the type differs. */
+
+typedef struct {
+	PyObject_HEAD
+	dictobject *dv_dict;
+} dictviewobject;
+
+
+static void
+dictview_dealloc(dictviewobject *dv)
+{
+	Py_XDECREF(dv->dv_dict);
+	PyObject_Del(dv);
+}
+
+static Py_ssize_t
+dictview_len(dictviewobject *dv)
+{
+	Py_ssize_t len = 0;
+	if (dv->dv_dict != NULL)
+		len = dv->dv_dict->ma_used;
+	return len;
+}
+
+static PyObject *
+dictview_new(PyObject *dict, PyTypeObject *type)
+{
+	dictviewobject *dv;
+	if (dict == NULL) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+	if (!PyDict_Check(dict)) {
+		/* XXX Get rid of this restriction later */
+		PyErr_Format(PyExc_TypeError,
+			     "%s() requires a dict argument, not '%s'",
+			     type->tp_name, dict->ob_type->tp_name);
+		return NULL;
+	}
+	dv = PyObject_New(dictviewobject, type);
+	if (dv == NULL)
+		return NULL;
+	Py_INCREF(dict);
+	dv->dv_dict = (dictobject *)dict;
+	return (PyObject *)dv;
+}
+
+/* Forward */
+PyTypeObject PyDictKeys_Type;
+PyTypeObject PyDictItems_Type;
+PyTypeObject PyDictValues_Type;
+
+#define PyDictKeys_Check(obj) ((obj)->ob_type == &PyDictKeys_Type)
+#define PyDictItems_Check(obj) ((obj)->ob_type == &PyDictItems_Type)
+#define PyDictValues_Check(obj) ((obj)->ob_type == &PyDictValues_Type)
+
+/* This excludes Values, since they are not sets. */
+# define PyDictViewSet_Check(obj) \
+	(PyDictKeys_Check(obj) || PyDictItems_Check(obj))
+
+static int
+all_contained_in(PyObject *self, PyObject *other)
+{
+	PyObject *iter = PyObject_GetIter(self);
+	int ok = 1;
+
+	if (iter == NULL)
+		return -1;
+	for (;;) {
+		PyObject *next = PyIter_Next(iter);
+		if (next == NULL) {
+			if (PyErr_Occurred())
+				ok = -1;
+			break;
+		}
+		ok = PySequence_Contains(other, next);
+		Py_DECREF(next);
+		if (ok <= 0)
+			break;
+	}
+	Py_DECREF(iter);
+	return ok;
+}
+
+static PyObject *
+dictview_richcompare(PyObject *self, PyObject *other, int op)
+{
+	assert(self != NULL);
+	assert(PyDictViewSet_Check(self));
+	assert(other != NULL);
+	if ((op == Py_EQ || op == Py_NE) &&
+	    (PyAnySet_Check(other) || PyDictViewSet_Check(other)))
+	{
+		Py_ssize_t len_self, len_other;
+		int ok;
+		PyObject *result;
+
+		len_self = PyObject_Size(self);
+		if (len_self < 0)
+			return NULL;
+		len_other = PyObject_Size(other);
+		if (len_other < 0)
+			return NULL;
+		if (len_self != len_other)
+			ok = 0;
+		else if (len_self == 0)
+			ok = 1;
+		else
+			ok = all_contained_in(self, other);
+		if (ok < 0)
+			return NULL;
+		if (ok == (op == Py_EQ))
+			result = Py_True;
+		else
+			result = Py_False;
+		Py_INCREF(result);
+		return result;
+	}
+	else {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+}
+
+/*** dict_keys ***/
+
+static PyObject *
+dictkeys_iter(dictviewobject *dv)
+{
+	if (dv->dv_dict == NULL) {
+		Py_RETURN_NONE;
+	}
+	return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
+}
+
+static int
+dictkeys_contains(dictviewobject *dv, PyObject *obj)
+{
+	if (dv->dv_dict == NULL)
+		return 0;
+	return PyDict_Contains((PyObject *)dv->dv_dict, obj);
+}
+
+static PySequenceMethods dictkeys_as_sequence = {
+	(lenfunc)dictview_len,		/* sq_length */
+	0,				/* sq_concat */
+	0,				/* sq_repeat */
+	0,				/* sq_item */
+	0,				/* sq_slice */
+	0,				/* sq_ass_item */
+	0,				/* sq_ass_slice */
+	(objobjproc)dictkeys_contains,	/* sq_contains */
+};
+
+static PyMethodDef dictkeys_methods[] = {
+ 	{NULL,		NULL}		/* sentinel */
+};
+
+PyTypeObject PyDictKeys_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,					/* ob_size */
+	"dict_keys",				/* tp_name */
+	sizeof(dictviewobject),			/* tp_basicsize */
+	0,					/* tp_itemsize */
+	/* methods */
+	(destructor)dictview_dealloc, 		/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	&dictkeys_as_sequence,			/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	PyObject_GenericGetAttr,		/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,			/* tp_flags */
+ 	0,					/* tp_doc */
+ 	0,					/* tp_traverse */
+ 	0,					/* tp_clear */
+	dictview_richcompare,			/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	(getiterfunc)dictkeys_iter,		/* tp_iter */
+	0,					/* tp_iternext */
+	dictkeys_methods,			/* tp_methods */
+	0,
+};
+
+static PyObject *
+dictkeys_new(PyObject *dict)
+{
+	return dictview_new(dict, &PyDictKeys_Type);
+}
+
+/*** dict_items ***/
+
+static PyObject *
+dictitems_iter(dictviewobject *dv)
+{
+	if (dv->dv_dict == NULL) {
+		Py_RETURN_NONE;
+	}
+	return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
+}
+
+static int
+dictitems_contains(dictviewobject *dv, PyObject *obj)
+{
+	PyObject *key, *value, *found;
+	if (dv->dv_dict == NULL)
+		return 0;
+	if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
+		return 0;
+	key = PyTuple_GET_ITEM(obj, 0);
+	value = PyTuple_GET_ITEM(obj, 1);
+	found = PyDict_GetItem((PyObject *)dv->dv_dict, key);
+	if (found == NULL) {
+		if (PyErr_Occurred())
+			return -1;
+		return 0;
+	}
+	return PyObject_RichCompareBool(value, found, Py_EQ);
+}
+
+static PySequenceMethods dictitems_as_sequence = {
+	(lenfunc)dictview_len,		/* sq_length */
+	0,				/* sq_concat */
+	0,				/* sq_repeat */
+	0,				/* sq_item */
+	0,				/* sq_slice */
+	0,				/* sq_ass_item */
+	0,				/* sq_ass_slice */
+	(objobjproc)dictitems_contains,	/* sq_contains */
+};
+
+static PyMethodDef dictitems_methods[] = {
+ 	{NULL,		NULL}		/* sentinel */
+};
+
+PyTypeObject PyDictItems_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,					/* ob_size */
+	"dict_items",				/* tp_name */
+	sizeof(dictviewobject),			/* tp_basicsize */
+	0,					/* tp_itemsize */
+	/* methods */
+	(destructor)dictview_dealloc, 		/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	&dictitems_as_sequence,			/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	PyObject_GenericGetAttr,		/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,			/* tp_flags */
+ 	0,					/* tp_doc */
+ 	0,					/* tp_traverse */
+ 	0,					/* tp_clear */
+	dictview_richcompare,			/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	(getiterfunc)dictitems_iter,		/* tp_iter */
+	0,					/* tp_iternext */
+	dictitems_methods,			/* tp_methods */
+	0,
+};
+
+static PyObject *
+dictitems_new(PyObject *dict)
+{
+	return dictview_new(dict, &PyDictItems_Type);
+}
+
+/*** dict_values ***/
+
+static PyObject *
+dictvalues_iter(dictviewobject *dv)
+{
+	if (dv->dv_dict == NULL) {
+		Py_RETURN_NONE;
+	}
+	return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
+}
+
+static PySequenceMethods dictvalues_as_sequence = {
+	(lenfunc)dictview_len,		/* sq_length */
+	0,				/* sq_concat */
+	0,				/* sq_repeat */
+	0,				/* sq_item */
+	0,				/* sq_slice */
+	0,				/* sq_ass_item */
+	0,				/* sq_ass_slice */
+	(objobjproc)0,			/* sq_contains */
+};
+
+static PyMethodDef dictvalues_methods[] = {
+ 	{NULL,		NULL}		/* sentinel */
+};
+
+PyTypeObject PyDictValues_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,					/* ob_size */
+	"dict_values",				/* tp_name */
+	sizeof(dictviewobject),			/* tp_basicsize */
+	0,					/* tp_itemsize */
+	/* methods */
+	(destructor)dictview_dealloc, 		/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	&dictvalues_as_sequence,		/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	PyObject_GenericGetAttr,		/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,			/* tp_flags */
+ 	0,					/* tp_doc */
+ 	0,					/* tp_traverse */
+ 	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	(getiterfunc)dictvalues_iter,		/* tp_iter */
+	0,					/* tp_iternext */
+	dictvalues_methods,			/* tp_methods */
+	0,
+};
+
+static PyObject *
+dictvalues_new(PyObject *dict)
+{
+	return dictview_new(dict, &PyDictValues_Type);
+}


More information about the Python-checkins mailing list