Is there an Entry mechanism for BTreeMap that allows returning an immutable reference?
Take the following code, which implements a kind of sparse vector. Essentially, it's a vector that assumes the elements are zero unless specifically set and manipulated:
// External libraries
use std::cell::{Ref, RefCell, RefMut};
use std::collections::BTreeMap;
// Stores a sparse vector
#[derive(Debug)]
struct MyVec {
data: RefCell<BTreeMap<usize, f64>>,
}
impl MyVec {
// Returns a reference to an element
pub fn get<'a>(&'a self, i: usize) -> Ref <'a,f64> {
// Insert a missing element
let mut data = self.data.replace(BTreeMap::new());
match data.get(&i) {
Some(_) => (),
None => {data.insert(i,0.0); ()}
}
self.data.replace(data);
// Return the element
Ref::map(self.data.borrow(), |data| data.get(&i).unwrap())
}
// Returns a mutable reference to an element
pub fn get_mut<'a>(&'a self, i: usize) -> RefMut<'a, f64> {
RefMut::map(self.data.borrow_mut(), |data| data.entry(i).or_insert(0.0))
}
// Create a new sparse vector
pub fn new() -> MyVec {
MyVec {
data: RefCell::new(BTreeMap::new()),
}
}
}
fn main() {
// Create a vector
let x = MyVec::new();
*x.get_mut(3) = 4.0;
*x.get_mut(5) += 0.5;
let x2 = *x.get(2);
let x3 = *x.get(3);
println!("x: {:?}, x[2]: {}, x[3]: {}", x, x2, x3);
}
This returns the result:
x: MyVec { data: RefCell { value: {2: 0.0, 3: 4.0, 5: 0.5} } }, x[2]: 0, x[3]: 4
My issue here is that the function get requires three look-ups into the map. It needs one look-up to determine if the data exists, one lookup to insert the entry if it does not, and a third look-up to return the data. This contrasts from the function get_mut which can do a single look-up for the element, insert a missing zero if necessary, and then return a mutable reference.
Is there a better way to insert a missing element if required and then return an immutable reference to the result?