added better range clearing after read
This commit is contained in:
+77
-27
@@ -1,13 +1,40 @@
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
struct Range {
|
struct Range {
|
||||||
|
// todo: consider just using a map instead
|
||||||
|
// todo: also consider there might be an off the shelf solution that does ranges
|
||||||
start: usize,
|
start: usize,
|
||||||
end: usize, // exclusive
|
end: usize, // exclusive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
enum RangeLocation {
|
||||||
|
LeftEnd,
|
||||||
|
RightEnd,
|
||||||
|
Middle,
|
||||||
|
No
|
||||||
|
}
|
||||||
|
|
||||||
impl Range {
|
impl Range {
|
||||||
pub fn contains(&self, index: usize) -> bool {
|
pub fn new(start: usize, end: usize) -> Self {
|
||||||
index >= self.start && index < self.end
|
Self { start, end }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn where_in_range(&self, index: usize) -> RangeLocation {
|
||||||
|
if index == self.start {
|
||||||
|
return RangeLocation::LeftEnd;
|
||||||
|
}
|
||||||
|
if index >= self.end {
|
||||||
|
return RangeLocation::No
|
||||||
|
}
|
||||||
|
if index == self.end - 1 {
|
||||||
|
return RangeLocation::RightEnd;
|
||||||
|
}
|
||||||
|
RangeLocation::Middle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.start >= self.end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,14 +47,14 @@ impl Blob {
|
|||||||
pub fn new() -> Self { Self {bytes: Vec::new(), valid_ranges: Vec::new()} }
|
pub fn new() -> Self { Self {bytes: Vec::new(), valid_ranges: Vec::new()} }
|
||||||
|
|
||||||
pub fn append(&mut self, input: &[u8]) {
|
pub fn append(&mut self, input: &[u8]) {
|
||||||
self.bytes.extend_from_slice(input);
|
let new_range = Range {start: self.bytes.len(), end: self.bytes.len() + input.len()};
|
||||||
|
|
||||||
// we are appending so only have to check the last range
|
// we are appending so only have to check the last range
|
||||||
let new_range = Range {start: self.bytes.len(), end: self.bytes.len() + input.len()};
|
|
||||||
match self.valid_ranges.last_mut() {
|
match self.valid_ranges.last_mut() {
|
||||||
Some(range) if range.contains(new_range.start) => range.end = new_range.end,
|
Some(range) if range.where_in_range(new_range.start) != RangeLocation::No => range.end = new_range.end,
|
||||||
_ => self.valid_ranges.push(new_range),
|
_ => self.valid_ranges.push(new_range),
|
||||||
}
|
}
|
||||||
|
self.bytes.extend_from_slice(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: better way to do the return type?
|
// todo: better way to do the return type?
|
||||||
@@ -36,16 +63,35 @@ impl Blob {
|
|||||||
let slice = &mut self.bytes[start..start+len];
|
let slice = &mut self.bytes[start..start+len];
|
||||||
slice.swap_with_slice(output);
|
slice.swap_with_slice(output);
|
||||||
|
|
||||||
// update the valid array
|
// we copy existing entries into a new list to avoid iterator invalidation
|
||||||
let clear_range = Range{ start: start, end: start + len };
|
// of inserting while iterating
|
||||||
for range in self.valid_ranges.iter_mut() {
|
// todo: might be a better way
|
||||||
if range.contains(clear_range.start) {
|
let clear_range = Range{ start, end: start + len };
|
||||||
range.end = clear_range.start;
|
let mut new_ranges = Vec::new();
|
||||||
}
|
let mut i = 0;
|
||||||
if range.contains(clear_range.end) {
|
while i < self.valid_ranges.len() {
|
||||||
|
let mut extra_range : Option<Range> = None;
|
||||||
|
let mut range = self.valid_ranges[i];
|
||||||
|
if range.where_in_range(clear_range.start) == RangeLocation::LeftEnd {
|
||||||
range.start = clear_range.end;
|
range.start = clear_range.end;
|
||||||
|
} else if range.where_in_range(clear_range.end-1) == RangeLocation::RightEnd {
|
||||||
|
range.end = clear_range.end
|
||||||
|
} else if range.where_in_range(clear_range.start) == RangeLocation::Middle {
|
||||||
|
let end = range.end;
|
||||||
|
range.end = clear_range.start;
|
||||||
|
extra_range = Some(Range::new(clear_range.end, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !range.is_empty() {
|
||||||
|
new_ranges.push(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(er) = extra_range && !er.is_empty() {
|
||||||
|
new_ranges.push(er);
|
||||||
|
}
|
||||||
|
i+=1;
|
||||||
|
}
|
||||||
|
self.valid_ranges = new_ranges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,31 +111,35 @@ mod tests {
|
|||||||
let range2 = Range{start:0, end:3};
|
let range2 = Range{start:0, end:3};
|
||||||
assert_eq!(range, range2); // similar
|
assert_eq!(range, range2); // similar
|
||||||
|
|
||||||
// basic contains
|
assert_eq!(range.where_in_range(0), RangeLocation::LeftEnd);
|
||||||
assert!(range.contains(0));
|
assert_eq!(range.where_in_range(1), RangeLocation::Middle);
|
||||||
assert!(range.contains(1));
|
assert_eq!(range.where_in_range(2), RangeLocation::RightEnd);
|
||||||
assert!(range.contains(2));
|
assert_eq!(range.where_in_range(3), RangeLocation::No);
|
||||||
assert!(!range.contains(3));
|
|
||||||
assert!(!range.contains(4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blob() {
|
fn test_blob() {
|
||||||
let mut b = Blob::new();
|
let mut b = Blob::new();
|
||||||
b.append(&[b'a', b'b', b'c']);
|
b.append(&[b'a', b'b', b'c']);
|
||||||
|
assert_eq!(b.valid_ranges, &[Range{start:0, end:3}]);
|
||||||
|
|
||||||
let mut read = vec![0; 1];
|
let mut read = vec![0; 1];
|
||||||
b.read(0,1, &mut read);
|
b.read(0,1, &mut read); // left read
|
||||||
// todo make some asserts
|
assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]);
|
||||||
//assert!(&read, Vec<u8>::new([b'a']));
|
|
||||||
println!("blob (0,1): {}", str::from_utf8(&read).unwrap());
|
|
||||||
|
|
||||||
let mut read = vec![0; 1];
|
let mut read = vec![0; 1];
|
||||||
b.read(0,1, &mut read);
|
b.read(0,1, &mut read); // dupe read // todo: should error or fail
|
||||||
println!("blob (0,1) again: {}", str::from_utf8(&read).unwrap());
|
assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]);
|
||||||
|
|
||||||
let mut read = vec![0; 2];
|
let mut read = vec![0; 2];
|
||||||
b.read(1,2, &mut read);
|
b.read(1,2, &mut read); // right read
|
||||||
println!("blob (1,2) again: {}", str::from_utf8(&read).unwrap());
|
assert_eq!(b.valid_ranges, &[]);
|
||||||
|
|
||||||
|
b.append(&[b'a', b'b', b'c']);
|
||||||
|
assert_eq!(b.valid_ranges, &[Range{start:3, end:6}]);
|
||||||
|
let mut read = vec![0; 1];
|
||||||
|
b.read(4,1, &mut read); // middle read
|
||||||
|
assert_eq!(b.valid_ranges, &[Range::new(3,4), Range::new(5,6)]);
|
||||||
|
println!("blob: {:?}", b.bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user