summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-06-04 21:00:21 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-06-04 21:00:21 (GMT)
commitafb6ae84526e9e6f70fef55b3743c2cd91327391 (patch)
tree2459ed703fddf4d70095cb63ca8669ca166c0ce6 /Objects
parentb9d973dac5f846123922492ea333c196c105b089 (diff)
downloadcpython-afb6ae84526e9e6f70fef55b3743c2cd91327391.zip
cpython-afb6ae84526e9e6f70fef55b3743c2cd91327391.tar.gz
cpython-afb6ae84526e9e6f70fef55b3743c2cd91327391.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index ce44abe..21cc6c6 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -162,7 +162,13 @@ struct dictobject {
PyObject_HEAD
int ma_fill; /* # Active + # Dummy */
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
* additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and
@@ -194,7 +200,7 @@ show_counts(void)
#define empty_to_minsize(mp) do { \
memset((mp)->ma_smalltable, 0, sizeof((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; \
} while(0)
@@ -248,7 +254,7 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
register int i;
register unsigned int perturb;
register dictentry *freeslot;
- register unsigned int mask = mp->ma_size-1;
+ register unsigned int mask = mp->ma_mask;
dictentry *ep0 = mp->ma_table;
register dictentry *ep;
register int restore_error;
@@ -359,7 +365,7 @@ lookdict_string(dictobject *mp, PyObject *key, register long hash)
register int i;
register unsigned int perturb;
register dictentry *freeslot;
- register unsigned int mask = mp->ma_size-1;
+ register unsigned int mask = mp->ma_mask;
dictentry *ep0 = mp->ma_table;
register dictentry *ep;
@@ -492,7 +498,7 @@ dictresize(dictobject *mp, int minused)
/* Make the dict empty, using the new table. */
assert(newtable != oldtable);
mp->ma_table = newtable;
- mp->ma_size = newsize;
+ mp->ma_mask = newsize - 1;
memset(newtable, 0, sizeof(dictentry) * newsize);
mp->ma_used = 0;
i = mp->ma_fill;
@@ -580,7 +586,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
if (hash == -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;
Py_INCREF(value);
Py_INCREF(key);
@@ -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
* 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)
return -1;
}
@@ -652,7 +658,7 @@ PyDict_Clear(PyObject *op)
return;
mp = (dictobject *)op;
#ifdef Py_DEBUG
- n = mp->ma_size;
+ n = mp->ma_mask + 1;
i = 0;
#endif
@@ -721,10 +727,10 @@ PyDict_Next(PyObject *op, int *ppos, PyObject **pkey, PyObject **pvalue)
i = *ppos;
if (i < 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++;
*ppos = i+1;
- if (i >= mp->ma_size)
+ if (i > mp->ma_mask)
return 0;
if (pkey)
*pkey = mp->ma_table[i].me_key;
@@ -772,7 +778,7 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
fprintf(fp, "{");
any = 0;
- for (i = 0; i < mp->ma_size; i++) {
+ for (i = 0; i <= mp->ma_mask; i++) {
dictentry *ep = mp->ma_table + i;
PyObject *pvalue = ep->me_value;
if (pvalue != NULL) {
@@ -819,7 +825,7 @@ dict_repr(dictobject *mp)
sepa = PyString_FromString(", ");
colon = PyString_FromString(": ");
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;
PyObject *pvalue = ep->me_value;
if (pvalue != NULL) {
@@ -905,7 +911,7 @@ dict_keys(register dictobject *mp, PyObject *args)
Py_DECREF(v);
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) {
PyObject *key = mp->ma_table[i].me_key;
Py_INCREF(key);
@@ -936,7 +942,7 @@ dict_values(register dictobject *mp, PyObject *args)
Py_DECREF(v);
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) {
PyObject *value = mp->ma_table[i].me_value;
Py_INCREF(value);
@@ -981,7 +987,7 @@ dict_items(register dictobject *mp, PyObject *args)
goto again;
}
/* 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) {
key = mp->ma_table[i].me_key;
value = mp->ma_table[i].me_value;
@@ -1010,11 +1016,11 @@ dict_update(register dictobject *mp, PyObject *args)
/* 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 ((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_size; i++) {
+ for (i = 0; i <= other->ma_mask; i++) {
entry = &other->ma_table[i];
if (entry->me_value != NULL) {
Py_INCREF(entry->me_key);
@@ -1055,7 +1061,7 @@ PyDict_Copy(PyObject *o)
if (mp->ma_used > 0) {
if (dictresize(copy, mp->ma_used*3/2) != 0)
return NULL;
- for (i = 0; i < mp->ma_size; i++) {
+ for (i = 0; i <= mp->ma_mask; i++) {
entry = &mp->ma_table[i];
if (entry->me_value != NULL) {
Py_INCREF(entry->me_key);
@@ -1123,7 +1129,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
PyObject *aval = NULL; /* a[akey] */
int i, cmp;
- for (i = 0; i < a->ma_size; i++) {
+ for (i = 0; i <= a->ma_mask; i++) {
PyObject *thiskey, *thisaval, *thisbval;
if (a->ma_table[i].me_value == NULL)
continue;
@@ -1136,7 +1142,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
goto Fail;
}
if (cmp > 0 ||
- i >= a->ma_size ||
+ i > a->ma_mask ||
a->ma_table[i].me_value == NULL)
{
/* Not the *smallest* a key; or maybe it is
@@ -1251,7 +1257,7 @@ dict_equal(dictobject *a, dictobject *b)
return 0;
/* 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;
if (aval != NULL) {
int cmp;
@@ -1427,11 +1433,11 @@ dict_popitem(dictobject *mp, PyObject *args)
* finger that's out of bounds now because it wrapped around
* 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 */
while ((ep = &mp->ma_table[i])->me_value == NULL) {
i++;
- if (i >= mp->ma_size)
+ if (i > mp->ma_mask)
i = 1;
}
}