implemented split_off() and append_platonic on map

This commit is contained in:
ripytide
2022-12-13 00:18:34 +00:00
parent 3c050ac4e2
commit 9b88da2add
3 changed files with 126 additions and 2 deletions
+122 -1
View File
@@ -669,7 +669,8 @@ where
///
/// If the remaining `RangeBounds` left in the map after the cut
/// are not able be created with the [`TryFromBounds`] trait then
/// a [`TryFromBoundsError`] will be returned.
/// a [`TryFromBoundsError`] will be returned and the map will not
/// be cut.
///
/// `V` must implement `Clone` as if you try to cut out the center
/// of a `RangeBounds` in the map it will split into two different
@@ -1379,6 +1380,7 @@ where
/// Some((&(1..4), &false))
/// );
/// ```
#[trivial]
pub fn first_entry(&self) -> Option<(&K, &V)> {
self.iter().next()
}
@@ -1401,9 +1403,128 @@ where
/// range_bounds_map.last_entry(),
/// Some((&(8..100), &false))
/// );
#[trivial]
pub fn last_entry(&self) -> Option<(&K, &V)> {
self.iter().next_back()
}
/// Moves all elements from `other` into `self` by
/// [`RangeBoundsMap::insert_platonic()`] in acending order,
/// leaving `other` empty.
///
/// If any of the `RangeBounds` in `other` overlap `self` then
/// that `RangeBounds` is not inserted and the function returns.
/// This will mean all `RangeBounds` after the failed one will not
/// be inserted into `self`.
///
/// # Examples
/// ```
/// use range_bounds_map::RangeBoundsMap;
///
/// let mut base =
/// RangeBoundsMap::try_from([(1..4, false), (4..8, true)])
/// .unwrap();
///
/// let mut add =
/// RangeBoundsMap::try_from([(10..38, true), (40..42, false)])
/// .unwrap();
///
/// let expected = RangeBoundsMap::try_from([
/// (1..4, false),
/// (4..8, true),
/// (10..38, true),
/// (40..42, false),
/// ])
/// .unwrap();
///
/// assert_eq!(base.append_platonic(&mut add), Ok(()));
/// assert_eq!(base, expected);
/// assert!(add.is_empty());
/// ```
#[trivial]
pub fn append_platonic(
&mut self,
other: &mut RangeBoundsMap<I, K, V>,
) -> Result<(), OverlapError> {
for (range_bounds, value) in
other.remove_overlapping(&(Bound::Unbounded::<I>, Bound::Unbounded))
{
self.insert_platonic(range_bounds, value)?;
}
return Ok(());
}
/// Splits the collection in two at the given `start_bound()`. Returns
/// the full or partial `RangeBounds` after the split.
///
/// If the remaining `RangeBounds` left in either the base or the
/// returned map are not able be created with the
/// [`TryFromBounds`] trait then a [`TryFromBoundsError`] will be
/// returned and the base map will not be split.
///
/// `V` must implement `Clone` as if you try to split the map
/// inside a `RangeBounds` then that entries value will need to be
/// cloned into the returned `RangeBoundsMap`.
///
/// # Examples
/// ```
/// use std::ops::Bound;
///
/// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError};
///
/// let mut a = RangeBoundsMap::try_from([
/// (1..2, false),
/// (4..8, true),
/// (10..16, true),
/// ])
/// .unwrap();
///
/// // fails because that would leave an Inclusive-Inclusive
/// // `RangeBounds` in `a`
/// assert_eq!(
/// a.split_off(Bound::Excluded(6)),
/// Err(TryFromBoundsError)
/// );
///
/// let b = a.split_off(Bound::Included(6)).unwrap();
///
/// assert_eq!(
/// a.into_iter().collect::<Vec<_>>(),
/// [(1..2, false), (4..6, true)],
/// );
/// assert_eq!(
/// b.into_iter().collect::<Vec<_>>(),
/// [(6..8, true), (10..16, true)],
/// );
/// ```
#[trivial]
pub fn split_off(
&mut self,
start_bound: Bound<I>,
) -> Result<RangeBoundsMap<I, K, V>, TryFromBoundsError>
where
K: TryFromBounds<I> + Clone,
V: Clone,
{
// optimisation: this is a terrible way of being atomic
let before = self.clone();
let split_off = self.cut_same(&(start_bound, Bound::Unbounded))?;
let mut output = RangeBoundsMap::new();
for (possible_key, value) in split_off {
match possible_key {
Ok(key) => output.insert_platonic(key, value).unwrap(),
Err(TryFromBoundsError) => {
*self = before;
return Err(TryFromBoundsError);
}
}
}
return Ok(output);
}
}
impl<const N: usize, I, K, V> TryFrom<[(K, V); N]> for RangeBoundsMap<I, K, V>
+2
View File
@@ -734,6 +734,7 @@ where
///
/// assert_eq!(range_bounds_set.first(), Some(&(1..4)));
/// ```
#[trivial]
pub fn first(&self) -> Option<&K> {
self.map.first_entry().map(|(key, _)| key)
}
@@ -749,6 +750,7 @@ where
///
/// assert_eq!(range_bounds_set.last(), Some(&(8..100)));
/// ```
#[trivial]
pub fn last(&self) -> Option<&K> {
self.map.last_entry().map(|(key, _)| key)
}
+2 -1
View File
@@ -27,12 +27,13 @@
symmetric types such as Range
- add rangemap's insert function to finally make range_bounds_map a superset of rangemap
- add append() split_off() etc..
- add append() split_off(), remove_at_point(), etc
# open questions
- should we implement FromIterator? If so which insert should we use?
(At the moment we do implement it using insert_platonic())
- should append_* functions not change the base if they fail half way?
#### PUBLISH