-# XXX: Move the size checking and resize into a single call which is opauqe to
-# the JIT when the dict isn't virtual, to avoid extra branches.
@jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i))
entry.key = lltype.nullptr(ENTRY.key.TO)
entry.value = lltype.nullptr(ENTRY.value.TO)
- num_entries = len(d.entries)
- if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4:
+ # The rest is commented out: like CPython we no longer shrink the
+ # dictionary here. It may shrink later if we try to append a number
+ # of new items to it. Unsure if this behavior was designed in
+ # CPython or is accidental. A design reason would be that if you
+ # delete all items in a dictionary (e.g. with a series of
+ # popitem()), then CPython avoids shrinking the table several times.
+ #num_entries = len(d.entries)
+ #if num_entries > DICT_INITSIZE and d.num_items <= num_entries / 4:
+ # A previous xxx: move the size checking and resize into a single
+ # call which is opaque to the JIT when the dict isn't virtual, to
+ # avoid extra branches.
old_size = len(old_entries)
# make a 'new_size' estimate and shrink it if there are many
- # deleted entry markers
- new_size = old_size * 2
- while new_size > DICT_INITSIZE and d.num_items < new_size / 4:
+ # deleted entry markers. See CPython for why it is a good idea to
+ # quadruple the dictionary size as long as it's not too big.
+ if d.num_items > 50000: new_estimate = d.num_items * 2
+ else: new_estimate = d.num_items * 4
+ new_size = DICT_INITSIZE
+ while new_size <= new_estimate:
d.entries = lltype.typeOf(old_entries).TO.allocate(new_size)
d.resize_counter = new_size * 2