From a5d944e2f9ad07a46eeb12d7a75f6c406d66eff9 Mon Sep 17 00:00:00 2001 From: feathercyc Date: Tue, 20 Aug 2024 12:45:28 +0000 Subject: [PATCH] chore: add example and correct README Signed-off-by: feathercyc --- README.md | 21 ++++++------ examples/new_point.rs | 27 ++++++++++++++++ examples/string_affine.rs | 68 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 examples/new_point.rs create mode 100644 examples/string_affine.rs diff --git a/README.md b/README.md index 0fdb9b5..a7f1cc6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The implementation of the interval tree in interval_map references "Introduction To safely and efficiently handle insertion and deletion operations in Rust, `interval_map` innovatively **uses arrays to simulate pointers** for managing the parent-child references in the red-black tree. This approach also ensures that interval_map has the `Send` and `Unpin` traits, allowing it to be safely transferred between threads and to maintain a fixed memory location during asynchronous operations. `interval_map` implements an `IntervalMap` struct: -- It accepts `Interval` as the key, where `T` can be any type that implements `Ord+Clone` trait. Therefore, intervals such as $[1, 2)$ and $["aaa", "bbb")$ are allowed +- It accepts `Interval` as the key, where `T` can be any type that implements `Ord` trait. Therefore, intervals such as $[1, 2)$ and $["aaa", "bbb")$ are allowed - The value can be of any type `interval_map` supports `insert`, `delete`, and `iter` fns. Traversal is performed in the order of `Interval` . For instance, with intervals of type `Interval`: @@ -22,15 +22,16 @@ Currently, `interval_map` only supports half-open intervals, i.e., $[...,...)$. The benchmark was conducted on a platform with `AMD R7 7840H + DDR5 5600MHz`. The result are as follows: 1. Only insert - | insert | 100 | 1000 | 10, 000 | 100, 000 | - | --------------- | --------- | --------- | --------- | --------- | - | Time per insert | 5.4168 µs | 80.518 µs | 2.2823 ms | 36.528 ms | + | insert | 100 | 1000 | 10, 000 | 100, 000 | + | ---------- | --------- | --------- | --------- | --------- | + | Total time | 5.4168 µs | 80.518 µs | 2.2823 ms | 36.528 ms | 2. Insert N and remove N - | insert_and_remove | 100 | 1000 | 10, 000 | 100, 000 | - | ------------------ | --------- | --------- | --------- | --------- | - | Time per operation | 10.333 µs | 223.43 µs | 4.9358 ms | 81.634 ms | + | insert_and_remove | 100 | 1000 | 10, 000 | 100, 000 | + | ----------------- | --------- | --------- | --------- | --------- | + | Total time | 10.333 µs | 223.43 µs | 4.9358 ms | 81.634 ms | ## TODO -- [] Support for $(...,...)$, $[...,...]$ and $(...,...]$ interval types. -- [] Add more tests like [etcd](https://github.com/etcd-io/etcd/blob/main/pkg/adt/interval_tree_test.go) -- [] Add Point type for Interval +- [ ] ~~Support for $(...,...)$, $[...,...]$ and $(...,...]$ interval types.~~ There's no way to support these interval type without performance loss now. +- [ ] ~~Add Point type for Interval~~ To support Point type, it should also support $[...,...]$, so it couldn't be supported now, either. But you could write code like [examples/new_point](examples/new_point.rs). +- [x] Add more tests like [etcd](https://github.com/etcd-io/etcd/blob/main/pkg/adt/interval_tree_test.go). +- [x] Refine iter mod. \ No newline at end of file diff --git a/examples/new_point.rs b/examples/new_point.rs new file mode 100644 index 0000000..e872dd6 --- /dev/null +++ b/examples/new_point.rs @@ -0,0 +1,27 @@ +use interval_map::{Interval, IntervalMap}; + +trait Point { + fn new_point(x: T) -> Interval; +} + +impl Point for Interval { + fn new_point(x: u32) -> Self { + Interval::new(x, x + 1) + } +} + +fn main() { + let mut interval_map = IntervalMap::::new(); + interval_map.insert(Interval::new(3, 7), 20); + interval_map.insert(Interval::new(2, 6), 15); + + let tmp_point = Interval::new_point(5); + assert_eq!(tmp_point, Interval::new(5, 6)); + + interval_map.insert(tmp_point.clone(), 10); + assert_eq!(interval_map.get(&tmp_point).unwrap(), &10); + assert_eq!( + interval_map.find_all_overlap(&Interval::new_point(5)).len(), + 3 + ); +} diff --git a/examples/string_affine.rs b/examples/string_affine.rs new file mode 100644 index 0000000..5595b18 --- /dev/null +++ b/examples/string_affine.rs @@ -0,0 +1,68 @@ +use std::cmp; + +use interval_map::{Interval, IntervalMap}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum StringAffine { + /// String + String(String), + /// Unbounded + Unbounded, +} + +impl StringAffine { + pub fn new_key(s: &str) -> Self { + Self::String(s.to_string()) + } + + pub fn new_unbounded() -> Self { + Self::Unbounded + } +} + +impl PartialOrd for StringAffine { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for StringAffine { + fn cmp(&self, other: &Self) -> cmp::Ordering { + match (self, other) { + (StringAffine::String(x), StringAffine::String(y)) => x.cmp(y), + (StringAffine::String(_), StringAffine::Unbounded) => cmp::Ordering::Less, + (StringAffine::Unbounded, StringAffine::String(_)) => cmp::Ordering::Greater, + (StringAffine::Unbounded, StringAffine::Unbounded) => cmp::Ordering::Equal, + } + } +} + +trait Point { + fn new_point(x: T) -> Interval; +} + +impl Point for Interval { + fn new_point(x: StringAffine) -> Interval { + match x { + StringAffine::String(mut x_string) => { + let low = x_string.clone(); + x_string.push('\0'); + Interval::new( + StringAffine::new_key(&low), + StringAffine::new_key(&x_string), + ) + } + _ => panic!("new_point only receive StringAffine::String!"), + } + } +} + +fn main() { + let mut interval_map = IntervalMap::::new(); + interval_map.insert( + Interval::new(StringAffine::new_key("8"), StringAffine::Unbounded), + 123, + ); + assert!(interval_map.overlaps(&Interval::new_point(StringAffine::new_key("9")))); + assert!(!interval_map.overlaps(&Interval::new_point(StringAffine::new_key("7")))); +}