]> granicus.if.org Git - python/commitdiff
Give meaning to the oparg for BUILD_MAP: estimated size of the dictionary.
authorRaymond Hettinger <python@rcn.com>
Tue, 18 Dec 2007 21:24:09 +0000 (21:24 +0000)
committerRaymond Hettinger <python@rcn.com>
Tue, 18 Dec 2007 21:24:09 +0000 (21:24 +0000)
Allows dictionaries to be pre-sized (upto 255 elements) saving time lost
to re-sizes with their attendant mallocs and re-insertions.

Has zero effect on small dictionaries (5 elements or fewer), a slight
benefit for dicts upto 22 elements (because they had to resize once
anyway), and more benefit for dicts upto 255 elements (saving multiple
resizes during the build-up and reducing the number of collisions on
the first insertions).  Beyond 255 elements, there is no addional benefit.

Include/dictobject.h
Lib/opcode.py
Misc/NEWS
Objects/dictobject.c
Python/ceval.c
Python/compile.c

index fec62958fe1a90d295adfd41f89b82678b3ec7d2..c5378cf2dd8e2ef3bfc73c5062f8a220c44797a4 100644 (file)
@@ -110,6 +110,7 @@ PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp);
 PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp);
 PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key);
 PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, long hash);
+PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
 
 /* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */
 PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);
index c3457d014ae1c7ed213da76c955620f80c706908..cee5057f919ceeb6c856b82339f0e57bf6fc31d6 100644 (file)
@@ -139,7 +139,7 @@ hasconst.append(100)
 name_op('LOAD_NAME', 101)       # Index in name list
 def_op('BUILD_TUPLE', 102)      # Number of tuple items
 def_op('BUILD_LIST', 103)       # Number of list items
-def_op('BUILD_MAP', 104)        # Always zero for now
+def_op('BUILD_MAP', 104)        # Number of dict entries (upto 255)
 name_op('LOAD_ATTR', 105)       # Index in name list
 def_op('COMPARE_OP', 106)       # Comparison operator
 hascompare.append(106)
index 1599ade483bff8494f1cd8d8f3d3872cec80b564..40e9e6aac4c25f146ccd4ac948a651d3cf8da2de 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
 Core and builtins
 -----------------
 
+- Compiler now generates simpler and faster code for dictionary literals.
+  The oparg for BUILD_MAP now indicates an estimated dictionary size.
+  There is a new opcode, STORE_MAP, for adding entries to the dictionary.
+
 - Issue #1638: %zd configure test fails on Linux
 
 - Issue #1620: New property decorator syntax was modifying the decorator
index bfb093b1d2069899cc181eab4d3bef5d769e7ab4..365aac605b9525f42c807e9fb110501fe14abf96 100644 (file)
@@ -549,6 +549,23 @@ dictresize(PyDictObject *mp, Py_ssize_t minused)
        return 0;
 }
 
+/* Create a new dictionary pre-sized to hold an estimated number of elements.
+   Underestimates are okay because the dictionary will resize as necessary.
+   Overestimates just mean the dictionary will be more sparse than usual.
+*/
+
+PyObject *
+_PyDict_NewPresized(Py_ssize_t minused)
+{
+       PyObject *op = PyDict_New();
+
+       if (minused>5 && op != NULL && dictresize((PyDictObject *)op, minused) == -1) {
+               Py_DECREF(op);
+               return NULL;
+       }
+       return op;
+}
+
 /* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
  * that may occur (originally dicts supported only string keys, and exceptions
  * weren't possible).  So, while the original intent was that a NULL return
index 1af998d77781c5701f1fc2a188251c0131f607fd..b6501b346425f7319051cf875e6523c215800480 100644 (file)
@@ -1997,7 +1997,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
                        break;
 
                case BUILD_MAP:
-                       x = PyDict_New();
+                       x = _PyDict_NewPresized((Py_ssize_t)oparg);
                        PUSH(x);
                        if (x != NULL) continue;
                        break;
index 3b0c53fb193c53ef8df987c2462bf79f340d8772..36ad8a48e0ec32d835e094b7d0be3a556d047a26 100644 (file)
@@ -2922,11 +2922,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
        case IfExp_kind:
                return compiler_ifexp(c, e);
        case Dict_kind:
-               /* XXX get rid of arg? */
-               ADDOP_I(c, BUILD_MAP, 0);
                n = asdl_seq_LEN(e->v.Dict.values);
-               /* We must arrange things just right for STORE_SUBSCR.
-                  It wants the stack to look like (value) (dict) (key) */
+               ADDOP_I(c, BUILD_MAP, (n>255 ? 255 : n));
+               n = asdl_seq_LEN(e->v.Dict.values);
                for (i = 0; i < n; i++) {
                        VISIT(c, expr, 
                                (expr_ty)asdl_seq_GET(e->v.Dict.values, i));