diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs index f80bf2a..5ea2e6b 100644 --- a/src/range_bounds_map.rs +++ b/src/range_bounds_map.rs @@ -680,65 +680,88 @@ where /// assert_eq!(base, after_cut); /// assert_eq!(base.cut(&(60..=80)), Err(TryFromBoundsError)); /// ``` - //#[untested] - //pub fn cut(&mut self, range_bounds: &Q) -> Result<(), TryFromBoundsError> - //where - //Q: RangeBounds, - //K: TryFromBounds, - //V: Clone, - //{ - //let mut to_insert = Vec::new(); + #[tested] + pub fn cut(&mut self, range_bounds: &Q) -> Result, Bound), V)>, TryFromBoundsError> + where + Q: RangeBounds, + K: TryFromBounds, + V: Clone, + { + let mut to_insert = Vec::new(); + let mut partial_first = None; + let mut partial_last = None; - //{ - //let mut overlapping = self.overlapping(range_bounds); + { + // only the first and last range_bounds in overlapping stand a + // change of remaining after the cut so we don't need to + // collect the iterator and can just look at the first and + // last elements since range is a double ended iterator ;p + let mut overlapping = self.overlapping(range_bounds); - //let first_last = (overlapping.next(), overlapping.next_back()); + if let Some(first) = overlapping.next() { + let cut_result = cut_range_bounds(first.0, range_bounds); - //match first_last { - //(Some(first), Some(last)) => { - //match cut_range_bounds(first.0, range_bounds) { - //CutResult::Nothing => {} - //CutResult::Single(left_section) => { - //to_insert.push((left_section, first.1.clone())); - //} - //CutResult::Double(_, _) => unreachable!(), - //} - //match cut_range_bounds(last.0, range_bounds) { - //CutResult::Nothing => {} - //CutResult::Single(right_section) => { - //to_insert.push((right_section, last.1.clone())); - //} - //CutResult::Double(_, _) => unreachable!(), - //} - //(Some(first), None) => { - //match cut_range_bounds(first.0, range_bounds) { - //CutResult::Nothing => {} - //CutResult::Single(section) => { - //to_insert.push((section, first.1.clone())); - //} - //CutResult::Double(left_section, right_section) => { - //to_insert.push((left_section, first.1.clone())); - //to_insert.push((right_section, first.1.clone())); - //} - //(None, None) => {} - //(None, Some(_)) => unreachable!(), - //} + if let Some(before) = cut_result.before_cut { + to_insert.push((cloned_bounds(before), first.1.clone())); + } + if let Some(after) = cut_result.after_cut { + to_insert.push((cloned_bounds(after), first.1.clone())); + } - //// Make sure that the inserts will work before we try to do - //// them, so if one fails the map remains unchanged - //if to_insert.iter().all(|(x, _)| K::is_valid(x)) { - //let removed = self.remove_overlapping(range_bounds); - //for ((start, end), value) in to_insert.into_iter() { - //self.insert_platonic( - //K::try_from_bounds(start, end).unwrap(), - //value.clone(), - //) - //.unwrap(); - //} - //return Ok(()); - //} else { - //return Err(TryFromBoundsError); - //} + partial_first = cut_result.inside_cut.map(cloned_bounds); + } + if let Some(last) = overlapping.next_back() { + let cut_result = cut_range_bounds(last.0, range_bounds); + + if cut_result.before_cut.is_some() { + unreachable!() + } + if let Some(after) = cut_result.after_cut { + to_insert.push((cloned_bounds(after), last.1.clone())); + } + + partial_last = cut_result.inside_cut.map(cloned_bounds); + } + } + + // Make sure that the inserts will work before we try to do + // them, so if one fails the map remains unchanged + if to_insert.iter().all(|(x, _)| K::is_valid(x)) { + let mut removed = self.remove_overlapping(range_bounds); + for ((start, end), value) in to_insert.into_iter() { + self.insert_platonic( + K::try_from_bounds(start, end).unwrap(), + value, + ) + .unwrap(); + } + + let mut removed_first = + removed.next().map(|(key, value)| (expand_cloned(&key), value)); + let mut removed_last = removed + .next_back() + .map(|(key, value)| (expand_cloned(&key), value)); + + //remove the full rangebounds and replace with their partial cuts + //if they exist + if let Some(partial_first) = partial_first { + removed_first = removed_first.map(|(_, v)| (partial_first, v)); + } + if let Some(partial_last) = partial_last { + removed_last = removed_last.map(|(_, v)| (partial_last, v)); + } + + // I'm in love again with this lol + let result = removed_first + .into_iter() + .chain(removed.map(|(key, value)| (expand_cloned(&key), value))) + .chain(removed_last.into_iter()); + + return Ok(result); + } else { + return Err(TryFromBoundsError); + } + } /// Returns an iterator of `(Bound<&I>, Bound<&I>)` over all the /// maximally-sized gaps in the map that are also within the given @@ -1205,21 +1228,21 @@ where /// [(&(2..4), &false), (&(4..6), &true), (&(6..8), &false)] /// ); /// ``` - //#[trivial] - //pub fn overwrite( - //&mut self, - //range_bounds: K, - //value: V, - //) -> Result<(), TryFromBoundsError> - //where - //V: Clone, - //K: TryFromBounds, - //{ - //self.cut(&range_bounds)?; - //self.insert_platonic(range_bounds, value).unwrap(); + #[trivial] + pub fn overwrite( + &mut self, + range_bounds: K, + value: V, + ) -> Result<(), TryFromBoundsError> + where + V: Clone, + K: TryFromBounds, + { + self.cut(&range_bounds)?; + self.insert_platonic(range_bounds, value).unwrap(); - //return Ok(()); - //} + return Ok(()); + } /// Returns the first (`RangeBounds`, `Value`) pair in the map, if /// any. @@ -1400,24 +1423,10 @@ where } #[derive(Debug)] -enum CutResult { - Nothing((Bound, Bound)), - Everything((Bound, Bound)), - Single(SingleCutResult), - Double(DoubleCutResult), -} - -#[derive(Debug)] -struct SingleCutResult { - inside_cut: (Bound, Bound), - outside_cut: (Bound, Bound), -} - -#[derive(Debug)] -struct DoubleCutResult { - inside_cut: (Bound, Bound), - before_cut: (Bound, Bound), - after_cut: (Bound, Bound), +struct CutResult { + before_cut: Option<(Bound, Bound)>, + inside_cut: Option<(Bound, Bound)>, + after_cut: Option<(Bound, Bound)>, } #[untested] @@ -1437,29 +1446,39 @@ where let cut_all @ (cut_start, cut_end) = (cut_range_bounds.start_bound(), cut_range_bounds.end_bound()); - match config(base_range_bounds, cut_range_bounds) { - Config::LeftFirstNonOverlapping(_, _) => CutResult::Nothing(base_all), - Config::LeftFirstPartialOverlap(_, _) => { - CutResult::Single(SingleCutResult { - inside_cut: (cut_start, base_end), - outside_cut: (base_start, flip_bound(cut_start)), - }) - } - Config::LeftContainsRight(a, b) => CutResult::Double(DoubleCutResult { - inside_cut: cut_all, - before_cut: (base_start, flip_bound(cut_start)), - after_cut: (flip_bound(cut_end), base_end), - }), + let mut result = CutResult { + before_cut: None, + inside_cut: None, + after_cut: None, + }; - Config::RightFirstNonOverlapping(_, _) => CutResult::Nothing(base_all), - Config::RightFirstPartialOverlap(_, _) => { - CutResult::Single(SingleCutResult { - inside_cut: (base_start, cut_end), - outside_cut: (flip_bound(cut_end), base_end), - }) + match config(base_range_bounds, cut_range_bounds) { + Config::LeftFirstNonOverlapping(_, _) => { + result.before_cut = Some(base_all); + } + Config::LeftFirstPartialOverlap(_, _) => { + result.inside_cut = Some((cut_start, base_end)); + result.after_cut = Some((base_start, flip_bound(cut_start))); + } + Config::LeftContainsRight(a, b) => { + result.before_cut = Some((base_start, flip_bound(cut_start))); + result.inside_cut = Some(cut_all); + result.after_cut = Some((flip_bound(cut_end), base_end)); + } + + Config::RightFirstNonOverlapping(_, _) => { + result.after_cut = Some(base_all); + } + Config::RightFirstPartialOverlap(_, _) => { + result.before_cut = Some((flip_bound(cut_end), base_end)); + result.inside_cut = Some((base_start, cut_end)); + } + Config::RightContainsLeft(_, _) => { + result.inside_cut = Some(base_all); } - Config::RightContainsLeft(_, _) => CutResult::Everything(base_all), } + + return result; } #[trivial] @@ -1510,6 +1529,33 @@ where } } +#[trivial] +fn expand(range_bounds: &K) -> (Bound<&I>, Bound<&I>) +where + K: RangeBounds, +{ + (range_bounds.start_bound(), range_bounds.end_bound()) +} + +#[trivial] +fn expand_cloned(range_bounds: &K) -> (Bound, Bound) +where + K: RangeBounds, + I: Clone +{ + cloned_bounds((range_bounds.start_bound(), range_bounds.end_bound())) +} + +#[trivial] +fn cloned_bounds( + (start, end): (Bound<&I>, Bound<&I>), +) -> (Bound, Bound) +where + I: Clone, +{ + (start.cloned(), end.cloned()) +} + #[trivial] fn flip_bound(bound: Bound<&I>) -> Bound<&I> { match bound { diff --git a/todo.md b/todo.md index 6a96c42..775d937 100644 --- a/todo.md +++ b/todo.md @@ -6,6 +6,8 @@ - make a range_bounds configuration: NonOverlapping, A contained in B, A partial overlap B, with A before B. And use it to simplify all the logic based RangeBounds functions +- make an expand function to go RangeBounds -> (Bound, Bound) rather + than doing it manually everywhere # features @@ -15,6 +17,10 @@ just add unwraps everywhere to simplify signatures on known-"Safe" symmetric types such as Range +- make gaps() DoubleEndedIterator +- make all iterators cutsom types as is standardised in libraries for + some reason + - add coalesce if same-value otherwise overwrite) function to make finally make range_bounds_map a superset of rangemap @@ -34,7 +40,7 @@ - copy map to set again - copy readme to lib.rs docs again - take a look around idiomatic rust for a bit first -- run is_labelled again +- run is_labelled again and check they are accurate - review method parameter names for all public functions - update lines of code figures on docs - add issues to github for all the caveats