Commit afb6ae84 authored by Tim Peters's avatar Tim Peters

Store the mask instead of the size in dictobjects. The mask is more

frequently used, and in particular this allows to drop the last
remaining obvious time-waster in the crucial lookdict() and
lookdict_string() functions.  Other changes consist mostly of changing
"i < ma_size" to "i <= ma_mask" everywhere.
parent b9d973da
...@@ -162,7 +162,13 @@ struct dictobject { ...@@ -162,7 +162,13 @@ struct dictobject {
PyObject_HEAD PyObject_HEAD
int ma_fill; /* # Active + # Dummy */ int ma_fill; /* # Active + # Dummy */
int ma_used; /* # Active */ int ma_used; /* # Active */
int ma_size; /* total # slots in ma_table */
/* The table contains ma_mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
int ma_mask;
/* ma_table points to ma_smalltable for small tables, else to /* ma_table points to ma_smalltable for small tables, else to
* additional malloc'ed memory. ma_table is never NULL! This rule * additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and * saves repeated runtime null-tests in the workhorse getitem and
...@@ -194,7 +200,7 @@ show_counts(void) ...@@ -194,7 +200,7 @@ show_counts(void)
#define empty_to_minsize(mp) do { \ #define empty_to_minsize(mp) do { \
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \ memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
(mp)->ma_table = (mp)->ma_smalltable; \ (mp)->ma_table = (mp)->ma_smalltable; \
(mp)->ma_size = MINSIZE; \ (mp)->ma_mask = MINSIZE - 1; \
(mp)->ma_used = (mp)->ma_fill = 0; \ (mp)->ma_used = (mp)->ma_fill = 0; \
} while(0) } while(0)
...@@ -248,7 +254,7 @@ lookdict(dictobject *mp, PyObject *key, register long hash) ...@@ -248,7 +254,7 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
register int i; register int i;
register unsigned int perturb; register unsigned int perturb;
register dictentry *freeslot; register dictentry *freeslot;
register unsigned int mask = mp->ma_size-1; register unsigned int mask = mp->ma_mask;
dictentry *ep0 = mp->ma_table; dictentry *ep0 = mp->ma_table;
register dictentry *ep; register dictentry *ep;
register int restore_error; register int restore_error;
...@@ -359,7 +365,7 @@ lookdict_string(dictobject *mp, PyObject *key, register long hash) ...@@ -359,7 +365,7 @@ lookdict_string(dictobject *mp, PyObject *key, register long hash)
register int i; register int i;
register unsigned int perturb; register unsigned int perturb;
register dictentry *freeslot; register dictentry *freeslot;
register unsigned int mask = mp->ma_size-1; register unsigned int mask = mp->ma_mask;
dictentry *ep0 = mp->ma_table; dictentry *ep0 = mp->ma_table;
register dictentry *ep; register dictentry *ep;
...@@ -492,7 +498,7 @@ dictresize(dictobject *mp, int minused) ...@@ -492,7 +498,7 @@ dictresize(dictobject *mp, int minused)
/* Make the dict empty, using the new table. */ /* Make the dict empty, using the new table. */
assert(newtable != oldtable); assert(newtable != oldtable);
mp->ma_table = newtable; mp->ma_table = newtable;
mp->ma_size = newsize; mp->ma_mask = newsize - 1;
memset(newtable, 0, sizeof(dictentry) * newsize); memset(newtable, 0, sizeof(dictentry) * newsize);
mp->ma_used = 0; mp->ma_used = 0;
i = mp->ma_fill; i = mp->ma_fill;
...@@ -580,7 +586,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value) ...@@ -580,7 +586,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
if (hash == -1) if (hash == -1)
return -1; return -1;
} }
assert(mp->ma_fill < mp->ma_size); assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */
n_used = mp->ma_used; n_used = mp->ma_used;
Py_INCREF(value); Py_INCREF(value);
Py_INCREF(key); Py_INCREF(key);
...@@ -591,7 +597,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value) ...@@ -591,7 +597,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
* much larger than ma_used, meaning a lot of dict keys have been * much larger than ma_used, meaning a lot of dict keys have been
* deleted). * deleted).
*/ */
if (mp->ma_used > n_used && mp->ma_fill*3 >= mp->ma_size*2) { if (mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2) {
if (dictresize(mp, mp->ma_used*2) != 0) if (dictresize(mp, mp->ma_used*2) != 0)
return -1; return -1;
} }
...@@ -652,7 +658,7 @@ PyDict_Clear(PyObject *op) ...@@ -652,7 +658,7 @@ PyDict_Clear(PyObject *op)
return; return;
mp = (dictobject *)op; mp = (dictobject *)op;
#ifdef Py_DEBUG #ifdef Py_DEBUG
n = mp->ma_size; n = mp->ma_mask + 1;
i = 0; i = 0;
#endif #endif
...@@ -721,10 +727,10 @@ PyDict_Next(PyObject *op, int *ppos, PyObject **pkey, PyObject **pvalue) ...@@ -721,10 +727,10 @@ PyDict_Next(PyObject *op, int *ppos, PyObject **pkey, PyObject **pvalue)
i = *ppos; i = *ppos;
if (i < 0) if (i < 0)
return 0; return 0;
while (i < mp->ma_size && mp->ma_table[i].me_value == NULL) while (i <= mp->ma_mask && mp->ma_table[i].me_value == NULL)
i++; i++;
*ppos = i+1; *ppos = i+1;
if (i >= mp->ma_size) if (i > mp->ma_mask)
return 0; return 0;
if (pkey) if (pkey)
*pkey = mp->ma_table[i].me_key; *pkey = mp->ma_table[i].me_key;
...@@ -772,7 +778,7 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags) ...@@ -772,7 +778,7 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
fprintf(fp, "{"); fprintf(fp, "{");
any = 0; any = 0;
for (i = 0; i < mp->ma_size; i++) { for (i = 0; i <= mp->ma_mask; i++) {
dictentry *ep = mp->ma_table + i; dictentry *ep = mp->ma_table + i;
PyObject *pvalue = ep->me_value; PyObject *pvalue = ep->me_value;
if (pvalue != NULL) { if (pvalue != NULL) {
...@@ -819,7 +825,7 @@ dict_repr(dictobject *mp) ...@@ -819,7 +825,7 @@ dict_repr(dictobject *mp)
sepa = PyString_FromString(", "); sepa = PyString_FromString(", ");
colon = PyString_FromString(": "); colon = PyString_FromString(": ");
any = 0; any = 0;
for (i = 0; i < mp->ma_size && v; i++) { for (i = 0; i <= mp->ma_mask && v; i++) {
dictentry *ep = mp->ma_table + i; dictentry *ep = mp->ma_table + i;
PyObject *pvalue = ep->me_value; PyObject *pvalue = ep->me_value;
if (pvalue != NULL) { if (pvalue != NULL) {
...@@ -905,7 +911,7 @@ dict_keys(register dictobject *mp, PyObject *args) ...@@ -905,7 +911,7 @@ dict_keys(register dictobject *mp, PyObject *args)
Py_DECREF(v); Py_DECREF(v);
goto again; goto again;
} }
for (i = 0, j = 0; i < mp->ma_size; i++) { for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) { if (mp->ma_table[i].me_value != NULL) {
PyObject *key = mp->ma_table[i].me_key; PyObject *key = mp->ma_table[i].me_key;
Py_INCREF(key); Py_INCREF(key);
...@@ -936,7 +942,7 @@ dict_values(register dictobject *mp, PyObject *args) ...@@ -936,7 +942,7 @@ dict_values(register dictobject *mp, PyObject *args)
Py_DECREF(v); Py_DECREF(v);
goto again; goto again;
} }
for (i = 0, j = 0; i < mp->ma_size; i++) { for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) { if (mp->ma_table[i].me_value != NULL) {
PyObject *value = mp->ma_table[i].me_value; PyObject *value = mp->ma_table[i].me_value;
Py_INCREF(value); Py_INCREF(value);
...@@ -981,7 +987,7 @@ dict_items(register dictobject *mp, PyObject *args) ...@@ -981,7 +987,7 @@ dict_items(register dictobject *mp, PyObject *args)
goto again; goto again;
} }
/* Nothing we do below makes any function calls. */ /* Nothing we do below makes any function calls. */
for (i = 0, j = 0; i < mp->ma_size; i++) { for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) { if (mp->ma_table[i].me_value != NULL) {
key = mp->ma_table[i].me_key; key = mp->ma_table[i].me_key;
value = mp->ma_table[i].me_value; value = mp->ma_table[i].me_value;
...@@ -1010,11 +1016,11 @@ dict_update(register dictobject *mp, PyObject *args) ...@@ -1010,11 +1016,11 @@ dict_update(register dictobject *mp, PyObject *args)
/* Do one big resize at the start, rather than incrementally /* Do one big resize at the start, rather than incrementally
resizing as we insert new items. Expect that there will be resizing as we insert new items. Expect that there will be
no (or few) overlapping keys. */ no (or few) overlapping keys. */
if ((mp->ma_fill + other->ma_used)*3 >= mp->ma_size*2) { 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) if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
return NULL; return NULL;
} }
for (i = 0; i < other->ma_size; i++) { for (i = 0; i <= other->ma_mask; i++) {
entry = &other->ma_table[i]; entry = &other->ma_table[i];
if (entry->me_value != NULL) { if (entry->me_value != NULL) {
Py_INCREF(entry->me_key); Py_INCREF(entry->me_key);
...@@ -1055,7 +1061,7 @@ PyDict_Copy(PyObject *o) ...@@ -1055,7 +1061,7 @@ PyDict_Copy(PyObject *o)
if (mp->ma_used > 0) { if (mp->ma_used > 0) {
if (dictresize(copy, mp->ma_used*3/2) != 0) if (dictresize(copy, mp->ma_used*3/2) != 0)
return NULL; return NULL;
for (i = 0; i < mp->ma_size; i++) { for (i = 0; i <= mp->ma_mask; i++) {
entry = &mp->ma_table[i]; entry = &mp->ma_table[i];
if (entry->me_value != NULL) { if (entry->me_value != NULL) {
Py_INCREF(entry->me_key); Py_INCREF(entry->me_key);
...@@ -1123,7 +1129,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval) ...@@ -1123,7 +1129,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
PyObject *aval = NULL; /* a[akey] */ PyObject *aval = NULL; /* a[akey] */
int i, cmp; int i, cmp;
for (i = 0; i < a->ma_size; i++) { for (i = 0; i <= a->ma_mask; i++) {
PyObject *thiskey, *thisaval, *thisbval; PyObject *thiskey, *thisaval, *thisbval;
if (a->ma_table[i].me_value == NULL) if (a->ma_table[i].me_value == NULL)
continue; continue;
...@@ -1136,7 +1142,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval) ...@@ -1136,7 +1142,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
goto Fail; goto Fail;
} }
if (cmp > 0 || if (cmp > 0 ||
i >= a->ma_size || i > a->ma_mask ||
a->ma_table[i].me_value == NULL) a->ma_table[i].me_value == NULL)
{ {
/* Not the *smallest* a key; or maybe it is /* Not the *smallest* a key; or maybe it is
...@@ -1251,7 +1257,7 @@ dict_equal(dictobject *a, dictobject *b) ...@@ -1251,7 +1257,7 @@ dict_equal(dictobject *a, dictobject *b)
return 0; return 0;
/* Same # of entries -- check all of 'em. Exit early on any diff. */ /* Same # of entries -- check all of 'em. Exit early on any diff. */
for (i = 0; i < a->ma_size; i++) { for (i = 0; i <= a->ma_mask; i++) {
PyObject *aval = a->ma_table[i].me_value; PyObject *aval = a->ma_table[i].me_value;
if (aval != NULL) { if (aval != NULL) {
int cmp; int cmp;
...@@ -1427,11 +1433,11 @@ dict_popitem(dictobject *mp, PyObject *args) ...@@ -1427,11 +1433,11 @@ dict_popitem(dictobject *mp, PyObject *args)
* finger that's out of bounds now because it wrapped around * finger that's out of bounds now because it wrapped around
* or the table shrunk -- simply make sure it's in bounds now. * or the table shrunk -- simply make sure it's in bounds now.
*/ */
if (i >= mp->ma_size || i < 1) if (i > mp->ma_mask || i < 1)
i = 1; /* skip slot 0 */ i = 1; /* skip slot 0 */
while ((ep = &mp->ma_table[i])->me_value == NULL) { while ((ep = &mp->ma_table[i])->me_value == NULL) {
i++; i++;
if (i >= mp->ma_size) if (i > mp->ma_mask)
i = 1; i = 1;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment