mirror of
https://github.com/python/cpython.git
synced 2025-07-27 21:24:32 +00:00
Give meaning to the oparg for BUILD_MAP: estimated size of the dictionary.
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.
This commit is contained in:
parent
3c887b2802
commit
fd7ed407d7
6 changed files with 26 additions and 6 deletions
|
@ -110,6 +110,7 @@ PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp);
|
||||||
PyAPI_FUNC(PyObject *) PyDict_Copy(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);
|
||||||
PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, long hash);
|
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). */
|
/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */
|
||||||
PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);
|
PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);
|
||||||
|
|
|
@ -139,7 +139,7 @@ hasconst.append(100)
|
||||||
name_op('LOAD_NAME', 101) # Index in name list
|
name_op('LOAD_NAME', 101) # Index in name list
|
||||||
def_op('BUILD_TUPLE', 102) # Number of tuple items
|
def_op('BUILD_TUPLE', 102) # Number of tuple items
|
||||||
def_op('BUILD_LIST', 103) # Number of list 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
|
name_op('LOAD_ATTR', 105) # Index in name list
|
||||||
def_op('COMPARE_OP', 106) # Comparison operator
|
def_op('COMPARE_OP', 106) # Comparison operator
|
||||||
hascompare.append(106)
|
hascompare.append(106)
|
||||||
|
|
|
@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
|
||||||
Core and builtins
|
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 #1638: %zd configure test fails on Linux
|
||||||
|
|
||||||
- Issue #1620: New property decorator syntax was modifying the decorator
|
- Issue #1620: New property decorator syntax was modifying the decorator
|
||||||
|
|
|
@ -549,6 +549,23 @@ dictresize(PyDictObject *mp, Py_ssize_t minused)
|
||||||
return 0;
|
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
|
/* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
|
||||||
* that may occur (originally dicts supported only string keys, and exceptions
|
* that may occur (originally dicts supported only string keys, and exceptions
|
||||||
* weren't possible). So, while the original intent was that a NULL return
|
* weren't possible). So, while the original intent was that a NULL return
|
||||||
|
|
|
@ -1997,7 +1997,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUILD_MAP:
|
case BUILD_MAP:
|
||||||
x = PyDict_New();
|
x = _PyDict_NewPresized((Py_ssize_t)oparg);
|
||||||
PUSH(x);
|
PUSH(x);
|
||||||
if (x != NULL) continue;
|
if (x != NULL) continue;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2922,11 +2922,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
|
||||||
case IfExp_kind:
|
case IfExp_kind:
|
||||||
return compiler_ifexp(c, e);
|
return compiler_ifexp(c, e);
|
||||||
case Dict_kind:
|
case Dict_kind:
|
||||||
/* XXX get rid of arg? */
|
|
||||||
ADDOP_I(c, BUILD_MAP, 0);
|
|
||||||
n = asdl_seq_LEN(e->v.Dict.values);
|
n = asdl_seq_LEN(e->v.Dict.values);
|
||||||
/* We must arrange things just right for STORE_SUBSCR.
|
ADDOP_I(c, BUILD_MAP, (n>255 ? 255 : n));
|
||||||
It wants the stack to look like (value) (dict) (key) */
|
n = asdl_seq_LEN(e->v.Dict.values);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
VISIT(c, expr,
|
VISIT(c, expr,
|
||||||
(expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
(expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue