orium / rpds

Rust persistent data structures
Mozilla Public License 2.0
1.22k stars 57 forks source link

Iterating over the values in a HashTrieMap #10

Closed Qqwy closed 6 years ago

Qqwy commented 6 years ago

When wanting to update a single value in the HashMap, we just call insert with the new value (and the same key that already was there). Of course, a wrapper could be written to only insert if the key already exists; this is simple to do for the user (although it might be a worthwhile addition to HashTrieMap's API as well, because it is a very common operation.)

However, when I want to update all of the values, I am out of luck: It is not possible to get a multable iterator to the values or (key, value)-pairs with the current API. Is this a restriction by the underlying data structure? Or is this something that could be improved? (Or is it already possible now and did I loverlook it?)

orium commented 6 years ago

Being able to actually mutate the values of the map would make the data structure non-persistent (i.e. previous versions of the data structure would be changed).

The recommended way to do this is by making an entirely new map:

let map: HashTrieMap<&str, i32> =
    HashTrieMap::new()
        .insert("a", 0)
        .insert("b", 1);

let map_updated: HashTrieMap<&str, i32> = map.iter().map(|(&k, &v)| {
    (k, v + 1)
}).collect();

However, this would require you to clone/copy the keys/values.

There is, of course, a way to cheat with interior mutability. You can have the values wrapped around a Cell/RefCell/Mutex:

let map =
    HashTrieMap::new()
        .insert("a", RefCell::new(0))
        .insert("b", RefCell::new(1));

for (_, v) in map.iter() {
    let mut mut_v = v.borrow_mut();
    *mut_v = *mut_v + 1;
}

Keep in mind that previous versions of the map will also change.