1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
use crate::ImpVec;
use orx_split_vec::SplitVecGrowth;
impl<T, G> ImpVec<T, G>
where
G: SplitVecGrowth<T>,
{
/// Returns a mutable reference to the element at the given `index`,
/// returns None if the index is out of bounds.
///
/// Unlike standard vector or `SplitVec`, this operation does **not**
/// require a mut reference.
///
/// # Safety
///
/// The following are the reasons why the access is safe:
///
/// * Due to the guarantees of the underlying `SplitVec`, pushed elements
/// are pinned to their memory location unless a method requiring a mut
/// reference to the vector is called. These are the methods that would
/// lead to changing positions of existing elements such as `insert`, `remove`,
/// `pop` or `clear`. On the other hand, `push`ing to or `extend`ing the
/// imp-vec does not affect already added elements' memory locations.
/// Therefore, whenever, we access an element with the given `index`,
/// we are sure that we are accessing the correct element.
/// Further, we are sure that the obtained mutable reference will be valid
/// and targeting the correct data.
///
/// * Mutation of the element is handled over an internal `RefCell`
/// which would provide the guarantees that there will only be one
/// mutable borrow at a time; the code will panic otherwise.
///
/// The method is still marked unsafe due to the following reasons:
///
/// * It makes it easy to have cyclic references which is often useful
/// in cyclic data structures. However, the implementer needs to be
/// careful for certain errors.
/// Default implementations of traits such as `Debug` or `PartialEq` could
/// easily lead to stackoverflows. See `ImpNode` struct which is a wrapper
/// around the data to be stored in an imp-vec while avoiding such problems.
///
/// * It is possible to hold an immutable reference to, say, the i-th
/// element of the vector. Assume that the value of the element is 'x' at the
/// time the reference is created. At the same time, it is also possible to get
/// a mutable reference to the i-th element and mutate its value to 'y'.
/// Finally, we can dereference the prior immutable reference just to read the
/// data as 'y'. This is confusing, and hence, scope of these mutations should
/// be kept limited; ideally, only while building a data structure which requires
/// this feature. On the other hand, it is safe to dereference the prior
/// immutable reference, the reference cannot be invalid due to the guarantees
/// discussed above. A similar example is demonstrated below.
///
/// # Examples
///
/// ```
/// use orx_imp_vec::ImpVec;
///
/// let vec = ImpVec::with_linear_growth(4);
///
/// for i in 0..21 {
/// vec.push(i);
/// }
/// let immut_ref_7 = &vec[7];
/// assert_eq!(7, *immut_ref_7);
///
/// for i in 0..21 {
/// *unsafe{ vec.get_mut(i) }.unwrap() *= 100;
/// }
///
/// for i in 0..21 {
/// assert_eq!(100 * i, vec[i]);
/// }
/// assert_eq!(700, *immut_ref_7);
/// ```
pub unsafe fn get_mut(&self, index: usize) -> Option<&mut T> {
self.get_fragment_and_inner_indices(index).map(|(f, i)| {
let split_vec = unsafe { &mut *self.as_mut_ptr() };
let fragments = unsafe { split_vec.fragments_mut() };
&mut fragments[f][i]
})
}
}
#[cfg(test)]
mod tests {
use crate::{test_all_growth_types, ImpVec};
use orx_split_vec::SplitVecGrowth;
#[test]
fn get_mut() {
fn test<G: SplitVecGrowth<usize>>(vec: ImpVec<usize, G>) {
for i in 0..462 {
vec.push(i);
assert_eq!(None, unsafe { vec.get_mut(i + 1) });
}
let immut_refs: Vec<_> = vec.into_iter().collect();
let mut mut_refs: Vec<_> = (0..vec.len())
.map(|i| unsafe { vec.get_mut(i) }.expect("in-bounds"))
.collect();
for i in 0..462 {
assert_eq!(i, vec[i]);
assert_eq!(i, *immut_refs[i]);
*mut_refs[i] *= 100;
assert_eq!(i * 100, *immut_refs[i]);
assert_eq!(i * 100, *mut_refs[i]);
}
for i in 0..462 {
assert_eq!(i * 100, vec[i]);
}
}
test_all_growth_types!(test);
}
}