From b21662247d810acdf1b2a431a91a8ab879fcaa06 Mon Sep 17 00:00:00 2001 From: Ed Guloien Date: Thu, 28 May 2026 16:08:15 -0400 Subject: [PATCH] added better range clearing after read --- src/main.rs | 106 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/src/main.rs b/src/main.rs index f13262b..d84dc3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,40 @@ -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, Clone, Copy)] 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, end: usize, // exclusive } +#[derive(PartialEq, Debug)] +enum RangeLocation { + LeftEnd, + RightEnd, + Middle, + No +} + impl Range { - pub fn contains(&self, index: usize) -> bool { - index >= self.start && index < self.end + pub fn new(start: usize, end: usize) -> Self { + 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 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 - let new_range = Range {start: self.bytes.len(), end: self.bytes.len() + input.len()}; 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.bytes.extend_from_slice(input); } // todo: better way to do the return type? @@ -36,16 +63,35 @@ impl Blob { let slice = &mut self.bytes[start..start+len]; slice.swap_with_slice(output); - // update the valid array - let clear_range = Range{ start: start, end: start + len }; - for range in self.valid_ranges.iter_mut() { - if range.contains(clear_range.start) { - range.end = clear_range.start; - } - if range.contains(clear_range.end) { - range.start = clear_range.end; + // we copy existing entries into a new list to avoid iterator invalidation + // of inserting while iterating + // todo: might be a better way + let clear_range = Range{ start, end: start + len }; + let mut new_ranges = Vec::new(); + let mut i = 0; + while i < self.valid_ranges.len() { + let mut extra_range : Option = None; + let mut range = self.valid_ranges[i]; + if range.where_in_range(clear_range.start) == RangeLocation::LeftEnd { + 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}; assert_eq!(range, range2); // similar - // basic contains - assert!(range.contains(0)); - assert!(range.contains(1)); - assert!(range.contains(2)); - assert!(!range.contains(3)); - assert!(!range.contains(4)); + assert_eq!(range.where_in_range(0), RangeLocation::LeftEnd); + assert_eq!(range.where_in_range(1), RangeLocation::Middle); + assert_eq!(range.where_in_range(2), RangeLocation::RightEnd); + assert_eq!(range.where_in_range(3), RangeLocation::No); } #[test] fn test_blob() { let mut b = Blob::new(); b.append(&[b'a', b'b', b'c']); + assert_eq!(b.valid_ranges, &[Range{start:0, end:3}]); let mut read = vec![0; 1]; - b.read(0,1, &mut read); - // todo make some asserts - //assert!(&read, Vec::new([b'a'])); - println!("blob (0,1): {}", str::from_utf8(&read).unwrap()); + b.read(0,1, &mut read); // left read + assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]); let mut read = vec![0; 1]; - b.read(0,1, &mut read); - println!("blob (0,1) again: {}", str::from_utf8(&read).unwrap()); + b.read(0,1, &mut read); // dupe read // todo: should error or fail + assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]); let mut read = vec![0; 2]; - b.read(1,2, &mut read); - println!("blob (1,2) again: {}", str::from_utf8(&read).unwrap()); + b.read(1,2, &mut read); // right read + 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); } }