Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add example and correct README #8

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>` 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<T>` 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<T>` . For instance, with intervals of type `Interval<u32>`:
Expand All @@ -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.
27 changes: 27 additions & 0 deletions examples/new_point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use interval_map::{Interval, IntervalMap};

trait Point<T> {
fn new_point(x: T) -> Interval<T>;
}

impl Point<u32> for Interval<u32> {
fn new_point(x: u32) -> Self {
Interval::new(x, x + 1)
}
}

fn main() {
let mut interval_map = IntervalMap::<u32, i32>::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
);
}
68 changes: 68 additions & 0 deletions examples/string_affine.rs
Original file line number Diff line number Diff line change
@@ -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<cmp::Ordering> {
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<T> {
fn new_point(x: T) -> Interval<T>;
}

impl Point<StringAffine> for Interval<StringAffine> {
fn new_point(x: StringAffine) -> Interval<StringAffine> {
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::<StringAffine, u32>::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"))));
}
Loading