Is there something like HashMap<K, Weak<V>>
, but which it auto drops the (K, Weak<V>)
pairs when the Weak<V>
hits a strong-count of 0 ?
You could implement it yourself. I see 3 strategies:
-
Wrap
get
, and only remove entries lazily whenupgrade
of the value fails. -
From time to time, run
hashmap.retain
and drop entries withWeak::strong_count(v) == 0
. You may need to runhashmap.shrink_to_fit()
too to free excess memory. This is going to be expensive, so run it every X inserts or every X minutes. -
Use
Arc<Mutex<HashMap<Arc<K>, Weak<NotifyOnDrop<V>>>>>
and wrap values in a newtype that will try to immediately remove entries from the hashmap when the value is dropped (Arc
runs destructors even whenWeak
references exist). As you can see, injecting an active observer into this is quite messy.
It's almost what I want, except cleaning out weak ptrs with 0-strong count seems to be O(n), which is rather expensive if called frequently.
The third option need not be O(n), because it can keep track of which keys should be removed (by sending them to a channel which is read by the cleanup operation, perhaps).
Also, if you run the sweep only when enough inserts have happened to double the length, it is amortized O(1), which may be good enough.
I was replying to @user16251 's weak-table crate WeakValueHashMap in weak_table - Rust which are documented to e O(n). I was note replying to @kornel 's three strategies.
I agree with you that the gist of "each obj keeps a Rc to the hashtable and removes self in destructor" can do it in O(1).
I think that's what the weak-table
crate does, based on my skimming of the source code.
There's also no need to run the entire sweep as an atomic operation. If you're implementing the hashtable yourself, you can maintain a sweep pointer over the underlying vector that you advance a few places on every insert.