-//! Implements a map from disjoint non-empty integer ranges to data associated with those ranges
+//! Implements a map from integer indices to data.
+//! Rather than storing data for every index, internally, this maps entire ranges to the data.
+//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as
+//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated).
+//! Users must not depend on whether a range is coalesced or not, even though this is observable
+//! via the iteration APIs.
use std::collections::{BTreeMap};
use std::ops;
impl Range {
fn range(offset: u64, len: u64) -> ops::Range<Range> {
+ assert!(len > 0);
// We select all elements that are within
// the range given by the offset into the allocation and the length.
// This is sound if all ranges that intersect with the argument range, are in the
left..right
}
+ /// Tests if all of [offset, offset+len) are contained in this range.
fn overlaps(&self, offset: u64, len: u64) -> bool {
assert!(len > 0);
offset < self.end && offset+len >= self.start
}
fn iter_with_range<'a>(&'a self, offset: u64, len: u64) -> impl Iterator<Item=(&'a Range, &'a T)> + 'a {
+ assert!(len > 0);
self.map.range(Range::range(offset, len))
.filter_map(move |(range, data)| {
if range.overlaps(offset, len) {
}
fn split_entry_at(&mut self, offset: u64) where T: Clone {
- let range = match self.iter_with_range(offset, 0).next() {
+ let range = match self.iter_with_range(offset, 1).next() {
Some((&range, _)) => range,
None => return,
};
pub fn iter_mut_with_gaps<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator<Item=&'a mut T> + 'a
where T: Clone
{
+ assert!(len > 0);
// Preparation: Split first and last entry as needed.
self.split_entry_at(offset);
self.split_entry_at(offset+len);
{
// Do a first iteration to collect the gaps
let mut gaps = Vec::new();
- let mut last_end = None;
+ let mut last_end = offset;
for (range, _) in self.iter_with_range(offset, len) {
- if let Some(last_end) = last_end {
- if last_end < range.start {
- gaps.push(Range { start: last_end, end: range.start });
- }
+ if last_end < range.start {
+ gaps.push(Range { start: last_end, end: range.start });
}
- last_end = Some(range.end);
+ last_end = range.end;
+ }
+ if last_end < offset+len {
+ gaps.push(Range { start: last_end, end: offset+len });
}
// Add default for all gaps
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ /// Query the map at every offset in the range and collect the results.
+ fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
+ (offset..offset+len).into_iter().map(|i| *map.iter(i, 1).next().unwrap()).collect()
+ }
+
+ #[test]
+ fn basic_insert() {
+ let mut map = RangeMap::<i32>::new();
+ // Insert
+ for x in map.iter_mut(10, 1) {
+ *x = 42;
+ }
+ // Check
+ assert_eq!(to_vec(&map, 10, 1), vec![42]);
+ }
+
+ #[test]
+ fn gaps() {
+ let mut map = RangeMap::<i32>::new();
+ for x in map.iter_mut(11, 1) {
+ *x = 42;
+ }
+ for x in map.iter_mut(15, 1) {
+ *x = 42;
+ }
+
+ // Now request a range that needs three gaps filled
+ for x in map.iter_mut(10, 10) {
+ if *x != 42 { *x = 23; }
+ }
+
+ assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23]);
+ assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]);
+ }
+}