Added dict.absorb() and dict.copy().
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6f92f67..408bd8f 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -258,10 +258,11 @@
 items again.  When entries have been deleted, the new table may
 actually be smaller than the old one.
 */
-static int dictresize Py_PROTO((dictobject *));
+static int dictresize Py_PROTO((dictobject *, int));
 static int
-dictresize(mp)
+dictresize(mp, minused)
 	dictobject *mp;
+	int minused;
 {
 	register int oldsize = mp->ma_size;
 	register int newsize, newpoly;
@@ -269,14 +270,13 @@
 	register dictentry *newtable;
 	register dictentry *ep;
 	register int i;
-	newsize = mp->ma_size;
 	for (i = 0, newsize = MINSIZE; ; i++, newsize <<= 1) {
 		if (i > sizeof(polys)/sizeof(polys[0])) {
 			/* Ran out of polynomials */
 			PyErr_NoMemory();
 			return -1;
 		}
-		if (newsize > mp->ma_used*2) {
+		if (newsize > minused) {
 			newpoly = polys[i];
 			break;
 		}
@@ -366,9 +366,9 @@
 		if (hash == -1)
 			return -1;
 	}
-	/* if fill >= 2/3 size, resize */
+	/* if fill >= 2/3 size, double in size */
 	if (mp->ma_fill*3 >= mp->ma_size*2) {
-		if (dictresize(mp) != 0) {
+		if (dictresize(mp, mp->ma_used*2) != 0) {
 			if (mp->ma_fill+1 > mp->ma_size)
 				return -1;
 		}
@@ -674,6 +674,68 @@
 	return v;
 }
 
+static PyObject *
+dict_absorb(mp, args)
+      register dictobject *mp;
+      PyObject *args;
+{
+	register int i;
+	dictobject *other;
+        dictentry *entry;
+	if (!PyArg_Parse(args, "O!", &PyDict_Type, &other))
+		return NULL;
+	if (other == mp)
+		goto done; /* a.absorb(a); 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_size*2) {
+		if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
+			return NULL;
+	}
+	for (i = 0; i < other->ma_size; 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);
+	return Py_None;
+}
+
+static PyObject *
+dict_copy(mp, args)
+      register dictobject *mp;
+      PyObject *args;
+{
+	register int i;
+	dictobject *copy;
+        dictentry *entry;
+	if (!PyArg_Parse(args, ""))
+		return NULL;
+	copy = (dictobject *)PyDict_New();
+	if (copy == NULL)
+		return NULL;
+	if (mp->ma_used > 0) {
+		if (dictresize(copy, mp->ma_used*3/2) != 0)
+			return NULL;
+		for (i = 0; i < mp->ma_size; i++) {
+			entry = &mp->ma_table[i];
+			if (entry->me_value != NULL) {
+				Py_INCREF(entry->me_key);
+				Py_INCREF(entry->me_value);
+				insertdict(copy, entry->me_key, entry->me_hash,
+					   entry->me_value);
+			}
+		}
+	}
+	return (PyObject *)copy;
+}
+
 int
 PyDict_Size(mp)
 	PyObject *mp;
@@ -901,7 +963,9 @@
 }
 
 static PyMethodDef mapp_methods[] = {
+	{"absorb",	(PyCFunction)dict_absorb},
 	{"clear",	(PyCFunction)dict_clear},
+	{"copy",	(PyCFunction)dict_copy},
 	{"has_key",	(PyCFunction)dict_has_key},
 	{"items",	(PyCFunction)dict_items},
 	{"keys",	(PyCFunction)dict_keys},