[Python-checkins] CVS: python/dist/src/Objects dictobject.c,2.105,2.106

Barry Warsaw bwarsaw@users.sourceforge.net
Tue, 26 Jun 2001 13:08:34 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv32745

Modified Files:
	dictobject.c 
Log Message:
dict_update(): Generalize this method so {}.update() accepts any
"mapping" object, specifically one that supports PyMapping_Keys() and
PyObject_GetItem().  This allows you to say e.g. {}.update(UserDict())

We keep the special case for concrete dict objects, although that
seems moderately questionable.  OTOH, the code exists and works, so
why change that?

.update()'s docstring already claims that D.update(E) implies calling
E.keys() so it's appropriate not to transform AttributeErrors in
PyMapping_Keys() to TypeErrors.

Patch eyeballed by Tim.


Index: dictobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v
retrieving revision 2.105
retrieving revision 2.106
diff -C2 -r2.105 -r2.106
*** dictobject.c	2001/06/16 07:52:53	2.105
--- dictobject.c	2001/06/26 20:08:32	2.106
***************
*** 1048,1071 ****
  	dictobject *other;
  	dictentry *entry;
! 	if (!PyArg_Parse(args, "O!", &PyDict_Type, &other))
  		return NULL;
! 	if (other == mp || other->ma_used == 0)
! 		goto done; /* a.update(a) or a.update({}); nothing to do */
! 	/* Do one big resize at the start, rather than incrementally
! 	   resizing as we insert new items.  Expect that there will be
! 	   no (or few) overlapping keys. */
! 	if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
! 		if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
! 			return NULL;
  	}
! 	for (i = 0; i <= other->ma_mask; i++) {
! 		entry = &other->ma_table[i];
! 		if (entry->me_value != NULL) {
! 			Py_INCREF(entry->me_key);
! 			Py_INCREF(entry->me_value);
! 			insertdict(mp, entry->me_key, entry->me_hash,
! 				   entry->me_value);
  		}
  	}
    done:
  	Py_INCREF(Py_None);
--- 1048,1124 ----
  	dictobject *other;
  	dictentry *entry;
! 	PyObject *param;
! 	/* We accept for the argument either a concrete dictionary object,
! 	 * or an abstract "mapping" object.  For the former, we can do
! 	 * things quite efficiently.  For the latter, we only require that
! 	 * PyMapping_Keys() and PyObject_GetItem() be supported.
! 	 */
! 	if (!PyArg_ParseTuple(args, "O:update", &param))
  		return NULL;
! 
! 	if (PyDict_Check(param)) {
! 		other = (dictobject*)param;
! 		if (other == mp || other->ma_used == 0)
! 			/* a.update(a) or a.update({}); nothing to do */
! 			goto done;
! 		/* Do one big resize at the start, rather than
! 		 * incrementally resizing as we insert new items.  Expect
! 		 * that there will be no (or few) overlapping keys.
! 		 */
! 		if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
! 		   if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
! 			   return NULL;
! 		}
! 		for (i = 0; i <= other->ma_mask; i++) {
! 			entry = &other->ma_table[i];
! 			if (entry->me_value != NULL) {
! 				Py_INCREF(entry->me_key);
! 				Py_INCREF(entry->me_value);
! 				insertdict(mp, entry->me_key, entry->me_hash,
! 					   entry->me_value);
! 			}
! 		}
  	}
! 	else {
! 		/* Do it the generic, slower way */
! 		PyObject *keys = PyMapping_Keys(param);
! 		PyObject *iter;
! 		PyObject *key, *value;
! 		int status;
! 
! 		if (keys == NULL)
! 			/* Docstring says this is equivalent to E.keys() so
! 			 * if E doesn't have a .keys() method we want
! 			 * AttributeError to percolate up.  Might as well
! 			 * do the same for any other error.
! 			 */
! 			return NULL;
! 
! 		iter = PyObject_GetIter(keys);
! 		Py_DECREF(keys);
! 		if (iter == NULL)
! 			return NULL;
! 
! 		for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
! 			value = PyObject_GetItem(param, key);
! 			if (value == NULL) {
! 				Py_DECREF(iter);
! 				Py_DECREF(key);
! 				return NULL;
! 			}
! 			status = PyDict_SetItem((PyObject*)mp, key, value);
! 			Py_DECREF(key);
! 			Py_DECREF(value);
! 			if (status < 0) {
! 				Py_DECREF(iter);
! 				return NULL;
! 			}
  		}
+ 		Py_DECREF(iter);
+ 		if (PyErr_Occurred())
+ 			/* Iterator completed, via error */
+ 			return NULL;
  	}
+ 	
    done:
  	Py_INCREF(Py_None);
***************
*** 1627,1631 ****
  	{"values",	(PyCFunction)dict_values,	METH_OLDARGS,
  	 values__doc__},
! 	{"update",	(PyCFunction)dict_update,	METH_OLDARGS,
  	 update__doc__},
  	{"clear",	(PyCFunction)dict_clear,	METH_OLDARGS,
--- 1680,1684 ----
  	{"values",	(PyCFunction)dict_values,	METH_OLDARGS,
  	 values__doc__},
! 	{"update",	(PyCFunction)dict_update,	METH_VARARGS,
  	 update__doc__},
  	{"clear",	(PyCFunction)dict_clear,	METH_OLDARGS,