btree-range-map-0.7.2/.cargo_vcs_info.json0000644000000001360000000000100140100ustar { "git": { "sha1": "ad2af35cd1fe34a3bee5a95a0db1537846368c23" }, "path_in_vcs": "" }btree-range-map-0.7.2/.github/FUNDING.yml000064400000000000000000000000251046102023000157520ustar 00000000000000patreon: thaudebourg btree-range-map-0.7.2/.github/workflows/ci.yml000064400000000000000000000026141046102023000173160ustar 00000000000000name: CI on: [push, pull_request] env: CARGO_TERM_COLORS: always jobs: test: name: Test Suite runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: nightly profile: minimal override: true - name: Build run: cargo build --all-features --verbose - name: Run tests run: cargo test --all-features --verbose rustfmt: name: rustfmt runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: nightly profile: minimal override: true components: rustfmt - name: Check formatting uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: name: clippy runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: nightly profile: minimal override: true components: clippy - name: Clippy Check uses: actions-rs/cargo@v1 with: command: clippy args: --all-features -- -D warningsbtree-range-map-0.7.2/.gitignore000064400000000000000000000000221046102023000145620ustar 00000000000000Cargo.lock target btree-range-map-0.7.2/.rustfmt.toml000064400000000000000000000000201046102023000152470ustar 00000000000000hard_tabs = truebtree-range-map-0.7.2/.vscode/launch.json000064400000000000000000000023521046102023000163100ustar 00000000000000{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "lldb", "request": "launch", "name": "Debug unit tests in library 'btree-range-map'", "cargo": { "args": [ "test", "--no-run", "--lib", "--package=btree-range-map" ], "filter": { "name": "btree-range-map", "kind": "lib" } }, "args": [], "cwd": "${workspaceFolder}" }, { "type": "lldb", "request": "launch", "name": "Debug integration test 'insert'", "cargo": { "args": [ "test", "--no-run", "--test=insert", "--package=btree-range-map" ], "filter": { "name": "insert", "kind": "test" } }, "args": [], "cwd": "${workspaceFolder}" }, { "type": "lldb", "request": "launch", "name": "Debug integration test 'remove'", "cargo": { "args": [ "test", "--no-run", "--test=remove", "--package=btree-range-map" ], "filter": { "name": "remove", "kind": "test" } }, "args": [], "cwd": "${workspaceFolder}" } ] }btree-range-map-0.7.2/.vscode/settings.json000064400000000000000000000001061046102023000166710ustar 00000000000000{ "lldb.showDisassembly": "auto", "lldb.dereferencePointers": true }btree-range-map-0.7.2/Cargo.toml0000644000000022570000000000100120140ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "btree-range-map" version = "0.7.2" authors = ["Timothée Haudebourg "] description = "B-tree range map implementation" documentation = "https://docs.rs/btree-range-map" readme = "README.md" keywords = [ "btree", "range", "map", "set", ] categories = ["data-structures"] license = "MIT/Apache-2.0" repository = "https://github.com/timothee-haudebourg/btree-range-map" [dependencies.btree-slab] version = "0.6" [dependencies.cc-traits] version = "2.0.0" [dependencies.ordered-float] version = "3.0.0" optional = true [dependencies.range-traits] version = "0.3.0" [dependencies.serde] version = "1.0" optional = true [dependencies.slab] version = "0.4.5" btree-range-map-0.7.2/Cargo.toml.orig000064400000000000000000000011471046102023000154720ustar 00000000000000[package] name = "btree-range-map" version = "0.7.2" authors = ["Timothée Haudebourg "] edition = "2021" categories = ["data-structures"] keywords = ["btree", "range", "map", "set"] description = "B-tree range map implementation" repository = "https://github.com/timothee-haudebourg/btree-range-map" documentation = "https://docs.rs/btree-range-map" license = "MIT/Apache-2.0" readme = "README.md" [dependencies] cc-traits = "2.0.0" btree-slab = "0.6" slab = "0.4.5" range-traits = "0.3.0" ordered-float = { version = "3.0.0", optional = true } serde = { version = "1.0", optional = true }btree-range-map-0.7.2/README.md000064400000000000000000000065141046102023000140650ustar 00000000000000# B-Tree range map [![CI](https://github.com/timothee-haudebourg/btree-range-map/workflows/CI/badge.svg)](https://github.com/timothee-haudebourg/btree-range-map/actions) [![Crate informations](https://img.shields.io/crates/v/btree-range-map.svg?style=flat-square)](https://crates.io/crates/btree-range-map) [![License](https://img.shields.io/crates/l/btree-range-map.svg?style=flat-square)](https://github.com/timothee-haudebourg/btree-range-map#license) [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square)](https://docs.rs/btree-range-map) A *range map* is a map where keys are aggregated into ranges of keys for efficient storage. Every time you need to store a large number numeric-keyed items in a map or set, a range map (or range set) should be used. This library provides a range map implementation based on [`btree-slab`](https://crates.io/crates/btree-slab)'s B-tree. It defines three basic types `RangeSet`, `RangeMap` and `RangeMultiMap`. ### Usage The `RangeSet` and `RangeMap` behave similarly to the standard `BTreeSet` and `BTreeMap` types. However in addition to `PartialOrd`, the key type must also implement the `Measure` trait defining how keys are merged into ranges. This trait is implemented by default for `char`, integer types and float types. ```rust use btree_range_map::RangeMap; let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..=05, true); range_map.insert(4, false); assert_eq!(range_map.range_count(), 3); assert_eq!(range_map.get(03), Some(&true)); assert_eq!(range_map.get(04), Some(&false)); assert_eq!(range_map.get(05), Some(&true)); ``` This library supports included and excluded bounds: ```rust range_map.insert(..1, true); range_map.insert(..=1, true); range_map.insert(2, true); range_map.insert(3..5, true); range_map.insert(5..=7, true); range_map.insert(7.., true); assert_eq!(range_map.range_count(), 1); ``` It also supports non standard ranges with excluded start bounds: ```rust use btree_range_map::{ RangeFromExcluded, RangeFromExcludedTo, RangeFromExcludedToIncluded }; // same as `4..` range_map.insert(RangeFromExcluded::new(3), true); // same as `3` range_map.insert(RangeFromExcludedTo::new(2, 4), true); // same as `1..=2` range_map.insert(RangeFromExcludedToIncluded::new(0, 2), true); assert_eq!(range_map.range_count(), 1); ``` #### Floats Floating point numbers `f32` and `f64` are handled as one might expect. ```rust use btree_range_map::{RangeMap, RangeFromExcluded}; let mut range_map: RangeMap = RangeMap::new(); // sets all `f32` below zero to `false`. range_map.insert(..0.0, false); // sets all `f32` above zero to `true`. range_map.insert(RangeFromExcluded::new(0.0), true); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0.0), None); // only `0.0` is unmapped. ``` ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. btree-range-map-0.7.2/README.tpl000064400000000000000000000020251046102023000142550ustar 00000000000000# B-Tree range map [![CI](https://github.com/timothee-haudebourg/{{crate}}/workflows/CI/badge.svg)](https://github.com/timothee-haudebourg/{{crate}}/actions) [![Crate informations](https://img.shields.io/crates/v/{{crate}}.svg?style=flat-square)](https://crates.io/crates/{{crate}}) [![License](https://img.shields.io/crates/l/{{crate}}.svg?style=flat-square)](https://github.com/timothee-haudebourg/{{crate}}#license) [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square)](https://docs.rs/{{crate}}) {{readme}} ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. btree-range-map-0.7.2/src/generic/map.rs000064400000000000000000000763171046102023000161440ustar 00000000000000use super::Node; use crate::{ range::{Difference, ProductArg}, AnyRange, AsRange, IntoRange, RangeOrdering, RangePartialOrd, }; use btree_slab::generic::{ map::{BTreeExt, BTreeExtMut, BTreeMap}, node::{Address, Item, Offset}, }; use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; use range_traits::{Bounded, Measure, PartialEnum}; use std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, hash::{Hash, Hasher}, }; /// Range map. #[derive(Clone)] pub struct RangeMap { btree: BTreeMap, V, C>, } impl RangeMap { /// Create a new empty map. pub fn new() -> RangeMap where C: Default, { RangeMap { btree: BTreeMap::new(), } } } impl Default for RangeMap { fn default() -> Self { Self::new() } } impl, V>>> RangeMap where C: SimpleCollectionRef, { pub fn len(&self) -> K::Len where K: Measure + PartialEnum + Bounded, { let mut len = K::Len::default(); for (range, _) in self { len = len + range.len() } len } pub fn bounded_len(&self) -> Option where K: Measure + PartialEnum, { let mut len = K::Len::default(); for (range, _) in self { len = len + range.bounded_len()? } Some(len) } pub fn is_empty(&self) -> bool where K: Measure + PartialEnum, { self.bounded_len() == Some(K::Len::default()) } pub fn range_count(&self) -> usize { self.btree.len() } fn address_of(&self, key: &T, connected: bool) -> Result where K: PartialEnum + Measure, T: RangePartialOrd, { if connected { if let Ok(addr) = self.address_of(key, false) { return Ok(addr); } } match self.btree.root_id() { Some(id) => self.address_in(id, key, connected), None => Err(Address::nowhere()), } } fn address_in(&self, mut id: usize, key: &T, connected: bool) -> Result where K: PartialEnum + Measure, T: RangePartialOrd, { loop { match self.offset_in(id, key, connected) { Ok(offset) => return Ok(Address::new(id, offset)), Err((offset, None)) => return Err(Address::new(id, offset.into())), Err((_, Some(child_id))) => { id = child_id; } } } } fn offset_in( &self, id: usize, key: &T, connected: bool, ) -> Result)> where K: PartialEnum + Measure, T: RangePartialOrd, { match self.btree.node(id) { Node::Internal(node) => { let branches = node.branches(); match binary_search(branches, key, connected) { Some(i) => { let b = &branches[i]; if key .range_partial_cmp(b.item.key()) .unwrap_or(RangeOrdering::After(false)) .matches(connected) { Ok(i.into()) } else { Err((i + 1, Some(b.child))) } } None => Err((0, Some(node.first_child_id()))), } } Node::Leaf(leaf) => { let items = leaf.items(); match binary_search(items, key, connected) { Some(i) => { let item = &items[i]; let ord = key .range_partial_cmp(item.key()) .unwrap_or(RangeOrdering::After(false)); if ord.matches(connected) { Ok(i.into()) } else { Err((i + 1, None)) } } None => Err((0, None)), } } } } pub fn intersects>(&self, key: R) -> bool where K: PartialEnum + Measure, V: PartialEq, { // let key = AnyRange::from(key); if key.is_empty() { false } else { self.address_of(&key, false).is_ok() } } pub fn contains_key(&self, key: K) -> bool where K: PartialEnum + RangePartialOrd + Measure, { self.address_of(&key, false).is_ok() } pub fn get(&self, key: K) -> Option<&V> where K: PartialEnum + RangePartialOrd + Measure, { match self.address_of(&key, false) { Ok(addr) => Some(self.btree.item(addr).unwrap().value()), Err(_) => None, } } pub fn iter(&self) -> Iter { self.btree.iter() } /// Returns an iterator over the gaps (unbounded keys) of the map. pub fn gaps(&self) -> Gaps { Gaps { inner: self.btree.iter(), prev: None, done: false, } } } impl, V>>> fmt::Debug for RangeMap where C: SimpleCollectionRef, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; for (range, value) in self { write!(f, "{:?}=>{:?}", range, value)? } write!(f, "}}") } } impl, V>>, D: Slab, W>>> PartialEq> for RangeMap where L: Measure + PartialOrd + PartialEnum, K: PartialEnum, W: PartialEq, C: SimpleCollectionRef, D: SimpleCollectionRef, { fn eq(&self, other: &RangeMap) -> bool { self.btree == other.btree } } impl, V>>> Eq for RangeMap where K: Measure + PartialEnum + Ord, V: Eq, C: SimpleCollectionRef, { } impl, V>>, D: Slab, W>>> PartialOrd> for RangeMap where L: Measure + PartialOrd + PartialEnum, K: PartialEnum, W: PartialOrd, C: SimpleCollectionRef, D: SimpleCollectionRef, { fn partial_cmp(&self, other: &RangeMap) -> Option { self.btree.partial_cmp(&other.btree) } } impl, V>>> Ord for RangeMap where K: Measure + PartialEnum + Ord, V: Ord, C: SimpleCollectionRef, { fn cmp(&self, other: &Self) -> Ordering { self.btree.cmp(&other.btree) } } impl, V>>> Hash for RangeMap where K: Hash + PartialEnum, V: Hash, C: SimpleCollectionRef, { fn hash(&self, h: &mut H) { for range in self { range.hash(h) } } } impl<'a, K, V, C: Slab, V>>> IntoIterator for &'a RangeMap where C: SimpleCollectionRef, { type Item = (&'a AnyRange, &'a V); type IntoIter = Iter<'a, K, V, C>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl, V>>> RangeMap where C: SimpleCollectionRef, C: SimpleCollectionMut, { fn merge_forward(&mut self, addr: Address, next_addr: Option
) where K: Clone + PartialEnum + Measure, V: PartialEq, { if let Some(next_addr) = next_addr { let item = self.btree.item(addr).unwrap(); let next_item = self.btree.item(next_addr).unwrap(); if item.key().connected_to(next_item.key()) && item.value() == next_item.value() { let (removed_item, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); let item = self.btree.item_mut(new_addr).unwrap(); item.key_mut().add(removed_item.key()); } } } fn set_item_key( &mut self, addr: Address, next_addr: Option
, new_key: AnyRange, ) -> (Address, Option
) where K: Clone + PartialEnum + Measure, V: PartialEq, { if let Some(next_addr) = next_addr { let next_item = self.btree.item(next_addr).unwrap(); if new_key.connected_to(next_item.key()) && next_item.value() == self.btree.item(addr).unwrap().value() { // Merge with the next item. let (_, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); let item = self.btree.item_mut(new_addr).unwrap(); item.key_mut().add(&new_key); return (new_addr, self.btree.next_item_address(new_addr)); } } let item = self.btree.item_mut(addr).unwrap(); *item.key_mut() = new_key; (addr, next_addr) } fn set_item( &mut self, addr: Address, next_addr: Option
, new_key: AnyRange, new_value: V, ) -> (Address, Option
, V) where K: Clone + PartialEnum + Measure, V: PartialEq, { if let Some(next_addr) = next_addr { let next_item = self.btree.item(next_addr).unwrap(); if new_key.connected_to(next_item.key()) && *next_item.value() == new_value { // Merge with the next item. let (removed_item, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); let item = self.btree.item_mut(new_addr).unwrap(); item.key_mut().add(&new_key); return ( new_addr, self.btree.next_item_address(new_addr), removed_item.into_value(), ); } } let item = self.btree.item_mut(addr).unwrap(); let removed_value = item.set_value(new_value); *item.key_mut() = new_key; (addr, next_addr, removed_value) } fn insert_item( &mut self, addr: Address, key: AnyRange, value: V, ) -> (Address, Option
) where K: Clone + PartialEnum + Measure, V: PartialEq, { let next_item = self.btree.item(addr).unwrap(); if key.connected_to(next_item.key()) && *next_item.value() == value { // Merge with the next item. let item = self.btree.item_mut(addr).unwrap(); item.key_mut().add(&key); return (addr, self.btree.next_item_address(addr)); } let new_addr = self.btree.insert_at(addr, Item::new(key, value)); (new_addr, self.btree.next_item_address(new_addr)) } fn remove_item(&mut self, addr: Address) -> (Address, Option
) { let (_, non_normalized_addr) = self.btree.remove_at(addr).unwrap(); let new_addr = self .btree .previous_item_address(non_normalized_addr) .unwrap(); (new_addr, self.btree.normalize(non_normalized_addr)) } pub fn update, F>(&mut self, key: R, f: F) where K: Clone + PartialEnum + Measure, F: Fn(Option<&V>) -> Option, V: PartialEq + Clone, { let mut key = AnyRange::from(key); if key.is_empty() { return; } match self.address_of(&key, true) { Ok(mut addr) => { let mut next_addr = self.btree.next_item_address(addr); loop { let (prev_addr, prev_next_addr) = { let product = key.product(self.btree.item(addr).unwrap().key()).cloned(); let mut removed_item_value = None; let (addr, next_addr) = match product.after { Some(ProductArg::Subject(key_after)) => { match f(None) { Some(value) => { let (new_addr, new_next_addr, removed_value) = self.set_item(addr, next_addr, key_after, value); removed_item_value = Some(removed_value); (new_addr, new_next_addr) } None => (addr, next_addr), // we wait the last minute to remove the item. } } Some(ProductArg::Object(item_after)) => { let item = self.btree.item_mut(addr).unwrap(); item.set_key(item_after); removed_item_value = Some(item.value().clone()); (addr, next_addr) } None => (addr, next_addr), // we wait the last minute to remove the item. }; let (addr, next_addr) = match product.intersection { Some(intersection) => { let new_value = match removed_item_value.as_ref() { Some(value) => f(Some(value)), None => f(Some(self.btree.item(addr).unwrap().value())), }; match new_value { Some(new_value) => { if removed_item_value.is_some() { let (new_addr, new_next_addr) = self.insert_item(addr, intersection, new_value); (new_addr, new_next_addr) } else { let (new_addr, new_next_addr, removed_value) = self .set_item(addr, next_addr, intersection, new_value); removed_item_value = Some(removed_value); (new_addr, new_next_addr) } } None => (addr, next_addr), // we wait the last minute to remove the item. } } None => (addr, next_addr), // we wait the last minute to remove the item. }; match product.before { Some(ProductArg::Subject(key_before)) => { match self.btree.previous_item_address(addr) { Some(prev_addr) if self .btree .item(prev_addr) .unwrap() .key() .connected_to(&key_before) => { let (prev_addr, addr) = if removed_item_value.is_none() { self.remove_item(addr) } else { (prev_addr, Some(addr)) }; // Let's go for another turn! // One item back this time. key = key_before; (prev_addr, addr) } _ => { // there is no previous connected item, we must insert here! match f(None) { Some(value) => { if removed_item_value.is_some() { // we cannot reuse the item // insert self.insert_item(addr, key_before, value); } else { // we can reuse the item // reuse self.set_item( addr, next_addr, key_before, value, ); } } None => { if removed_item_value.is_none() { self.btree.remove_at(addr); // finally remove the item. } } } break; } } } Some(ProductArg::Object(item_before)) => { match removed_item_value { Some(value) => { self.insert_item(addr, item_before, value); } None => { self.set_item_key(addr, next_addr, item_before); } } break; } None => { match self.btree.previous_item_address(addr) { Some(prev_addr) => { let (prev_addr, addr) = if removed_item_value.is_none() { self.remove_item(addr) } else { (prev_addr, Some(addr)) }; self.merge_forward(prev_addr, addr) } _ => { if removed_item_value.is_none() { self.btree.remove_at(addr).unwrap(); } } } break; } } }; addr = prev_addr; next_addr = prev_next_addr; } } Err(addr) => { // case (G) if let Some(new_value) = f(None) { self.btree.insert_at(addr, Item::new(key, new_value)); } } } for (range, _) in self.iter() { debug_assert!(!range.is_empty()); } } pub fn insert_disconnected>( &mut self, key: R, value: V, ) -> Result<(), (AnyRange, V)> where K: PartialEnum + Measure, { let key = key.into_range(); match self.address_of(&key, true) { Ok(_) => Err((key, value)), Err(addr) => { self.btree.insert_at(addr, Item::new(key, value)); Ok(()) } } } /// Insert a new key-value binding. pub fn insert>(&mut self, key: R, value: V) where K: Clone + PartialEnum + Measure, V: PartialEq + Clone, { let mut key = key.into_range(); if key.is_empty() { return; } match self.address_of(&key, true) { Ok(mut addr) => { // let mut value = Some(value); let mut next_addr = self.btree.next_item_address(addr); loop { let (prev_addr, prev_next_addr) = { let product = key.product(self.btree.item(addr).unwrap().key()).cloned(); let mut removed_item_value = None; if let Some(ProductArg::Object(item_after)) = product.after { let item = self.btree.item_mut(addr).unwrap(); item.set_key(item_after); removed_item_value = Some(item.value().clone()); } match product.before { Some(ProductArg::Object(item_before)) => { match removed_item_value { Some(old_value) => { if old_value == value { key.add(&item_before); self.insert_item(addr, key, value); } else { let (addr, _) = self.insert_item(addr, key, value); self.insert_item(addr, item_before, old_value); } } None => { if *self.btree.item(addr).unwrap().value() == value { key.add(&item_before); self.set_item_key(addr, next_addr, key); } else { let (_, _, old_value) = self.set_item(addr, next_addr, key, value); self.insert_item(addr, item_before, old_value); } } } break; } Some(ProductArg::Subject(_)) | None => { match self.btree.previous_item_address(addr) { Some(prev_addr) if self .btree .item(prev_addr) .unwrap() .key() .connected_to(&key) => { // We can move one to the previous item. let (prev_addr, addr) = if removed_item_value.is_none() { self.remove_item(addr) } else { (prev_addr, Some(addr)) }; (prev_addr, addr) } _ => { // There is no previous item, we must get it done now. if removed_item_value.is_some() { self.insert_item(addr, key, value); } else { self.set_item(addr, next_addr, key, value); } break; } } } } }; addr = prev_addr; next_addr = prev_next_addr; } } Err(addr) => { // case (G) self.btree.insert_at(addr, Item::new(key, value)); } } } /// Remove a key. pub fn remove>(&mut self, key: R) where K: Clone + PartialEnum + Measure, V: Clone, { let key = AnyRange::from(key); if let Ok(mut addr) = self.address_of(&key, false) { loop { if self .btree .item(addr) .map(|item| item.key().intersects(&key)) .unwrap_or(false) { match self.btree.item(addr).unwrap().key().without(&key) { Difference::Split(left, right) => { let left = left.cloned(); let right = right.cloned(); let right_value = { let item = self.btree.item_mut(addr).unwrap(); *item.key_mut() = right; item.value().clone() }; self.btree.insert_at(addr, Item::new(left, right_value)); break; // no need to go further, the removed range was totaly included in this one. } Difference::Before(left, _) => { let left = left.cloned(); let item = self.btree.item_mut(addr).unwrap(); *item.key_mut() = left; break; // no need to go further, the removed range does not intersect anything below this range. } Difference::After(right, _) => { let right = right.cloned(); let item = self.btree.item_mut(addr).unwrap(); *item.key_mut() = right; } Difference::Empty => { let (_, next_addr) = self.btree.remove_at(addr).unwrap(); addr = next_addr } } match self.btree.previous_item_address(addr) { Some(prev_addr) => addr = prev_addr, None => break, } } else { break; } } } } } impl, V>>> IntoIterator for RangeMap where C: SimpleCollectionRef, C: SimpleCollectionMut, { type Item = (AnyRange, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { self.btree.into_iter() } } pub type Iter<'a, K, V, C> = btree_slab::generic::map::Iter<'a, AnyRange, V, C>; pub type IntoIter = btree_slab::generic::map::IntoIter, V, C>; /// Iterator over the gaps (unbound keys) of a `RangeMap`. pub struct Gaps<'a, K, V, C> { inner: Iter<'a, K, V, C>, prev: Option>, done: bool, } impl<'a, K: Measure + PartialEnum, V, C: Slab, V>>> Iterator for Gaps<'a, K, V, C> where C: SimpleCollectionRef, { type Item = AnyRange<&'a K>; fn next(&mut self) -> Option { use std::ops::{Bound, RangeBounds}; if self.done { None } else { loop { match self.inner.next() { Some((range, _)) => { let start = match self.prev.take() { Some(bound) => bound, None => Bound::Unbounded, }; self.prev = match range.end_bound() { Bound::Unbounded => { self.done = true; None } Bound::Included(t) => Some(Bound::Excluded(t)), Bound::Excluded(t) => Some(Bound::Included(t)), }; let end = match range.start_bound() { Bound::Unbounded => continue, Bound::Included(t) => Bound::Excluded(t), Bound::Excluded(t) => Bound::Included(t), }; let gap = AnyRange { start, end }; if !gap.ref_is_empty() { break Some(gap); } } None => { self.done = true; let start = self.prev.take(); match start { Some(bound) => { let gap = AnyRange { start: bound, end: Bound::Unbounded, }; break if gap.ref_is_empty() { None } else { Some(gap) }; } None => { break Some(AnyRange { start: Bound::Unbounded, end: Bound::Unbounded, }) } } } } } } } } /// Search for the index of the gratest item less/below or equal/including the given element. /// /// If `connected` is `true`, then it will search for the gratest item less/below or equal/including **or connected to** the given element. pub fn binary_search, V>>>( items: &[I], element: &U, connected: bool, ) -> Option where U: RangePartialOrd, { if items.is_empty() || element .range_partial_cmp(items[0].as_ref().key()) .unwrap_or(RangeOrdering::Before(false)) .is_before(connected) { None } else { let mut i = 0; let mut j = items.len() - 1; if !element .range_partial_cmp(items[j].as_ref().key()) .unwrap_or(RangeOrdering::After(false)) .is_before(connected) { return Some(j); } // invariants: // vec[i].as_ref().key() < range // vec[j].as_ref().key() >= range // j > i while j - i > 1 { let k = (i + j) / 2; if let Some(ord) = element.range_partial_cmp(items[k].as_ref().key()) { if ord.is_before(connected) { j = k; } else { i = k; } } else { return None; // FIXME: that's bad. Maybe we should expect a total order. } } Some(i) } } #[cfg(test)] mod tests { use std::{collections::HashSet, ops::Bound}; use super::*; macro_rules! items { [$($item:expr),*] => { &[ $( Item::new(AnyRange::from($item), ()) ),* ] }; } #[test] fn binary_search_disconnected_singletons() { assert_eq!(binary_search(items![0], &0, false), Some(0)); assert_eq!(binary_search(items![0, 2, 4], &0, false), Some(0)); assert_eq!(binary_search(items![0, 2, 4], &1, false), Some(0)); assert_eq!(binary_search(items![0, 2, 4], &2, false), Some(1)); assert_eq!(binary_search(items![0, 2, 4], &3, false), Some(1)); assert_eq!(binary_search(items![0, 2, 4], &4, false), Some(2)); assert_eq!(binary_search(items![0, 2, 4], &5, false), Some(2)); assert_eq!(binary_search(items![0, 3, 6], &0, false), Some(0)); assert_eq!(binary_search(items![0, 3, 6], &1, false), Some(0)); assert_eq!(binary_search(items![0, 3, 6], &2, false), Some(0)); assert_eq!(binary_search(items![0, 3, 6], &3, false), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &4, false), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &5, false), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &6, false), Some(2)); assert_eq!(binary_search(items![0, 3, 6], &7, false), Some(2)); } #[test] fn binary_search_disconnected_singletons_float() { assert_eq!(binary_search(items![0.0], &0.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &-1.0, false), None); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &0.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &1.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &2.0, false), Some(1)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &3.0, false), Some(1)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &4.0, false), Some(2)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &5.0, false), Some(2)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &0.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &1.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &2.0, false), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &3.0, false), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &4.0, false), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &5.0, false), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &6.0, false), Some(2)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &7.0, false), Some(2)); } #[test] fn binary_search_connected_singletons() { assert_eq!(binary_search(items![0], &0, true), Some(0)); assert_eq!(binary_search(items![0, 2, 4], &0, true), Some(0)); assert_eq!(binary_search(items![0, 2, 4], &1, true), Some(1)); assert_eq!(binary_search(items![0, 2, 4], &2, true), Some(1)); assert_eq!(binary_search(items![0, 2, 4], &3, true), Some(2)); assert_eq!(binary_search(items![0, 2, 4], &4, true), Some(2)); assert_eq!(binary_search(items![0, 2, 4], &5, true), Some(2)); assert_eq!(binary_search(items![2, 4, 8], &0, true), None); assert_eq!(binary_search(items![0, 3, 6], &0, true), Some(0)); assert_eq!(binary_search(items![0, 3, 6], &1, true), Some(0)); assert_eq!(binary_search(items![0, 3, 6], &2, true), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &3, true), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &4, true), Some(1)); assert_eq!(binary_search(items![0, 3, 6], &5, true), Some(2)); assert_eq!(binary_search(items![0, 3, 6], &6, true), Some(2)); assert_eq!(binary_search(items![0, 3, 6], &7, true), Some(2)); } // for floats, connected or disconnected makes no difference for singletons. #[test] fn binary_search_connected_singletons_float() { assert_eq!(binary_search(items![0.0], &0.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &-1.0, true), None); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &0.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &1.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &2.0, true), Some(1)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &3.0, true), Some(1)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &4.0, true), Some(2)); assert_eq!(binary_search(items![0.0, 2.0, 4.0], &5.0, true), Some(2)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &0.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &1.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &2.0, true), Some(0)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &3.0, true), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &4.0, true), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &5.0, true), Some(1)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &6.0, true), Some(2)); assert_eq!(binary_search(items![0.0, 3.0, 6.0], &7.0, true), Some(2)); } #[test] fn insert() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('+', 0); map.insert('-', 1); map.insert('0'..='9', 2); map.insert('.', 3); assert_eq!(*map.get('.').unwrap(), 3) } #[test] fn insert_around() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert(' ', 0); map.insert('#', 1); map.insert('e', 2); map.insert('%', 3); map.insert('A'..='Z', 4); map.insert('a'..='z', 5); assert!(map.get('a').is_some()) } #[test] fn update_connected_after() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('+', 0); map.insert('-', 1); map.insert('0'..='9', 2); map.update('.', |binding| { assert!(binding.is_none()); Some(3) }); assert_eq!(*map.get('.').unwrap(), 3) } #[test] fn update_singleton() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('*', 0); map.update('*', |_| Some(1)); assert_eq!(map.iter().count(), 1); assert_eq!(map.get('*'), Some(&1)) } #[test] fn update_connected_before() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('+', 0); map.insert('.', 1); map.insert('0'..='9', 2); map.update('-', |binding| { assert!(binding.is_none()); Some(3) }); assert_eq!(map.iter().count(), 4); assert_eq!(*map.get('-').unwrap(), 3) } #[test] fn update_around() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('e', 0); map.update('a'..='z', |_| Some(1)); assert_eq!(map.iter().count(), 1); assert_eq!(map.get('a'), Some(&1)) } #[test] fn update_stress() { let ranges = [ // 'A'..='Z', // 'a'..='z', // '0'..='9', // '-'..='-', // '.'..='.', // '_'..='_', // '~'..='~', // '%'..='%', // '!'..='!', // '$'..='$', // '&'..='&', // '\''..='\'', // '('..='(', // ')'..=')', // '*'..='*', // '+'..='+', ','..=',', ';'..=';', '='..='=', ':'..=':', // '@'..='@', // '['..='[', // '0'..='9', // '1'..='9', // '1'..='1', // '2'..='2', // '2'..='2', // 'A'..='Z', // 'a'..='z', // '0'..='9', // '-'..='-', // '.'..='.', // '_'..='_', // '~'..='~', // '%'..='%', // '!'..='!', // '$'..='$', // '&'..='&', '\''..='\'', '('..='(', ')'..=')', '*'..='*', '+'..='+', // ','..=',', // ';'..=';', // '='..='=', // ':'..=':', // '/'..='/', // '?'..='?', // '#'..='#' ]; let mut map: crate::RangeMap> = crate::RangeMap::new(); for (i, range) in ranges.into_iter().enumerate() { map.update(range, |current| { let mut list = current.cloned().unwrap_or_default(); list.push(i); Some(list) }); } eprintln!("before: {map:?}"); map.update(','..=',', |current| { let mut list = current.cloned().unwrap_or_default(); list.push(9); Some(list) }); eprintln!("after: {map:?}"); let mut found_ranges = HashSet::new(); for (range, _) in map.iter() { eprintln!("looking for range: {range:?}"); assert!(found_ranges.insert(range)) } } #[test] fn update_stress2() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('+'..='+', 0); map.insert(AnyRange::new(Bound::Excluded('+'), Bound::Included(',')), 1); map.update(','..=',', |_| Some(2)); let mut found_ranges = HashSet::new(); for (range, _) in map.iter() { eprintln!("looking for range: {range:?}"); assert!(found_ranges.insert(range)) } } #[test] fn update_test() { let mut map: crate::RangeMap = crate::RangeMap::new(); map.insert('0'..='9', 0); map.insert( AnyRange::new(Bound::Excluded('\''), Bound::Included('(')), 1, ); map.insert(AnyRange::new(Bound::Excluded('('), Bound::Included(')')), 2); map.insert(AnyRange::new(Bound::Excluded(')'), Bound::Included('*')), 3); map.insert('+', 4); map.insert(',', 5); map.insert('-', 6); map.insert('.', 7); map.insert('/', 8); assert_eq!(map.range_count(), 9); assert_eq!(map.iter().count(), 9); map.update( AnyRange::new(Bound::Excluded('\''), Bound::Included('(')), |_| Some(10), ); map.update( AnyRange::new(Bound::Excluded('('), Bound::Included(')')), |_| Some(11), ); map.update( AnyRange::new(Bound::Excluded(')'), Bound::Included('*')), |_| Some(12), ); assert_eq!(map.range_count(), 9); assert_eq!(map.iter().count(), 9); // let mut ranges = map.iter(); // let (a, _) = ranges.next().unwrap(); // assert_eq!(a.first(), Some('(')); // assert_eq!(a.last(), Some(')')); // let (b, _) = ranges.next().unwrap(); // assert_eq!(b.first(), Some('*')); // assert_eq!(b.last(), Some('*')); // let (c, _) = ranges.next().unwrap(); // assert_eq!(c.first(), Some('+')); // assert_eq!(c.last(), Some('9')); } } btree-range-map-0.7.2/src/generic/mod.rs000064400000000000000000000002401046102023000161240ustar 00000000000000pub use btree_slab::generic::Node; pub mod map; pub mod multimap; pub mod set; pub use map::RangeMap; pub use multimap::RangeMultiMap; pub use set::RangeSet; btree-range-map-0.7.2/src/generic/multimap.rs000064400000000000000000000050331046102023000172020ustar 00000000000000use crate::{ generic::{ map::{IntoIter, Iter}, RangeMap, }, AnyRange, AsRange, }; use btree_slab::generic::Node; use cc_traits::{SetMut, SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; use range_traits::{Measure, PartialEnum}; /// Multi map. /// /// In a multi map, each key is associated to a set of values. /// The type parameter `S` is the set type. It can be replaced by anything /// implementing the [`cc_traits::SetMut`] trait, such as the standard /// [`BTreeSet`](std::collections::BTreeSet) and [`HashSet`](std::collections::HashSet). #[derive(Clone)] pub struct RangeMultiMap { map: RangeMap, } impl RangeMultiMap { pub fn new() -> RangeMultiMap where C: Default, { RangeMultiMap { map: RangeMap::new(), } } } impl Default for RangeMultiMap { fn default() -> Self { Self::new() } } impl, S>>> RangeMultiMap where C: SimpleCollectionRef, { pub fn iter(&self) -> Iter { self.map.iter() } } impl<'a, K: Clone + PartialOrd + Measure, S, C: Slab, S>>> IntoIterator for &'a RangeMultiMap where C: SimpleCollectionRef, { type Item = (&'a AnyRange, &'a S); type IntoIter = Iter<'a, K, S, C>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl, S>>> RangeMultiMap where C: SimpleCollectionRef, C: SimpleCollectionMut, { pub fn insert, V>(&mut self, key: R, value: V) where K: Clone + PartialEnum + Measure, V: PartialEq + Clone, S: SetMut + PartialEq + Clone + Default, { self.map.update(key, |set_opt| { let mut result = match set_opt { Some(set) => set.clone(), None => S::default(), }; result.insert(value.clone()); Some(result) }) } pub fn remove, V>(&mut self, key: R, value: &V) where K: Clone + PartialEnum + Measure, V: PartialEq + Clone, S: SetMut + PartialEq + Clone + Default, { self.map.update(key, |set_opt| match set_opt { Some(set) => { let mut result = set.clone(); result.remove(value); if result.is_empty() { None } else { Some(result) } } None => None, }) } } impl, S>>> IntoIterator for RangeMultiMap where C: SimpleCollectionRef, C: SimpleCollectionMut, { type Item = (AnyRange, S); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { self.map.into_iter() } } btree-range-map-0.7.2/src/generic/set.rs000064400000000000000000000154371046102023000161560ustar 00000000000000use crate::{generic::RangeMap, AnyRange, AsRange, IntoRange, RangePartialOrd}; use btree_slab::generic::Node; use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; use range_traits::{Bounded, Measure, PartialEnum}; use std::{ cmp::Ordering, fmt, hash::{Hash, Hasher}, }; /// Range set. /// /// This is based on a range map, where the values are `()`. #[derive(Clone)] pub struct RangeSet { map: RangeMap, } impl RangeSet { pub fn new() -> RangeSet where C: Default, { RangeSet { map: RangeMap::new(), } } } impl Default for RangeSet { fn default() -> Self { Self::new() } } impl, ()>>> RangeSet where C: SimpleCollectionRef, { pub fn range_count(&self) -> usize { self.map.range_count() } pub fn len(&self) -> T::Len where T: Measure + PartialEnum + Bounded, { self.map.len() } pub fn bounded_len(&self) -> Option where T: Measure + PartialEnum, { self.map.bounded_len() } pub fn is_empty(&self) -> bool where T: Measure + PartialEnum, { self.map.is_empty() } pub fn intersects>(&self, values: R) -> bool where T: Clone + PartialEnum + Measure, { self.map.intersects(values) } pub fn contains(&self, value: T) -> bool where T: Clone + PartialEnum + RangePartialOrd + Measure, { self.map.contains_key(value) } pub fn iter(&self) -> Iter { Iter { inner: self.map.iter(), } } /// Returns an iterator over the gaps (missing values) of the set. pub fn gaps(&self) -> Gaps { self.map.gaps() } } impl, ()>>> fmt::Debug for RangeSet where C: SimpleCollectionRef, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; for range in self { write!(f, "{:?}", range)? } write!(f, "}}") } } impl<'a, T, C: Slab, ()>>> IntoIterator for &'a RangeSet where C: SimpleCollectionRef, { type Item = &'a AnyRange; type IntoIter = Iter<'a, T, C>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl, ()>>> RangeSet where C: SimpleCollectionRef, C: SimpleCollectionMut, { pub fn insert>(&mut self, key: R) where T: Clone + PartialEnum + Measure, { self.map.insert(key, ()) } pub fn remove>(&mut self, key: R) where T: Clone + PartialEnum + Measure, { self.map.remove(key) } pub fn complement(&self) -> Self where T: Clone + Measure + PartialEnum, C: Default, { self.gaps().map(AnyRange::cloned).collect() } } impl, ()>>, D: Slab, ()>>> PartialEq> for RangeSet where L: Measure + PartialOrd + PartialEnum, K: PartialEnum, C: SimpleCollectionRef, D: SimpleCollectionRef, { fn eq(&self, other: &RangeSet) -> bool { self.map == other.map } } impl, ()>>> Eq for RangeSet where K: Measure + PartialEnum + Ord, C: SimpleCollectionRef, { } impl, ()>>, D: Slab, ()>>> PartialOrd> for RangeSet where L: Measure + PartialOrd + PartialEnum, K: PartialEnum, C: SimpleCollectionRef, D: SimpleCollectionRef, { fn partial_cmp(&self, other: &RangeSet) -> Option { self.map.partial_cmp(&other.map) } } impl, ()>>> Ord for RangeSet where K: Measure + PartialEnum + Ord, C: SimpleCollectionRef, { fn cmp(&self, other: &Self) -> Ordering { self.map.cmp(&other.map) } } impl, ()>>> Hash for RangeSet where K: Hash + PartialEnum, C: SimpleCollectionRef, { fn hash(&self, h: &mut H) { self.map.hash(h) } } impl, ()>>> IntoIterator for RangeSet where C: SimpleCollectionRef, C: SimpleCollectionMut, { type Item = AnyRange; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.map.into_iter(), } } } pub struct Iter<'a, T, C> { inner: crate::generic::map::Iter<'a, T, (), C>, } impl<'a, T, C: Slab, ()>>> Iterator for Iter<'a, T, C> where C: SimpleCollectionRef, { type Item = &'a AnyRange; fn next(&mut self) -> Option { match self.inner.next() { Some((range, ())) => Some(range), None => None, } } } pub struct IntoIter { inner: crate::generic::map::IntoIter, } impl, ()>>> Iterator for IntoIter where C: SimpleCollectionRef, C: SimpleCollectionMut, { type Item = AnyRange; fn next(&mut self) -> Option { self.inner.next().map(|(range, _)| range) } } /// Iterator over the gaps (unbound keys) of a `RangeSet`. pub type Gaps<'a, T, C> = crate::generic::map::Gaps<'a, T, (), C>; impl, ()>>> std::iter::Extend for RangeSet where R::Item: Clone + Measure + PartialOrd, C: SimpleCollectionRef, C: SimpleCollectionMut, { fn extend>(&mut self, iter: I) { for range in iter { self.insert(range) } } } impl, ()>>> FromIterator for RangeSet where R::Item: Clone + Measure + PartialOrd, C: SimpleCollectionRef, C: SimpleCollectionMut, { fn from_iter>(iter: I) -> Self { let mut result = Self::default(); result.extend(iter); result } } #[cfg(test)] mod test { use crate::{AnyRange, RangeSet}; #[test] fn gaps1() { let mut a: RangeSet = RangeSet::new(); let mut b: RangeSet = RangeSet::new(); a.insert(10..20); b.insert(0..10); b.insert(20..); assert_eq!(a.complement(), b) } #[test] fn gaps2() { let mut a: RangeSet = RangeSet::new(); let mut b: RangeSet = RangeSet::new(); a.insert(0..10); b.insert(10..); assert_eq!(a.complement(), b) } #[test] fn gaps3() { let mut a: RangeSet = RangeSet::new(); let mut b: RangeSet = RangeSet::new(); a.insert(20..); b.insert(0..=19); assert_eq!(a.complement(), b) } #[test] fn gaps4() { let mut a: RangeSet = RangeSet::new(); a.insert(10..20); let mut gaps = a.gaps().map(AnyRange::cloned); assert_eq!(gaps.next(), Some(AnyRange::from(..10u8))); assert_eq!(gaps.next(), Some(AnyRange::from(20u8..))); assert_eq!(gaps.next(), None) } #[test] fn gaps5() { let mut a: RangeSet = RangeSet::new(); a.insert(..10); a.insert(20..); let mut gaps = a.gaps().map(AnyRange::cloned); assert_eq!(gaps.next(), Some(AnyRange::from(10..20))); assert_eq!(gaps.next(), None) } #[test] fn gaps6() { let mut a: RangeSet = RangeSet::new(); a.insert(10..20); assert_eq!(a.complement().complement(), a) } } btree-range-map-0.7.2/src/lib.rs000064400000000000000000000063351046102023000145120ustar 00000000000000//! A *range map* is a map where keys are aggregated into ranges of keys for //! efficient storage. Every time you need to store a large number numeric-keyed //! items in a map or set, a range map (or range set) should be used. //! //! This library provides a range map implementation based on //! [`btree-slab`](https://crates.io/crates/btree-slab)'s B-tree. //! It defines three basic types `RangeSet`, `RangeMap` and //! `RangeMultiMap`. //! //! ## Usage //! //! The `RangeSet` and `RangeMap` behave similarly to the standard //! `BTreeSet` and `BTreeMap` types. //! However in addition to `PartialOrd`, the key type must also implement the //! `Measure` trait defining how keys are merged into ranges. //! This trait is implemented by default for `char`, integer types and float //! types. //! //! ``` //! use btree_range_map::RangeMap; //! //! let mut range_map: RangeMap = RangeMap::new(); //! range_map.insert(00..=05, true); //! range_map.insert(4, false); //! assert_eq!(range_map.range_count(), 3); //! assert_eq!(range_map.get(03), Some(&true)); //! assert_eq!(range_map.get(04), Some(&false)); //! assert_eq!(range_map.get(05), Some(&true)); //! ``` //! //! This library supports included and excluded bounds: //! //! ``` //! # use btree_range_map::RangeMap; //! # let mut range_map: RangeMap = RangeMap::new(); //! range_map.insert(..1, true); //! range_map.insert(..=1, true); //! range_map.insert(2, true); //! range_map.insert(3..5, true); //! range_map.insert(5..=7, true); //! range_map.insert(7.., true); //! assert_eq!(range_map.range_count(), 1); //! ``` //! //! It also supports non standard ranges with excluded start bounds: //! //! ``` //! # use btree_range_map::RangeMap; //! # let mut range_map: RangeMap = RangeMap::new(); //! use btree_range_map::{ //! RangeFromExcluded, //! RangeFromExcludedTo, //! RangeFromExcludedToIncluded //! }; //! //! // same as `4..` //! range_map.insert(RangeFromExcluded::new(3), true); //! //! // same as `3` //! range_map.insert(RangeFromExcludedTo::new(2, 4), true); //! //! // same as `1..=2` //! range_map.insert(RangeFromExcludedToIncluded::new(0, 2), true); //! //! assert_eq!(range_map.range_count(), 1); //! ``` //! //! ### Floats //! //! Floating point numbers `f32` and `f64` are handled as one might expect. //! //! ``` //! use btree_range_map::{RangeMap, RangeFromExcluded}; //! let mut range_map: RangeMap = RangeMap::new(); //! //! // sets all `f32` below zero to `false`. //! range_map.insert(..0.0, false); //! //! // sets all `f32` above zero to `true`. //! range_map.insert(RangeFromExcluded::new(0.0), true); //! //! assert_eq!(range_map.range_count(), 2); //! assert_eq!(range_map.get(0.0), None); // only `0.0` is unmapped. //! ``` pub mod generic; mod range; #[cfg(feature = "serde")] mod serde; pub use range::*; pub type DefaultSetContainer = slab::Slab, ()>>; pub type DefaultMapContainer = slab::Slab, V>>; pub type RangeSet = generic::RangeSet>; pub type RangeMap = generic::RangeMap>; pub type RangeMultiMap = generic::RangeMultiMap>; btree-range-map-0.7.2/src/range/any.rs000064400000000000000000000233301046102023000156210ustar 00000000000000use super::{ direct_bound_cmp, direct_bound_partial_cmp, direct_bound_partial_eq, is_range_empty, max_bound, min_bound, AsRange, Bound, BoundOrdering, Directed, Measure, }; use range_traits::{Bounded, MaybeBounded, PartialEnum}; use std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, hash::{Hash, Hasher}, ops::RangeBounds, }; #[derive(Clone, Copy)] pub struct AnyRange { pub start: Bound, pub end: Bound, } impl AnyRange { pub fn new(start: Bound, end: Bound) -> Self { Self { start, end } } pub fn from>(range: R) -> AnyRange where T: Clone, { AnyRange { start: range.start().cloned(), end: range.end().cloned(), } } pub fn into_bounds(self) -> (Bound, Bound) { (self.start, self.end) } pub fn is_empty(&self) -> bool where T: Measure + PartialEnum, { is_range_empty(self.start_bound(), self.end_bound()) } pub fn len(&self) -> T::Len where T: Measure + Bounded, { match (self.start_bound(), self.end_bound()) { (Bound::Included(a), Bound::Included(b)) => a.distance(b) + b.len(), (Bound::Included(a), Bound::Excluded(b)) => a.distance(b), (Bound::Included(a), Bound::Unbounded) => a.distance(&T::max()), (Bound::Excluded(a), Bound::Included(b)) => a.distance(b) - a.len() + b.len(), (Bound::Excluded(a), Bound::Excluded(b)) => a.distance(b) - a.len(), (Bound::Excluded(a), Bound::Unbounded) => a.distance(&T::max()) - a.len(), (Bound::Unbounded, Bound::Included(b)) => T::min().distance(b) + b.len(), (Bound::Unbounded, Bound::Excluded(b)) => T::min().distance(b), (Bound::Unbounded, Bound::Unbounded) => T::min().distance(&T::max()), } } pub fn bounded_len(&self) -> Option where T: Measure + MaybeBounded, { match (self.start_bound(), self.end_bound()) { (Bound::Included(a), Bound::Included(b)) => Some(a.distance(b) + b.len()), (Bound::Included(a), Bound::Excluded(b)) => Some(a.distance(b)), (Bound::Included(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m)), (Bound::Excluded(a), Bound::Included(b)) => Some(a.distance(b) - a.len() + b.len()), (Bound::Excluded(a), Bound::Excluded(b)) => Some(a.distance(b) - a.len()), (Bound::Excluded(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m) - a.len()), (Bound::Unbounded, Bound::Included(b)) => T::min().map(|m| m.distance(b) + b.len()), (Bound::Unbounded, Bound::Excluded(b)) => T::min().map(|m| m.distance(b)), (Bound::Unbounded, Bound::Unbounded) => { T::min().and_then(|min| T::max().map(|max| min.distance(&max))) } } } pub fn pick(&self) -> Option where T: Clone + Measure + PartialEnum + Bounded, { self.first().or_else(|| self.last()) } /// Get the first element of the range if there is one. pub fn first(&self) -> Option where T: Clone + Measure + PartialEnum + Bounded, { if self.is_empty() { None } else { match self.start_bound() { Bound::Included(a) => Some(a.clone()), Bound::Excluded(a) => a.succ(), Bound::Unbounded => Some(::min()), } } } /// Get the last element of the range if there is one. pub fn last(&self) -> Option where T: Clone + Measure + PartialEnum + Bounded, { if self.is_empty() { None } else { match self.end_bound() { Bound::Included(a) => Some(a.clone()), Bound::Excluded(a) => a.pred(), Bound::Unbounded => Some(::max()), } } } pub fn add(&mut self, other: &S) where T: Clone + Measure + PartialEnum, S: RangeBounds, { self.start = min_bound(self.start_bound(), other.start_bound(), true).cloned(); self.end = max_bound(self.end_bound(), other.end_bound(), false).cloned(); } pub fn intersects(&self, other: &S) -> bool where T: Measure + PartialEnum, S: RangeBounds, { Directed::End(self.end_bound()) >= Directed::Start(other.start_bound()) && Directed::End(other.end_bound()) >= Directed::Start(self.start_bound()) } pub fn intersection(&self, other: &Self) -> Self where T: Clone + Measure + PartialEnum, { Self { start: max_bound(self.start_bound(), other.start_bound(), true).cloned(), end: min_bound(self.end_bound(), other.end_bound(), false).cloned(), } } // pub fn pick_in_intersection(&self, other: &S) -> Option // where // T: Clone + Measure + PartialEnum, // S: AsRange + RangeBounds, // { // if self.intersects(other) { // if Directed::End(self.end_bound()) <= Directed::End(other.end_bound()) { // if other.is_empty() { // None // } else { // // pick between other.start and self.end // Some(match other.start_bound() { // Bound::Included(a) => a.clone(), // Bound::Excluded(a) => a.succ().unwrap(), // Bound::Unbounded => T::MIN, // }) // } // } else if self.is_empty() { // None // } else { // // pick between self.start and other.end // Some(match self.start_bound() { // Bound::Included(a) => a.clone(), // Bound::Excluded(a) => a.succ().unwrap(), // Bound::Unbounded => T::MIN, // }) // } // } else { // None // } // } } impl fmt::Debug for AnyRange { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.start { Bound::Included(v) => v.fmt(f)?, Bound::Excluded(v) => write!(f, "{:?}.", v)?, Bound::Unbounded => write!(f, ".")?, } match &self.end { Bound::Included(v) => write!(f, "..={:?}", v), Bound::Excluded(v) => write!(f, "..{:?}", v), Bound::Unbounded => write!(f, ".."), } } } impl<'a, T> AnyRange<&'a T> { pub fn ref_is_empty(&self) -> bool where T: PartialEnum + Measure, { is_range_empty(self.start_bound().cloned(), self.end_bound().cloned()) } } impl PartialEq> for AnyRange where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { fn eq(&self, other: &AnyRange) -> bool { direct_bound_partial_eq(self.start_bound(), other.start_bound(), true) && direct_bound_partial_eq(self.end_bound(), other.end_bound(), false) } } impl Eq for AnyRange where T: Measure + PartialEnum + Ord {} impl PartialOrd> for AnyRange where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { fn partial_cmp(&self, other: &AnyRange) -> Option { // Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound())) match direct_bound_partial_cmp(self.start_bound(), other.start_bound(), true) { Some(BoundOrdering::Excluded(_)) => Some(Ordering::Less), Some(BoundOrdering::Included(false)) => Some(Ordering::Greater), Some(BoundOrdering::Included(true)) => { match direct_bound_partial_cmp(self.end_bound(), other.end_bound(), false) { Some(BoundOrdering::Excluded(_)) => Some(Ordering::Greater), Some(BoundOrdering::Included(false)) => Some(Ordering::Less), Some(BoundOrdering::Included(true)) => Some(Ordering::Equal), None => None, } } None => None, } } } impl Ord for AnyRange where T: Measure + PartialEnum + Ord, { fn cmp(&self, other: &Self) -> Ordering { // Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound())) match direct_bound_cmp(self.start_bound(), other.start_bound(), true) { BoundOrdering::Excluded(_) => Ordering::Less, BoundOrdering::Included(false) => Ordering::Greater, BoundOrdering::Included(true) => { match direct_bound_cmp(self.end_bound(), other.end_bound(), false) { BoundOrdering::Excluded(_) => Ordering::Greater, BoundOrdering::Included(false) => Ordering::Less, BoundOrdering::Included(true) => Ordering::Equal, } } } } } impl Hash for AnyRange where T: Hash + PartialEnum, { fn hash(&self, h: &mut H) { Directed::Start(self.start_bound()).hash(h); Directed::End(self.end_bound()).hash(h); } } impl AnyRange<&T> { pub fn cloned(self) -> AnyRange { AnyRange { start: self.start.cloned(), end: self.end.cloned(), } } } impl RangeBounds for AnyRange { fn start_bound(&self) -> Bound<&T> { match &self.start { Bound::Included(v) => Bound::Included(v), Bound::Excluded(v) => Bound::Excluded(v), Bound::Unbounded => Bound::Unbounded, } } fn end_bound(&self) -> Bound<&T> { match &self.end { Bound::Included(v) => Bound::Included(v), Bound::Excluded(v) => Bound::Excluded(v), Bound::Unbounded => Bound::Unbounded, } } } impl From> for AnyRange { fn from(value: std::ops::Range) -> Self { Self { start: Bound::Included(value.start), end: Bound::Excluded(value.end), } } } impl From> for AnyRange { fn from(value: std::ops::RangeInclusive) -> Self { let (start, end) = value.into_inner(); Self { start: Bound::Included(start), end: Bound::Included(end), } } } impl From> for AnyRange { fn from(value: std::ops::RangeFrom) -> Self { Self { start: Bound::Included(value.start), end: Bound::Unbounded, } } } impl From> for AnyRange { fn from(value: std::ops::RangeTo) -> Self { Self { start: Bound::Unbounded, end: Bound::Excluded(value.end), } } } impl From> for AnyRange { fn from(value: std::ops::RangeToInclusive) -> Self { Self { start: Bound::Unbounded, end: Bound::Included(value.end), } } } impl From for AnyRange { fn from(_: std::ops::RangeFull) -> Self { Self { start: Bound::Unbounded, end: Bound::Unbounded, } } } #[cfg(test)] mod tests { use super::*; #[test] fn intersection_test1() { let a: AnyRange = ('A'..='A').into(); assert!(a.intersects(&a)) } #[test] fn intersection_test2() { let a: AnyRange = ('A'..='A').into(); let b: AnyRange = ('B'..='B').into(); assert!(!a.intersects(&b)) } } btree-range-map-0.7.2/src/range/bound.rs000064400000000000000000000104021046102023000161350ustar 00000000000000use super::{direct_bound_partial_cmp, BoundOrd, BoundOrdering, BoundPartialOrd, Measure}; use range_traits::PartialEnum; use std::{ cmp::Ordering, hash::{Hash, Hasher}, ops::Bound, }; /// Types that can be interpreted as range bounds. pub trait AsBound { type Item; fn bound(&self) -> Bound<&Self::Item>; } impl AsBound for u8 { type Item = u8; fn bound(&self) -> Bound<&u8> { Bound::Included(self) } } impl<'a, T> AsBound for Bound<&'a T> { type Item = T; fn bound(&self) -> Bound<&T> { *self } } #[inline(always)] pub(crate) fn invert_bound(bound: Bound) -> Option> { match bound { Bound::Unbounded => None, Bound::Included(t) => Some(Bound::Excluded(t)), Bound::Excluded(t) => Some(Bound::Included(t)), } } #[derive(Clone, Copy, Debug)] pub enum Directed { Start(T), End(T), } impl Directed { /// Returns the directed value, without direction. pub fn unwrap(self) -> T { match self { Self::Start(t) => t, Self::End(t) => t, } } /// Returns a reference to the directed value, without direction. pub fn value(&self) -> &T { match self { Self::Start(t) => t, Self::End(t) => t, } } } impl Directed> { pub fn as_ref(&self) -> Directed> { match self { Directed::Start(b) => Directed::Start(match b { Bound::Included(b) => Bound::Included(b), Bound::Excluded(b) => Bound::Excluded(b), Bound::Unbounded => Bound::Unbounded, }), Directed::End(b) => Directed::End(match b { Bound::Included(b) => Bound::Included(b), Bound::Excluded(b) => Bound::Excluded(b), Bound::Unbounded => Bound::Unbounded, }), } } } impl<'a, T: Hash + PartialEnum> Hash for Directed> { fn hash(&self, h: &mut H) { match self { Directed::Start(b) => match b { Bound::Included(b) => b.hash(h), Bound::Excluded(b) => match b.succ() { Some(c) => c.hash(h), None => b.hash(h), }, Bound::Unbounded => (), }, Directed::End(b) => match b { Bound::Included(b) => b.hash(h), Bound::Excluded(b) => match b.pred() { Some(c) => c.hash(h), None => b.hash(h), }, Bound::Unbounded => (), }, } } } impl PartialEq>> for Directed> where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { fn eq(&self, other: &Directed>) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl Eq for Directed> where T: Measure + Ord + PartialEnum {} impl PartialOrd>> for Directed> where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { fn partial_cmp(&self, other: &Directed>) -> Option { match self.bound_partial_cmp(other) { Some(BoundOrdering::Included(true)) => Some(Ordering::Equal), Some(BoundOrdering::Included(false)) => match other { Directed::Start(_) => Some(Ordering::Greater), Directed::End(_) => Some(Ordering::Less), }, Some(BoundOrdering::Excluded(_)) => match other { Directed::Start(_) => Some(Ordering::Less), Directed::End(_) => Some(Ordering::Greater), }, None => None, } } } impl Ord for Directed> where T: Measure + Ord + PartialEnum, { fn cmp(&self, other: &Directed>) -> Ordering { match self.bound_cmp(other) { BoundOrdering::Included(true) => Ordering::Equal, BoundOrdering::Included(false) => match other { Directed::Start(_) => Ordering::Greater, Directed::End(_) => Ordering::Less, }, BoundOrdering::Excluded(_) => match other { Directed::Start(_) => Ordering::Less, Directed::End(_) => Ordering::Greater, }, } } } pub(crate) fn min_bound<'a, T: Measure + PartialOrd + PartialEnum>( a: Bound<&'a T>, b: Bound<&'a T>, start: bool, ) -> Bound<&'a T> { match direct_bound_partial_cmp(a, b, start) { Some(BoundOrdering::Included(_)) => { if start { b } else { a } } _ => { if start { a } else { b } } } } pub(crate) fn max_bound<'a, T: Measure + PartialOrd + PartialEnum>( a: Bound<&'a T>, b: Bound<&'a T>, start: bool, ) -> Bound<&'a T> { match direct_bound_partial_cmp(a, b, start) { Some(BoundOrdering::Included(_)) => { if start { a } else { b } } _ => { if start { b } else { a } } } } btree-range-map-0.7.2/src/range/from_excluded.rs000064400000000000000000000006671046102023000176620ustar 00000000000000use std::ops::{Bound, RangeBounds}; /// Range with only an start bound, excluded. pub struct RangeFromExcluded { pub start: T, } impl RangeFromExcluded { pub const fn new(start: T) -> RangeFromExcluded { RangeFromExcluded { start } } } impl RangeBounds for RangeFromExcluded { fn start_bound(&self) -> Bound<&T> { Bound::Excluded(&self.start) } fn end_bound(&self) -> Bound<&T> { Bound::Unbounded } } btree-range-map-0.7.2/src/range/from_excluded_to.rs000064400000000000000000000007411046102023000203550ustar 00000000000000use std::ops::{Bound, RangeBounds}; /// Range where both bounds are excluded. pub struct RangeFromExcludedTo { pub start: T, pub end: T, } impl RangeFromExcludedTo { pub const fn new(start: T, end: T) -> RangeFromExcludedTo { RangeFromExcludedTo { start, end } } } impl RangeBounds for RangeFromExcludedTo { fn start_bound(&self) -> Bound<&T> { Bound::Excluded(&self.start) } fn end_bound(&self) -> Bound<&T> { Bound::Excluded(&self.end) } } btree-range-map-0.7.2/src/range/from_excluded_to_included.rs000064400000000000000000000010361046102023000222220ustar 00000000000000use std::ops::{Bound, RangeBounds}; /// Range with an excluded start bound and included end bound. pub struct RangeFromExcludedToIncluded { pub start: T, pub end: T, } impl RangeFromExcludedToIncluded { pub const fn new(start: T, end: T) -> RangeFromExcludedToIncluded { RangeFromExcludedToIncluded { start, end } } } impl RangeBounds for RangeFromExcludedToIncluded { fn start_bound(&self) -> Bound<&T> { Bound::Excluded(&self.start) } fn end_bound(&self) -> Bound<&T> { Bound::Included(&self.end) } } btree-range-map-0.7.2/src/range/ordering.rs000064400000000000000000000406041046102023000166460ustar 00000000000000use super::{AsBound, AsRange, Directed, Measure}; use range_traits::{MaybeBounded, PartialEnum}; use std::{ cmp::{Ordering, PartialOrd}, ops::Bound, }; #[derive(Debug)] pub enum RangeOrdering { Before(bool), Intersecting(bool, bool), After(bool), } impl RangeOrdering { pub fn is_before(&self, connected: bool) -> bool { match self { RangeOrdering::Before(c) => !*c || !connected, _ => false, } } pub fn is_after(&self, connected: bool) -> bool { match self { RangeOrdering::After(c) => !*c || !connected, _ => false, } } pub fn matches(&self, connected: bool) -> bool { match self { RangeOrdering::Before(c) => *c && connected, RangeOrdering::After(c) => *c && connected, RangeOrdering::Intersecting(_, _) => true, } } } pub trait RangePartialOrd { fn range_partial_cmp>(&self, other: &R) -> Option; } impl RangePartialOrd for R where R::Item: PartialOrd + Measure, U: PartialEnum, { fn range_partial_cmp>(&self, other: &S) -> Option { match direct_bound_partial_cmp(self.start(), other.start(), true) { Some(BoundOrdering::Included(limit_before)) => { match inverse_bound_partial_cmp(self.start(), other.end(), false) { Some(BoundOrdering::Included(_)) => { match direct_bound_partial_cmp(self.end(), other.end(), false) { Some(BoundOrdering::Included(limit_after)) => { Some(RangeOrdering::Intersecting(limit_before, limit_after)) } Some(BoundOrdering::Excluded(_)) => { Some(RangeOrdering::Intersecting(limit_before, false)) } None => None, } } Some(BoundOrdering::Excluded(limit_after)) => { Some(RangeOrdering::After(limit_after)) } None => None, } } Some(BoundOrdering::Excluded(_)) => { match inverse_bound_partial_cmp(self.end(), other.start(), true) { Some(BoundOrdering::Included(_)) => { match direct_bound_partial_cmp(self.end(), other.end(), false) { Some(BoundOrdering::Included(limit_after)) => { Some(RangeOrdering::Intersecting(false, limit_after)) } Some(BoundOrdering::Excluded(_)) => { Some(RangeOrdering::Intersecting(false, false)) } None => None, } } Some(BoundOrdering::Excluded(limit_before)) => { Some(RangeOrdering::Before(limit_before)) } None => None, } } None => None, } } } pub enum BoundOrdering { Included(bool), Excluded(bool), } pub trait BoundPartialOrd { fn bound_partial_cmp>(&self, other: &Directed) -> Option; } impl BoundPartialOrd for Directed where B::Item: PartialOrd + Measure + PartialEnum, U: PartialEnum, { fn bound_partial_cmp>( &self, other: &Directed, ) -> Option { match (self, other) { (Directed::Start(a), Directed::Start(b)) => { direct_bound_partial_cmp(a.bound(), b.bound(), true) } (Directed::Start(a), Directed::End(b)) => { inverse_bound_partial_cmp(a.bound(), b.bound(), false) } (Directed::End(a), Directed::Start(b)) => { inverse_bound_partial_cmp(a.bound(), b.bound(), true) } (Directed::End(a), Directed::End(b)) => { direct_bound_partial_cmp(a.bound(), b.bound(), false) } } } } pub trait BoundOrd { fn bound_cmp>(&self, other: &Directed) -> BoundOrdering; } impl BoundOrd for Directed where B::Item: Ord + Measure + PartialEnum, { fn bound_cmp>(&self, other: &Directed) -> BoundOrdering { match (self, other) { (Directed::Start(a), Directed::Start(b)) => { direct_bound_cmp(a.bound(), b.bound(), true) } (Directed::Start(a), Directed::End(b)) => { inverse_bound_cmp(a.bound(), b.bound(), false) } (Directed::End(a), Directed::Start(b)) => inverse_bound_cmp(a.bound(), b.bound(), true), (Directed::End(a), Directed::End(b)) => direct_bound_cmp(a.bound(), b.bound(), false), } } } pub enum Dist { Equals, Zero, One, More, } fn dist(t: &T, u: &U) -> Dist where T: PartialEnum + PartialEq, { if t == u { return Dist::Equals; } if let Some(s) = t.succ() { if s == *u { return Dist::Zero; } else { match s.succ() { Some(ss) if ss == *u => return Dist::One, _ => (), } } } if let Some(s) = t.pred() { if s == *u { return Dist::Zero; } else { match s.pred() { Some(ss) if ss == *u => return Dist::One, _ => (), } } } Dist::More } fn distance_zero(t: &T, u: &U) -> bool where T: PartialEnum + PartialEq, { match t.succ() { Some(s) if s == *u => return true, _ => (), } match t.pred() { Some(p) if p == *u => return true, _ => (), } false } pub(crate) fn direct_bound_partial_cmp( b1: Bound<&T>, b2: Bound<&U>, start: bool, ) -> Option where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { let included_ord = if start { Ordering::Greater } else { Ordering::Less }; match (b1, b2) { (Bound::Included(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), None => None, }, (Bound::Included(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), Some(ord) if ord == included_ord => { Some(BoundOrdering::Included(distance_zero(v1, v2))) } Some(_) => Some(BoundOrdering::Excluded(false)), None => None, }, (Bound::Included(v1), Bound::Unbounded) => Some(BoundOrdering::Included( (start && U::min().map(|m| *v1 == m).unwrap_or(false)) || (!start && U::max().map(|m| *v1 == m).unwrap_or(false)), )), (Bound::Excluded(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Included(false)), Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), Some(_) => match dist(v1, v2) { Dist::Zero => Some(BoundOrdering::Included(true)), Dist::One => Some(BoundOrdering::Excluded(true)), _ => Some(BoundOrdering::Excluded(false)), }, None => None, }, (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), None => None, }, (Bound::Excluded(_), Bound::Unbounded) => Some(BoundOrdering::Included(false)), (Bound::Unbounded, Bound::Included(v2)) => { if (start && U::min().map(|m| *v2 == m).unwrap_or(false)) || (!start && U::max().map(|m| *v2 == m).unwrap_or(false)) { Some(BoundOrdering::Included(true)) } else { Some(BoundOrdering::Excluded( (start && v2 .pred() .and_then(|pred| U::min().map(|m| pred == m)) .unwrap_or(false)) || (!start && v2 .succ() .and_then(|succ| U::min().map(|m| succ == m)) .unwrap_or(false)), )) } } (Bound::Unbounded, Bound::Excluded(_)) => Some(BoundOrdering::Excluded(false)), (Bound::Unbounded, Bound::Unbounded) => Some(BoundOrdering::Included(true)), } } pub(crate) fn direct_bound_cmp(b1: Bound<&T>, b2: Bound<&T>, start: bool) -> BoundOrdering where T: Measure + PartialEnum + Ord, { let included_ord = if start { Ordering::Greater } else { Ordering::Less }; match (b1, b2) { (Bound::Included(v1), Bound::Included(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Included(true), ord if ord == included_ord => BoundOrdering::Included(false), _ => BoundOrdering::Excluded(distance_zero(v1, v2)), }, (Bound::Included(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Excluded(true), ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), _ => BoundOrdering::Excluded(false), }, (Bound::Included(v1), Bound::Unbounded) => BoundOrdering::Included( (start && Some(v1) == ::min().as_ref()) || (!start && Some(v1) == ::max().as_ref()), ), (Bound::Excluded(v1), Bound::Included(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Included(false), ord if ord == included_ord => BoundOrdering::Included(false), _ => match dist(v1, v2) { Dist::Zero => BoundOrdering::Included(true), Dist::One => BoundOrdering::Excluded(true), _ => BoundOrdering::Excluded(false), }, }, (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Included(true), ord if ord == included_ord => BoundOrdering::Included(false), _ => BoundOrdering::Excluded(distance_zero(v1, v2)), }, (Bound::Excluded(_), Bound::Unbounded) => BoundOrdering::Included(false), (Bound::Unbounded, Bound::Included(v2)) => { if (start && ::min().as_ref() == Some(v2)) || (!start && ::max().as_ref() == Some(v2)) { BoundOrdering::Included(true) } else { BoundOrdering::Excluded( (start && v2 .pred() .map(|pred| ::min() == Some(pred)) .unwrap_or(false)) || (!start && v2 .succ() .map(|succ| ::min() == Some(succ)) .unwrap_or(false)), ) } } (Bound::Unbounded, Bound::Excluded(_)) => BoundOrdering::Excluded(false), (Bound::Unbounded, Bound::Unbounded) => BoundOrdering::Included(true), } } pub(crate) fn direct_bound_partial_eq(b1: Bound<&T>, b2: Bound<&U>, start: bool) -> bool where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { match direct_bound_partial_cmp(b1, b2, start) { Some(BoundOrdering::Included(eq)) => eq, _ => false, } } // pub(crate) fn direct_bound_eq(b1: Bound<&T>, b2: Bound<&T>, start: bool) -> bool where T: Measure + Ord { // match direct_bound_cmp(b1, b2, start) { // BoundOrdering::Included(eq) => eq, // _ => false // } // } pub(crate) fn inverse_bound_partial_cmp( b1: Bound<&T>, b2: Bound<&U>, b2_start: bool, ) -> Option where T: Measure + PartialOrd + PartialEnum, U: PartialEnum, { let included_ord = if b2_start { Ordering::Greater } else { Ordering::Less }; match (b1, b2) { (Bound::Included(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), None => None, }, (Bound::Included(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), Some(ord) if ord == included_ord => { Some(BoundOrdering::Included(distance_zero(v1, v2))) } Some(_) => Some(BoundOrdering::Excluded(false)), None => None, }, (Bound::Included(_), Bound::Unbounded) => Some(BoundOrdering::Included(false)), (Bound::Excluded(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), // []v2=v1 Some(ord) if ord == included_ord => { Some(BoundOrdering::Included(distance_zero(v1, v2))) } Some(_) => Some(BoundOrdering::Excluded(false)), None => None, }, (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { Some(Ordering::Equal) => Some(BoundOrdering::Excluded(false)), Some(ord) if ord == included_ord => match dist(v1, v2) { Dist::Zero => Some(BoundOrdering::Excluded(true)), // v2 [] v1 Dist::One => Some(BoundOrdering::Included(true)), // v2 [ x ] v1 _ => Some(BoundOrdering::Included(false)), // v2 [ x .. y ] v1 }, Some(_) => Some(BoundOrdering::Excluded(false)), // ] v1 v2 [ None => None, }, (Bound::Excluded(v1), Bound::Unbounded) => { if (!b2_start && U::max().map(|m| *v1 == m).unwrap_or(false)) || (b2_start && U::min().map(|m| *v1 == m).unwrap_or(false)) { Some(BoundOrdering::Excluded(true)) } else { Some(BoundOrdering::Included( (!b2_start && v1 .pred() .map(|pred| U::min().map(|m| pred == m).unwrap_or(false)) .unwrap_or(false)) || (b2_start && v1 .succ() .map(|succ| U::max().map(|m| succ == m).unwrap_or(false)) .unwrap_or(false)), )) } } (Bound::Unbounded, Bound::Included(_)) => Some(BoundOrdering::Included(false)), (Bound::Unbounded, Bound::Excluded(v2)) => { if (!b2_start && U::min().map(|m| *v2 == m).unwrap_or(false)) || (b2_start && U::max().map(|m| *v2 == m).unwrap_or(false)) { Some(BoundOrdering::Excluded(true)) } else { Some(BoundOrdering::Included( (!b2_start && v2 .pred() .map(|pred| U::min().map(|m| pred == m).unwrap_or(false)) .unwrap_or(false)) || (b2_start && v2 .succ() .map(|succ| U::max().map(|m| succ == m).unwrap_or(false)) .unwrap_or(false)), )) } } (Bound::Unbounded, Bound::Unbounded) => Some(BoundOrdering::Included(false)), } } pub(crate) fn inverse_bound_cmp(b1: Bound<&T>, b2: Bound<&T>, b2_start: bool) -> BoundOrdering where T: Measure + Ord + PartialEnum, { let included_ord = if b2_start { Ordering::Greater } else { Ordering::Less }; match (b1, b2) { (Bound::Included(v1), Bound::Included(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Included(true), ord if ord == included_ord => BoundOrdering::Included(false), _ => BoundOrdering::Excluded(distance_zero(v1, v2)), }, (Bound::Included(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Excluded(true), ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), _ => BoundOrdering::Excluded(false), }, (Bound::Included(_), Bound::Unbounded) => BoundOrdering::Included(false), (Bound::Excluded(v1), Bound::Included(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Excluded(true), // []v2=v1 ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), _ => BoundOrdering::Excluded(false), }, (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { Ordering::Equal => BoundOrdering::Excluded(false), ord if ord == included_ord => match dist(v1, v2) { Dist::Zero => BoundOrdering::Excluded(true), // v2 [] v1 Dist::One => BoundOrdering::Included(true), // v2 [ x ] v1 _ => BoundOrdering::Included(false), // v2 [ x .. y ] v1 }, _ => BoundOrdering::Excluded(false), // ] v1 v2 [ }, (Bound::Excluded(v1), Bound::Unbounded) => { if (!b2_start && ::max() .map(|m| *v1 == m) .unwrap_or(false)) || (b2_start && ::min() .map(|m| *v1 == m) .unwrap_or(false)) { BoundOrdering::Excluded(true) } else { BoundOrdering::Included( (!b2_start && v1 .pred() .map(|pred| { ::min() .map(|m| pred == m) .unwrap_or(false) }) .unwrap_or(false)) || (b2_start && v1 .succ() .map(|succ| { ::max() .map(|m| succ == m) .unwrap_or(false) }) .unwrap_or(false)), ) } } (Bound::Unbounded, Bound::Included(_)) => BoundOrdering::Included(false), (Bound::Unbounded, Bound::Excluded(v2)) => { if (!b2_start && ::min() .map(|m| *v2 == m) .unwrap_or(false)) || (b2_start && ::max() .map(|m| *v2 == m) .unwrap_or(false)) { BoundOrdering::Excluded(true) } else { BoundOrdering::Included( (!b2_start && v2 .pred() .map(|pred| { ::min() .map(|m| pred == m) .unwrap_or(false) }) .unwrap_or(false)) || (b2_start && v2 .succ() .map(|succ| { ::max() .map(|m| succ == m) .unwrap_or(false) }) .unwrap_or(false)), ) } } (Bound::Unbounded, Bound::Unbounded) => BoundOrdering::Included(false), } } // fn inverse_bound_partial_eq(b1: Bound<&T>, b2: Bound<&U>, start: bool) -> bool where T: Measure + PartialOrd { // match inverse_bound_partial_cmp(b1, b2, start) { // Some(BoundOrdering::Included(eq)) => eq, // _ => false // } // } btree-range-map-0.7.2/src/range.rs000064400000000000000000000436761046102023000150510ustar 00000000000000pub use range_traits::{Measure, PartialEnum}; use std::{ cmp::PartialOrd, ops::{Bound, RangeBounds}, }; mod bound; mod ordering; mod any; mod from_excluded; mod from_excluded_to; mod from_excluded_to_included; pub use any::*; pub use bound::*; pub use from_excluded::*; pub use from_excluded_to::*; pub use from_excluded_to_included::*; pub use ordering::*; /// Types that can be interpreted as ranges. pub trait AsRange: Sized { /// Type of the elements of the range. type Item: Measure + PartialEnum; /// Start bound of the range. fn start(&self) -> Bound<&Self::Item>; /// End bound of the range. fn end(&self) -> Bound<&Self::Item>; fn is_empty(&self) -> bool { is_range_empty(self.start(), self.end()) } fn intersects(&self, other: &R) -> bool where Self::Item: PartialOrd + Measure, { matches!( self.range_partial_cmp(other), Some(RangeOrdering::Intersecting(_, _)) ) } fn connected_to(&self, other: &R) -> bool where Self::Item: PartialOrd + Measure, { match self.range_partial_cmp(other) { Some(RangeOrdering::Intersecting(_, _)) => true, Some(RangeOrdering::Before(connected)) => connected, Some(RangeOrdering::After(connected)) => connected, _ => false, } } fn intersected_with<'a, R: AsRange>( &'a self, other: &'a R, ) -> AnyRange<&'a Self::Item> where Self::Item: PartialOrd + Measure, { AnyRange { start: max_bound(self.start(), other.start(), true), end: min_bound(self.end(), other.end(), false), } } fn without<'a, R: AsRange>( &'a self, other: &'a R, ) -> Difference<&'a Self::Item> where Self::Item: PartialOrd + Measure, { let left = match invert_bound(other.start()) { Some(inverted_other_start) => { if !is_range_empty(self.start(), inverted_other_start) { Some(AnyRange { start: self.start(), end: inverted_other_start, }) } else { None } } None => None, }; let right = match invert_bound(other.end()) { Some(inverted_other_end) => { if !is_range_empty(inverted_other_end, self.end()) { Some(AnyRange { start: inverted_other_end, end: self.end(), }) } else { None } } None => None, }; match (left, right) { (Some(left), None) => Difference::Before( left, Directed::End(left.end) >= Directed::Start(other.start()), ), (None, Some(right)) => Difference::After( right, Directed::Start(right.start) <= Directed::End(other.end()), ), (Some(left), Some(right)) => Difference::Split(left, right), (None, None) => Difference::Empty, } } fn product<'a, R: AsRange>(&'a self, other: &'a R) -> Product<&'a Self::Item> where Self::Item: PartialOrd + Measure, { let before = match crop_right(self, other.start()) { Some(self_before) => Some(ProductArg::Subject(self_before)), None => crop_right(other, self.start()).map(ProductArg::Object), }; let intersection = self.intersected_with(other); let intersection = if is_range_empty(intersection.start, intersection.end) { None } else { Some(intersection) }; let after = match crop_left(self, other.end()) { Some(self_after) => Some(ProductArg::Subject(self_after)), None => crop_left(other, self.end()).map(ProductArg::Object), }; Product { before, intersection, after, } } } pub trait IntoRange: AsRange { fn into_range(self) -> AnyRange; } fn crop_left<'a, R: AsRange>( range: &'a R, other_end: Bound<&'a R::Item>, ) -> Option> { match invert_bound(other_end) { Some(inverted_other_end) => { let max_start = max_bound(range.start(), inverted_other_end, true); if !is_range_empty(max_start, range.end()) { Some(AnyRange { start: inverted_other_end, end: range.end(), }) } else { None } } None => None, } } fn crop_right<'a, R: AsRange>( range: &'a R, other_start: Bound<&'a R::Item>, ) -> Option> { match invert_bound(other_start) { Some(inverted_other_start) => { let min_end = min_bound(range.end(), inverted_other_start, false); if !is_range_empty(range.start(), min_end) { Some(AnyRange { start: range.start(), end: min_end, }) } else { None } } None => None, } } /// Part of the result of a `product` operation. pub enum ProductArg { /// A part of the subject, `self`. Subject(AnyRange), /// A part of the object, `other`. Object(AnyRange), } impl<'a, T: Clone> ProductArg<&'a T> { pub fn cloned(&self) -> ProductArg { match self { ProductArg::Subject(range) => ProductArg::Subject(range.cloned()), ProductArg::Object(range) => ProductArg::Object(range.cloned()), } } } /// Result of a `product` operation. pub struct Product { /// What is left of `self` and `other` before their intersection. pub before: Option>, /// The intersection of `self` and `other`, if not empty. pub intersection: Option>, /// What is left of `self` and `other` after their intersection. pub after: Option>, } impl<'a, T: Clone> Product<&'a T> { pub fn cloned(&self) -> Product { Product { before: self.before.as_ref().map(|r| r.cloned()), intersection: self.intersection.as_ref().map(|r| r.cloned()), after: self.after.as_ref().map(|r| r.cloned()), } } } pub enum RelativePosition { Before, After, } /// Result of a `without` operation. pub enum Difference { /// The end of the range may intersects `other`. The boolean is set to true if it does. Before(AnyRange, bool), /// The begining of the range may intersects `other`. The boolean is set to true if it does. After(AnyRange, bool), /// The `other` range if fully included. Split(AnyRange, AnyRange), /// The range is fully included in `other`. Empty, } macro_rules! singleton_range { ($ty:ident) => { impl AsRange for $ty { type Item = Self; fn start(&self) -> Bound<&Self::Item> { Bound::Included(self) } fn end(&self) -> Bound<&Self::Item> { Bound::Included(self) } } impl IntoRange for $ty { fn into_range(self) -> AnyRange { AnyRange::new(Bound::Included(self), Bound::Included(self)) } } }; } singleton_range!(u8); singleton_range!(i8); singleton_range!(u16); singleton_range!(i16); singleton_range!(u32); singleton_range!(i32); singleton_range!(u64); singleton_range!(i64); // singleton_range!(u128); // singleton_range!(i128); singleton_range!(usize); // singleton_range!(isize); singleton_range!(f32); singleton_range!(f64); singleton_range!(char); macro_rules! standard_range { ($ty:path, |$this:ident| $into_range:expr) => { impl AsRange for $ty { type Item = T; fn start(&self) -> Bound<&Self::Item> { self.start_bound() } fn end(&self) -> Bound<&Self::Item> { self.end_bound() } } impl IntoRange for $ty { fn into_range($this) -> AnyRange { $into_range } } }; } standard_range!(std::ops::Range, |self| AnyRange::new( Bound::Included(self.start), Bound::Excluded(self.end) )); standard_range!(std::ops::RangeInclusive, |self| { let (a, b) = self.into_inner(); AnyRange::new(Bound::Included(a), Bound::Included(b)) }); standard_range!(std::ops::RangeFrom, |self| AnyRange::new( Bound::Included(self.start), Bound::Unbounded )); standard_range!(std::ops::RangeTo, |self| AnyRange::new( Bound::Unbounded, Bound::Excluded(self.end) )); standard_range!(std::ops::RangeToInclusive, |self| AnyRange::new( Bound::Unbounded, Bound::Included(self.end) )); standard_range!(AnyRange, |self| self); standard_range!(RangeFromExcluded, |self| AnyRange::new( Bound::Excluded(self.start), Bound::Unbounded )); standard_range!(RangeFromExcludedTo, |self| AnyRange::new( Bound::Excluded(self.start), Bound::Excluded(self.end) )); standard_range!(RangeFromExcludedToIncluded, |self| AnyRange::new( Bound::Excluded(self.start), Bound::Included(self.end) )); #[inline(always)] fn is_range_empty(start: Bound<&T>, end: Bound<&U>) -> bool where T: PartialOrd + Measure + PartialEnum, U: PartialEnum, { Directed::Start(start) > Directed::End(end) } #[cfg(test)] mod tests { use crate::RangeSet; use super::*; use std::cmp::Ordering; macro_rules! make_bound { ([= $v:literal ..]) => { Directed::Start(Bound::Included(&$v)) }; ([$v:literal ..]) => { Directed::Start(Bound::Excluded(&$v)) }; ([~ ..]) => { Directed::Start(Bound::Unbounded) }; ([..= $v:literal]) => { Directed::End(Bound::Included(&$v)) }; ([.. $v:literal]) => { Directed::End(Bound::Excluded(&$v)) }; ([.. ~]) => { Directed::End(Bound::Unbounded) }; } macro_rules! test_bound_cmp { (@assert $ty:ty, $a:tt, $b:tt, $expected:ident) => { assert_eq!(> as PartialOrd>::partial_cmp(&make_bound!($a), &make_bound!($b)), Some(Ordering::$expected)); }; ($ty:ty, $a:tt < $b:tt) => { test_bound_cmp!(@assert $ty, $a, $b, Less) }; ($ty:ty, $a:tt == $b:tt) => { test_bound_cmp!(@assert $ty, $a, $b, Equal) }; ($ty:ty, $a:tt > $b:tt) => { test_bound_cmp!(@assert $ty, $a, $b, Greater) } } #[test] fn issue_2() { let k = AnyRange { start: Bound::Excluded(0u32), end: Bound::Unbounded, }; assert!(!k.is_empty()); let mut ids: RangeSet = RangeSet::new(); ids.insert(0u32); let mut gaps = ids.gaps(); assert_eq!( gaps.next().unwrap().cloned(), AnyRange::new(Bound::Excluded(0), Bound::Unbounded) ); assert_eq!(gaps.next().map(AnyRange::cloned), None); } #[test] fn unsigned_integer_bound_partial_less() { test_bound_cmp!(u32, [=0..] < [=1..]); test_bound_cmp!(u32, [=0..] < [0..]); test_bound_cmp!(u32, [=0..] < [..=1]); test_bound_cmp!(u32, [=0..] < [..2]); test_bound_cmp!(u32, [=0..] < [..~]); test_bound_cmp!(u32, [0..] < [=2..]); test_bound_cmp!(u32, [0..] < [1..]); test_bound_cmp!(u32, [0..] < [..=2]); test_bound_cmp!(u32, [0..] < [..3]); test_bound_cmp!(u32, [0..] < [..~]); test_bound_cmp!(u32, [~..] < [..=0]); test_bound_cmp!(u32, [~..] < [..~]); test_bound_cmp!(u32, [..=0] < [=1..]); test_bound_cmp!(u32, [..=0] < [0..]); test_bound_cmp!(u32, [..=0] < [..=1]); test_bound_cmp!(u32, [..=0] < [..2]); test_bound_cmp!(u32, [..=0] < [..~]); test_bound_cmp!(u32, [..1] < [=1..]); test_bound_cmp!(u32, [..1] < [0..]); test_bound_cmp!(u32, [..1] < [..=1]); test_bound_cmp!(u32, [..1] < [..2]); test_bound_cmp!(u32, [..0] < [..~]); } #[test] fn unsigned_integer_bound_partial_eq() { test_bound_cmp!(u32, [~..] == [=0..]); } #[test] fn unsigned_integer_bound_partial_greater() { test_bound_cmp!(u32, [~..] > [..0]); } #[test] fn integer_bound_partial_less() { test_bound_cmp!(i32, [=0..] < [=1..]); test_bound_cmp!(i32, [=0..] < [0..]); test_bound_cmp!(i32, [=0..] < [..=1]); test_bound_cmp!(i32, [=0..] < [..2]); test_bound_cmp!(i32, [=0..] < [..~]); test_bound_cmp!(i32, [0..] < [=2..]); test_bound_cmp!(i32, [0..] < [1..]); test_bound_cmp!(i32, [0..] < [..=2]); test_bound_cmp!(i32, [0..] < [..3]); test_bound_cmp!(i32, [0..] < [..~]); test_bound_cmp!(i32, [-2_147_483_648i32..] < [..~]); test_bound_cmp!(i32, [~..] < [=0..]); test_bound_cmp!(i32, [~..] < [..=0]); test_bound_cmp!(i32, [~..] < [..0]); test_bound_cmp!(i32, [~..] < [..~]); test_bound_cmp!(i32, [..=0] < [=1..]); test_bound_cmp!(i32, [..=0] < [0..]); test_bound_cmp!(i32, [..=0] < [..=1]); test_bound_cmp!(i32, [..=0] < [..2]); test_bound_cmp!(i32, [..=0] < [..~]); test_bound_cmp!(i32, [..1] < [=1..]); test_bound_cmp!(i32, [..1] < [0..]); test_bound_cmp!(i32, [..1] < [..=1]); test_bound_cmp!(i32, [..1] < [..2]); test_bound_cmp!(i32, [..0] < [..~]); } #[test] fn integer_bound_partial_eq() { test_bound_cmp!(i32, [=0..] == [=0..]); test_bound_cmp!(i32, [=1..] == [0..]); test_bound_cmp!(i32, [=0..] == [..=0]); test_bound_cmp!(i32, [=0..] == [..1]); test_bound_cmp!(i32, [0..] == [=1..]); test_bound_cmp!(i32, [0..] == [0..]); test_bound_cmp!(i32, [0..] == [..=1]); test_bound_cmp!(i32, [0..] == [..2]); test_bound_cmp!(i32, [~..] == [~..]); test_bound_cmp!(i32, [..=0] == [=0..]); test_bound_cmp!(i32, [..=1] == [0..]); test_bound_cmp!(i32, [..=0] == [..=0]); test_bound_cmp!(i32, [..=0] == [..1]); test_bound_cmp!(i32, [..1] == [=0..]); test_bound_cmp!(i32, [..2] == [0..]); test_bound_cmp!(i32, [..1] == [..=0]); test_bound_cmp!(i32, [..0] == [..0]); test_bound_cmp!(i32, [..~] == [..~]); } #[test] fn integer_bound_partial_greater() { test_bound_cmp!(i32, [=1..] > [=0..]); test_bound_cmp!(i32, [0..] > [=0..]); test_bound_cmp!(i32, [..=1] > [=0..]); test_bound_cmp!(i32, [..2] > [=0..]); test_bound_cmp!(i32, [..~] > [=0..]); test_bound_cmp!(i32, [=2..] > [0..]); test_bound_cmp!(i32, [1..] > [0..]); test_bound_cmp!(i32, [..=2] > [0..]); test_bound_cmp!(i32, [..3] > [0..]); test_bound_cmp!(i32, [..~] > [0..]); test_bound_cmp!(i32, [=0..] > [~..]); test_bound_cmp!(i32, [..=0] > [~..]); test_bound_cmp!(i32, [..0] > [~..]); test_bound_cmp!(i32, [..~] > [~..]); test_bound_cmp!(i32, [=1..] > [..=0]); test_bound_cmp!(i32, [0..] > [..=0]); test_bound_cmp!(i32, [..=1] > [..=0]); test_bound_cmp!(i32, [..2] > [..=0]); test_bound_cmp!(i32, [..~] > [..=0]); test_bound_cmp!(i32, [=1..] > [..1]); test_bound_cmp!(i32, [0..] > [..1]); test_bound_cmp!(i32, [..=1] > [..1]); test_bound_cmp!(i32, [..2] > [..1]); test_bound_cmp!(i32, [..~] > [..0]); } #[test] fn float_bound_partial_less() { test_bound_cmp!(f32, [=0.0..] < [=1.0..]); test_bound_cmp!(f32, [=0.0..] < [0.0..]); test_bound_cmp!(f32, [=0.0..] < [..=1.0]); test_bound_cmp!(f32, [=0.0..] < [..2.0]); test_bound_cmp!(f32, [=0.0..] < [..~]); test_bound_cmp!(f32, [0.0..] < [=2.0..]); test_bound_cmp!(f32, [0.0..] < [1.0..]); test_bound_cmp!(f32, [0.0..] < [..1.0]); // different from the int behavior test_bound_cmp!(f32, [0.0..] < [..=2.0]); test_bound_cmp!(f32, [0.0..] < [..3.0]); test_bound_cmp!(f32, [0.0..] < [..~]); test_bound_cmp!(f32, [~..] < [=0.0..]); test_bound_cmp!(f32, [~..] < [..=0.0]); test_bound_cmp!(f32, [~..] < [..0.0]); test_bound_cmp!(f32, [~..] < [..~]); test_bound_cmp!(f32, [..=0.0] < [=1.0..]); test_bound_cmp!(f32, [..=0.0] < [0.0..]); test_bound_cmp!(f32, [..=0.0] < [..=1.0]); test_bound_cmp!(f32, [..=0.0] < [..2.0]); test_bound_cmp!(f32, [..=0.0] < [..~]); test_bound_cmp!(f32, [..1.0] < [=1.0..]); test_bound_cmp!(f32, [..1.0] < [1.0..]); test_bound_cmp!(f32, [..1.0] < [..=1.0]); test_bound_cmp!(f32, [..1.0] < [..2.0]); test_bound_cmp!(f32, [..0.0] < [..~]); } #[test] fn float_bound_partial_eq() { test_bound_cmp!(f32, [=0.0..] == [=0.0..]); test_bound_cmp!(f32, [=1.0..] > [0.0..]); // different from the int behavior test_bound_cmp!(f32, [=0.0..] == [..=0.0]); test_bound_cmp!(f32, [=0.0..] < [..1.0]); // different from the int behavior test_bound_cmp!(f32, [0.0..] < [=1.0..]); // different from the int behavior test_bound_cmp!(f32, [0.0..] == [0.0..]); test_bound_cmp!(f32, [0.0..] < [..=1.0]); // different from the int behavior test_bound_cmp!(f32, [0.0..] < [..2.0]); // different from the int behavior test_bound_cmp!(f32, [~..] == [~..]); test_bound_cmp!(f32, [..=0.0] == [=0.0..]); test_bound_cmp!(f32, [..=1.0] > [0.0..]); // different from the int behavior test_bound_cmp!(f32, [..=0.0] == [..=0.0]); test_bound_cmp!(f32, [..=0.0] < [..1.0]); // different from the int behavior test_bound_cmp!(f32, [..1.0] > [=0.0..]); // different from the int behavior test_bound_cmp!(f32, [..2.0] > [0.0..]); // different from the int behavior test_bound_cmp!(f32, [..1.0] > [..=0.0]); // different from the int behavior test_bound_cmp!(f32, [..0.0] == [..0.0]); test_bound_cmp!(f32, [..~] == [..~]); } #[test] fn float_bound_partial_greater() { test_bound_cmp!(f32, [=1.0..] > [=0.0..]); test_bound_cmp!(f32, [0.0..] > [=0.0..]); test_bound_cmp!(f32, [..=1.0] > [=0.0..]); test_bound_cmp!(f32, [..2.0] > [=0.0..]); test_bound_cmp!(f32, [..~] > [=0.0..]); test_bound_cmp!(f32, [=2.0..] > [0.0..]); test_bound_cmp!(f32, [1.0..] > [0.0..]); test_bound_cmp!(f32, [..1.0] > [0.0..]); // different from the int behavior test_bound_cmp!(f32, [..=2.0] > [0.0..]); test_bound_cmp!(f32, [..3.0] > [0.0..]); test_bound_cmp!(f32, [..~] > [0.0..]); test_bound_cmp!(f32, [=0.0..] > [~..]); test_bound_cmp!(f32, [..=0.0] > [~..]); test_bound_cmp!(f32, [..0.0] > [~..]); test_bound_cmp!(f32, [..~] > [~..]); test_bound_cmp!(f32, [=1.0..] > [..=0.0]); test_bound_cmp!(f32, [0.0..] > [..=0.0]); test_bound_cmp!(f32, [..=1.0] > [..=0.0]); test_bound_cmp!(f32, [..2.0] > [..=0.0]); test_bound_cmp!(f32, [..~] > [..=0.0]); test_bound_cmp!(f32, [=1.0..] > [..1.0]); test_bound_cmp!(f32, [1.0..] > [..1.0]); test_bound_cmp!(f32, [..=1.0] > [..1.0]); test_bound_cmp!(f32, [..2.0] > [..1.0]); test_bound_cmp!(f32, [..~] > [..0.0]); } #[test] fn int_intersection() { assert!((0..10).intersects(&(5..100))); } // Intersecting ranges are connected. #[test] fn int_connected_intersection() { assert!((0..10).connected_to(&(5..100))); } #[test] fn int_connected() { assert!((0..10).connected_to(&(10..20))); assert!((10..20).connected_to(&(0..10))); assert!((0..=10).connected_to(&(RangeFromExcludedTo::new(10, 20)))); } #[test] fn int_disconnected() { assert!(!(0..10).connected_to(&(11..20))); assert!(!(11..20).connected_to(&(0..10))); assert!(!(0..10).connected_to(&(RangeFromExcludedTo::new(10, 20)))); } #[test] fn float_connected() { assert!((0.0..10.0).connected_to(&(10.0..20.0))); assert!((0.0..=10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); } #[test] fn float_disconnected() { assert!(!(0.0..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); assert!(!(..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); assert!(!(0.0..10.0).connected_to(&(RangeFromExcluded::new(10.0)))); assert!(!(..10.0).connected_to(&(RangeFromExcluded::new(10.0)))); } } btree-range-map-0.7.2/src/serde.rs000064400000000000000000000107411046102023000150420ustar 00000000000000use std::marker::PhantomData; use btree_slab::generic::Node; use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; use range_traits::{Measure, PartialEnum}; use serde::{ de::Error, ser::{SerializeMap, SerializeSeq, SerializeTuple}, Deserialize, Serialize, }; use crate::{generic, AnyRange}; impl Serialize for AnyRange { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let mut t = serializer.serialize_tuple(2)?; t.serialize_element(&self.start)?; t.serialize_element(&self.end)?; t.end() } } impl<'de, T: Deserialize<'de>> Deserialize<'de> for AnyRange { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct Visitor(PhantomData); impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for Visitor { type Value = AnyRange; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "any range") } fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { let start = seq .next_element()? .ok_or_else(|| A::Error::custom("missing start bound"))?; let end = seq .next_element()? .ok_or_else(|| A::Error::custom("missing end bound"))?; Ok(AnyRange { start, end }) } } deserializer.deserialize_tuple(2, Visitor(PhantomData)) } } impl, ()>>> Serialize for generic::RangeSet { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let mut seq = serializer.serialize_seq(Some(self.range_count()))?; for range in self { seq.serialize_element(range)?; } seq.end() } } impl< 'de, T: Clone + PartialEnum + Measure + Deserialize<'de>, C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, ()>>, > Deserialize<'de> for generic::RangeSet { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct Visitor(PhantomData<(T, C)>); impl< 'de, T: Clone + PartialEnum + Measure + Deserialize<'de>, C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, ()>>, > serde::de::Visitor<'de> for Visitor { type Value = generic::RangeSet; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a range set") } fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { let mut result = generic::RangeSet::new(); while let Some(range) = seq.next_element::>()? { result.insert(range); } Ok(result) } } deserializer.deserialize_seq(Visitor(PhantomData)) } } impl, V>>> Serialize for generic::RangeMap { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let mut map = serializer.serialize_map(Some(self.range_count()))?; for (range, value) in self { map.serialize_entry(range, value)?; } map.end() } } impl< 'de, K: PartialEnum + Measure + Deserialize<'de>, V: Deserialize<'de>, C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, V>>, > Deserialize<'de> for generic::RangeMap { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct Visitor(PhantomData<(K, V, C)>); impl< 'de, K: PartialEnum + Measure + Deserialize<'de>, V: Deserialize<'de>, C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, V>>, > serde::de::Visitor<'de> for Visitor { type Value = generic::RangeMap; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a range map") } fn visit_map(self, mut map: A) -> Result where A: serde::de::MapAccess<'de>, { let mut result = generic::RangeMap::new(); while let Some((range, value)) = map.next_entry::, V>()? { if result.insert_disconnected(range, value).is_err() { return Err(A::Error::custom("unexpected connected range")); } } Ok(result) } } deserializer.deserialize_map(Visitor(PhantomData)) } } btree-range-map-0.7.2/tests/insert.rs000064400000000000000000000205611046102023000156200ustar 00000000000000use btree_range_map::{RangeMap, RangeSet}; #[test] fn insert_single() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..05, true); assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(02), Some(&true)); } /// Testing case (G) only. #[test] fn insert_exclusive_ranges() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..05, true); range_map.insert(10..15, false); range_map.insert(20..25, true); range_map.insert(30..35, false); range_map.insert(40..45, true); range_map.insert(50..55, false); range_map.insert(60..65, true); range_map.insert(70..75, false); range_map.insert(80..85, true); range_map.insert(90..95, false); assert_eq!(range_map.range_count(), 10); assert_eq!(range_map.get(02), Some(&true)); assert_eq!(range_map.get(07), None); assert_eq!(range_map.get(12), Some(&false)); assert_eq!(range_map.get(17), None); assert_eq!(range_map.get(22), Some(&true)); assert_eq!(range_map.get(27), None); assert_eq!(range_map.get(32), Some(&false)); assert_eq!(range_map.get(37), None); assert_eq!(range_map.get(42), Some(&true)); assert_eq!(range_map.get(47), None); assert_eq!(range_map.get(52), Some(&false)); assert_eq!(range_map.get(57), None); assert_eq!(range_map.get(62), Some(&true)); assert_eq!(range_map.get(67), None); assert_eq!(range_map.get(72), Some(&false)); assert_eq!(range_map.get(77), None); assert_eq!(range_map.get(82), Some(&true)); assert_eq!(range_map.get(87), None); assert_eq!(range_map.get(92), Some(&false)); assert_eq!(range_map.get(97), None); } #[test] fn insert_inclusive_ranges_a() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..20, true); // case (G) range_map.insert(05..15, false); // case (A) assert_eq!(range_map.range_count(), 3); assert_eq!(range_map.get(00), Some(&true)); assert_eq!(range_map.get(04), Some(&true)); assert_eq!(range_map.get(05), Some(&false)); assert_eq!(range_map.get(14), Some(&false)); assert_eq!(range_map.get(19), Some(&true)); assert_eq!(range_map.get(20), None); } #[test] fn insert_inclusive_ranges_b() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..20, true); // case (G) range_map.insert(10..30, false); // case (B) assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(00), Some(&true)); assert_eq!(range_map.get(09), Some(&true)); assert_eq!(range_map.get(10), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(29), Some(&false)); assert_eq!(range_map.get(30), None); } #[test] fn insert_inclusive_ranges_ce() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(10..30, true); // case (G) range_map.insert(00..20, false); // cases (C) and (E) assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(00), Some(&false)); assert_eq!(range_map.get(09), Some(&false)); assert_eq!(range_map.get(10), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(20), Some(&true)); assert_eq!(range_map.get(29), Some(&true)); assert_eq!(range_map.get(30), None); } #[test] fn insert_inclusive_ranges_bcd() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(10..15, true); // case (G) range_map.insert(20..25, true); // case (G) range_map.insert(30..35, true); // case (G) range_map.insert(10..35, false); // case (B, C, D) assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(10), Some(&false)); assert_eq!(range_map.get(14), Some(&false)); assert_eq!(range_map.get(17), Some(&false)); assert_eq!(range_map.get(20), Some(&false)); assert_eq!(range_map.get(24), Some(&false)); assert_eq!(range_map.get(27), Some(&false)); assert_eq!(range_map.get(30), Some(&false)); assert_eq!(range_map.get(34), Some(&false)); assert_eq!(range_map.get(35), None); } #[test] fn insert_inclusive_ranges_cf() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..10, true); // case (G) range_map.insert(20..30, true); // case (G) range_map.insert(15..25, false); // case (C, F) assert_eq!(range_map.range_count(), 3); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(9), Some(&true)); assert_eq!(range_map.get(10), None); assert_eq!(range_map.get(15), Some(&false)); assert_eq!(range_map.get(24), Some(&false)); assert_eq!(range_map.get(25), Some(&true)); assert_eq!(range_map.get(29), Some(&true)); assert_eq!(range_map.get(30), None); } #[test] fn insert_merge_ranges() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..10, true); range_map.insert(10..20, true); assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(19), Some(&true)); assert_eq!(range_map.get(20), None); } #[test] fn insert_merge_ranges2() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..10, true); range_map.insert(10..20, false); range_map.insert(10..15, true); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(9), Some(&true)); assert_eq!(range_map.get(10), Some(&true)); assert_eq!(range_map.get(14), Some(&true)); assert_eq!(range_map.get(15), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(20), None); } #[test] fn update_merge_ranges() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..10, true); range_map.update(10..20, |_| Some(true)); assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(19), Some(&true)); assert_eq!(range_map.get(20), None); } #[test] fn update_merge_ranges2() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..10, true); range_map.insert(10..20, false); range_map.update(10..15, |_| Some(true)); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(9), Some(&true)); assert_eq!(range_map.get(10), Some(&true)); assert_eq!(range_map.get(14), Some(&true)); assert_eq!(range_map.get(15), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(20), None); } #[test] fn insert_merge_ranges_rev() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(10..20, true); range_map.insert(00..10, true); assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(19), Some(&true)); assert_eq!(range_map.get(20), None); } #[test] fn insert_merge_ranges_rev2() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..10, true); range_map.insert(10..20, false); range_map.insert(5..10, false); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(4), Some(&true)); assert_eq!(range_map.get(5), Some(&false)); assert_eq!(range_map.get(9), Some(&false)); assert_eq!(range_map.get(10), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(20), None); } #[test] fn update_merge_ranges_rev() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(10..20, true); range_map.update(0..10, |_| Some(true)); assert_eq!(range_map.range_count(), 1); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(19), Some(&true)); assert_eq!(range_map.get(20), None); } #[test] fn update_merge_ranges_rev2() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..10, true); range_map.insert(10..20, false); range_map.update(5..10, |_| Some(false)); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(4), Some(&true)); assert_eq!(range_map.get(5), Some(&false)); assert_eq!(range_map.get(9), Some(&false)); assert_eq!(range_map.get(10), Some(&false)); assert_eq!(range_map.get(19), Some(&false)); assert_eq!(range_map.get(20), None); } #[test] fn insert_chars() { let mut charset = RangeSet::new(); charset.insert('c'); charset.insert('a'); charset.insert('b'); assert_eq!(charset.range_count(), 1); assert_eq!(charset.len(), 3); } #[test] fn insert_chars2() { let mut charset = RangeSet::new(); charset.insert('%'); charset.insert('$'); assert_eq!(charset.range_count(), 1); assert_eq!(charset.len(), 2); assert!(charset.contains('%')); assert!(charset.contains('$')) } btree-range-map-0.7.2/tests/remove.rs000064400000000000000000000006461046102023000156130ustar 00000000000000use btree_range_map::RangeMap; #[test] fn remove_range() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(00..10, true); range_map.remove(1..9); assert_eq!(range_map.range_count(), 2); assert_eq!(range_map.get(0), Some(&true)); assert_eq!(range_map.get(1), None); assert_eq!(range_map.get(8), None); assert_eq!(range_map.get(9), Some(&true)); assert_eq!(range_map.get(10), None); }