]> git.lizzy.rs Git - rust.git/commitdiff
some tests for RangeMap
authorRalf Jung <post@ralfj.de>
Mon, 7 Aug 2017 22:39:27 +0000 (15:39 -0700)
committerRalf Jung <post@ralfj.de>
Wed, 9 Aug 2017 22:49:47 +0000 (15:49 -0700)
.travis.yml
src/librustc_mir/Cargo.toml
src/librustc_mir/interpret/range_map.rs

index 78de5b657edcfffce8d4eb05d5048d66d0dd34de..ef15fa98d3fc83f4ed6ea9795e744a865d9dea62 100644 (file)
@@ -16,7 +16,7 @@ script:
 - |
   # Test plain miri
   cargo build --release --features "cargo_miri" &&
-  cargo test --release &&
+  cargo test --release --all &&
   cargo install --features "cargo_miri"
 - |
   # Test cargo miri
index 1a64bb8c7c7973c69706500c711e330a6e3b52cb..4189f240c582415ab1f512cce0d0689eb4ead000 100644 (file)
@@ -8,7 +8,6 @@ version = "0.1.0"
 workspace = "../.."
 
 [lib]
-test = false
 path = "lib.rs"
 
 [dependencies]
index 7c8debc270d0c1b2e1be7bb61b1f5e76481cec8f..e4db9b0e0fc45bfd710dff018d9674e2cabbd9fb 100644 (file)
@@ -1,4 +1,9 @@
-//! 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;
 
@@ -21,6 +26,7 @@ struct Range {
 
 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
@@ -36,6 +42,7 @@ fn range(offset: u64, len: u64) -> ops::Range<Range> {
         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
@@ -48,6 +55,7 @@ pub fn new() -> RangeMap<T> {
     }
 
     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) {
@@ -63,7 +71,7 @@ pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator<Item=&'a T> +
     }
 
     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,
         };
@@ -88,6 +96,7 @@ pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator<Item=&'a mut T> + 'a {
     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);
@@ -112,14 +121,15 @@ pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator<Item=&
     {
         // 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
@@ -147,3 +157,43 @@ pub fn retain<F>(&mut self, mut f: F)
         }
     }
 }
+
+#[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]);
+    }
+}