Skip to content

Commit

Permalink
[stdlib] Add Dict ability to auto reduce capacity
Browse files Browse the repository at this point in the history
Signed-off-by: rd4com <[email protected]>
  • Loading branch information
rd4com committed Jul 1, 2024
1 parent 9cf3a83 commit ade41f9
Showing 1 changed file with 35 additions and 15 deletions.
50 changes: 35 additions & 15 deletions stdlib/src/collections/dict.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -785,12 +785,14 @@ struct Dict[K: KeyElement, V: CollectionElement](
found, slot, index = self._find_index(hash, key)
if found:
self._set_index(slot, Self.REMOVED)
var entry = self._entries.__get_ref(index)
var entry = Reference(self._entries[index])
debug_assert(entry[].__bool__(), "entry in index must be full")
var entry_value = entry[].unsafe_take()
entry[] = None
self.size -= 1
return entry_value.value^
var tmp = entry_value.value^
self._maybe_resize()
return tmp^
raise "KeyError"

fn popitem(inout self) raises -> DictEntry[K, V]:
Expand Down Expand Up @@ -932,28 +934,46 @@ struct Dict[K: KeyElement, V: CollectionElement](
return (True, slot, index)
self._next_index_slot(slot, perturb)

fn _under_load_factor(self) -> Bool:
if self._reserved() == Self._initial_reservation:
return False
return 3 * self.size < self._reserved()

fn _over_load_factor(self) -> Bool:
return 3 * self.size > 2 * self._reserved()

fn _over_compact_factor(self) -> Bool:
return 4 * self._n_entries > 3 * self._reserved()

fn _maybe_resize(inout self):
if not self._over_load_factor():
if self._over_compact_factor():
self._compact()
return
var _reserved = self._reserved() * 2
self.size = 0
self._n_entries = 0
if self._over_load_factor():
self._resize(self._reserved() << 1)
elif self._under_load_factor():
self._resize(self._reserved() >> 1)
elif self._over_compact_factor():
self._compact()

fn _resize(inout self, _new_reserved: Int):
"""Not for resizing, used internally to manage the capacity.
The `Dict` load balancer uses that method for balancing memory usage.
"""
debug_assert(_new_reserved%2==0, "_new_reserved is not a power of two")
var old_entries = self._entries^
self._entries = self._new_entries(_reserved)
self._index = _DictIndex(self._reserved())

for i in range(len(old_entries)):
var entry = old_entries.__get_ref(i)
self._entries = self._new_entries(_new_reserved)
self._index = _DictIndex(_new_reserved)
self.size = 0
for i in range(self._n_entries):
var entry = Reference(old_entries[i])
if entry[]:
self._insert(entry[].unsafe_take())
self._set_index(
self._find_empty_index(entry[].value().hash),
self.size
)
self._entries[self.size] = entry[].unsafe_take()
self.size +=1
self._n_entries = self.size

fn _compact(inout self):
self._index = _DictIndex(self._reserved())
Expand Down

0 comments on commit ade41f9

Please sign in to comment.