Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit afb6ae8

Browse files
committed
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.
1 parent b9d973d commit afb6ae8

1 file changed

Lines changed: 29 additions & 23 deletions

File tree

Objects/dictobject.c

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,13 @@ struct dictobject {
162162
PyObject_HEAD
163163
int ma_fill; /* # Active + # Dummy */
164164
int ma_used; /* # Active */
165-
int ma_size; /* total # slots in ma_table */
165+
166+
/* The table contains ma_mask + 1 slots, and that's a power of 2.
167+
* We store the mask instead of the size because the mask is more
168+
* frequently needed.
169+
*/
170+
int ma_mask;
171+
166172
/* ma_table points to ma_smalltable for small tables, else to
167173
* additional malloc'ed memory. ma_table is never NULL! This rule
168174
* saves repeated runtime null-tests in the workhorse getitem and
@@ -194,7 +200,7 @@ show_counts(void)
194200
#define empty_to_minsize(mp) do { \
195201
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
196202
(mp)->ma_table = (mp)->ma_smalltable; \
197-
(mp)->ma_size = MINSIZE; \
203+
(mp)->ma_mask = MINSIZE - 1; \
198204
(mp)->ma_used = (mp)->ma_fill = 0; \
199205
} while(0)
200206

@@ -248,7 +254,7 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
248254
register int i;
249255
register unsigned int perturb;
250256
register dictentry *freeslot;
251-
register unsigned int mask = mp->ma_size-1;
257+
register unsigned int mask = mp->ma_mask;
252258
dictentry *ep0 = mp->ma_table;
253259
register dictentry *ep;
254260
register int restore_error;
@@ -359,7 +365,7 @@ lookdict_string(dictobject *mp, PyObject *key, register long hash)
359365
register int i;
360366
register unsigned int perturb;
361367
register dictentry *freeslot;
362-
register unsigned int mask = mp->ma_size-1;
368+
register unsigned int mask = mp->ma_mask;
363369
dictentry *ep0 = mp->ma_table;
364370
register dictentry *ep;
365371

@@ -492,7 +498,7 @@ dictresize(dictobject *mp, int minused)
492498
/* Make the dict empty, using the new table. */
493499
assert(newtable != oldtable);
494500
mp->ma_table = newtable;
495-
mp->ma_size = newsize;
501+
mp->ma_mask = newsize - 1;
496502
memset(newtable, 0, sizeof(dictentry) * newsize);
497503
mp->ma_used = 0;
498504
i = mp->ma_fill;
@@ -580,7 +586,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
580586
if (hash == -1)
581587
return -1;
582588
}
583-
assert(mp->ma_fill < mp->ma_size);
589+
assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */
584590
n_used = mp->ma_used;
585591
Py_INCREF(value);
586592
Py_INCREF(key);
@@ -591,7 +597,7 @@ PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
591597
* much larger than ma_used, meaning a lot of dict keys have been
592598
* deleted).
593599
*/
594-
if (mp->ma_used > n_used && mp->ma_fill*3 >= mp->ma_size*2) {
600+
if (mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2) {
595601
if (dictresize(mp, mp->ma_used*2) != 0)
596602
return -1;
597603
}
@@ -652,7 +658,7 @@ PyDict_Clear(PyObject *op)
652658
return;
653659
mp = (dictobject *)op;
654660
#ifdef Py_DEBUG
655-
n = mp->ma_size;
661+
n = mp->ma_mask + 1;
656662
i = 0;
657663
#endif
658664

@@ -721,10 +727,10 @@ PyDict_Next(PyObject *op, int *ppos, PyObject **pkey, PyObject **pvalue)
721727
i = *ppos;
722728
if (i < 0)
723729
return 0;
724-
while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
730+
while (i <= mp->ma_mask && mp->ma_table[i].me_value == NULL)
725731
i++;
726732
*ppos = i+1;
727-
if (i >= mp->ma_size)
733+
if (i > mp->ma_mask)
728734
return 0;
729735
if (pkey)
730736
*pkey = mp->ma_table[i].me_key;
@@ -772,7 +778,7 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
772778

773779
fprintf(fp, "{");
774780
any = 0;
775-
for (i = 0; i < mp->ma_size; i++) {
781+
for (i = 0; i <= mp->ma_mask; i++) {
776782
dictentry *ep = mp->ma_table + i;
777783
PyObject *pvalue = ep->me_value;
778784
if (pvalue != NULL) {
@@ -819,7 +825,7 @@ dict_repr(dictobject *mp)
819825
sepa = PyString_FromString(", ");
820826
colon = PyString_FromString(": ");
821827
any = 0;
822-
for (i = 0; i < mp->ma_size && v; i++) {
828+
for (i = 0; i <= mp->ma_mask && v; i++) {
823829
dictentry *ep = mp->ma_table + i;
824830
PyObject *pvalue = ep->me_value;
825831
if (pvalue != NULL) {
@@ -905,7 +911,7 @@ dict_keys(register dictobject *mp, PyObject *args)
905911
Py_DECREF(v);
906912
goto again;
907913
}
908-
for (i = 0, j = 0; i < mp->ma_size; i++) {
914+
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
909915
if (mp->ma_table[i].me_value != NULL) {
910916
PyObject *key = mp->ma_table[i].me_key;
911917
Py_INCREF(key);
@@ -936,7 +942,7 @@ dict_values(register dictobject *mp, PyObject *args)
936942
Py_DECREF(v);
937943
goto again;
938944
}
939-
for (i = 0, j = 0; i < mp->ma_size; i++) {
945+
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
940946
if (mp->ma_table[i].me_value != NULL) {
941947
PyObject *value = mp->ma_table[i].me_value;
942948
Py_INCREF(value);
@@ -981,7 +987,7 @@ dict_items(register dictobject *mp, PyObject *args)
981987
goto again;
982988
}
983989
/* Nothing we do below makes any function calls. */
984-
for (i = 0, j = 0; i < mp->ma_size; i++) {
990+
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
985991
if (mp->ma_table[i].me_value != NULL) {
986992
key = mp->ma_table[i].me_key;
987993
value = mp->ma_table[i].me_value;
@@ -1010,11 +1016,11 @@ dict_update(register dictobject *mp, PyObject *args)
10101016
/* Do one big resize at the start, rather than incrementally
10111017
resizing as we insert new items. Expect that there will be
10121018
no (or few) overlapping keys. */
1013-
if ((mp->ma_fill + other->ma_used)*3 >= mp->ma_size*2) {
1019+
if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
10141020
if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
10151021
return NULL;
10161022
}
1017-
for (i = 0; i < other->ma_size; i++) {
1023+
for (i = 0; i <= other->ma_mask; i++) {
10181024
entry = &other->ma_table[i];
10191025
if (entry->me_value != NULL) {
10201026
Py_INCREF(entry->me_key);
@@ -1055,7 +1061,7 @@ PyDict_Copy(PyObject *o)
10551061
if (mp->ma_used > 0) {
10561062
if (dictresize(copy, mp->ma_used*3/2) != 0)
10571063
return NULL;
1058-
for (i = 0; i < mp->ma_size; i++) {
1064+
for (i = 0; i <= mp->ma_mask; i++) {
10591065
entry = &mp->ma_table[i];
10601066
if (entry->me_value != NULL) {
10611067
Py_INCREF(entry->me_key);
@@ -1123,7 +1129,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
11231129
PyObject *aval = NULL; /* a[akey] */
11241130
int i, cmp;
11251131

1126-
for (i = 0; i < a->ma_size; i++) {
1132+
for (i = 0; i <= a->ma_mask; i++) {
11271133
PyObject *thiskey, *thisaval, *thisbval;
11281134
if (a->ma_table[i].me_value == NULL)
11291135
continue;
@@ -1136,7 +1142,7 @@ characterize(dictobject *a, dictobject *b, PyObject **pval)
11361142
goto Fail;
11371143
}
11381144
if (cmp > 0 ||
1139-
i >= a->ma_size ||
1145+
i > a->ma_mask ||
11401146
a->ma_table[i].me_value == NULL)
11411147
{
11421148
/* Not the *smallest* a key; or maybe it is
@@ -1251,7 +1257,7 @@ dict_equal(dictobject *a, dictobject *b)
12511257
return 0;
12521258

12531259
/* Same # of entries -- check all of 'em. Exit early on any diff. */
1254-
for (i = 0; i < a->ma_size; i++) {
1260+
for (i = 0; i <= a->ma_mask; i++) {
12551261
PyObject *aval = a->ma_table[i].me_value;
12561262
if (aval != NULL) {
12571263
int cmp;
@@ -1427,11 +1433,11 @@ dict_popitem(dictobject *mp, PyObject *args)
14271433
* finger that's out of bounds now because it wrapped around
14281434
* or the table shrunk -- simply make sure it's in bounds now.
14291435
*/
1430-
if (i >= mp->ma_size || i < 1)
1436+
if (i > mp->ma_mask || i < 1)
14311437
i = 1; /* skip slot 0 */
14321438
while ((ep = &mp->ma_table[i])->me_value == NULL) {
14331439
i++;
1434-
if (i >= mp->ma_size)
1440+
if (i > mp->ma_mask)
14351441
i = 1;
14361442
}
14371443
}

0 commit comments

Comments
 (0)