├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .rustfmt.toml ├── .vscode ├── launch.json └── settings.json ├── Cargo.toml ├── README.md ├── README.tpl ├── src ├── generic │ ├── map.rs │ ├── mod.rs │ ├── multimap.rs │ └── set.rs ├── lib.rs ├── range.rs ├── range │ ├── any.rs │ ├── bound.rs │ ├── from_excluded.rs │ ├── from_excluded_to.rs │ ├── from_excluded_to_included.rs │ └── ordering.rs └── serde.rs └── tests ├── insert.rs └── remove.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: thaudebourg 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLORS: always 7 | 8 | jobs: 9 | test: 10 | name: Test Suite 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: Install Rust 16 | uses: actions-rs/toolchain@v1 17 | with: 18 | toolchain: nightly 19 | profile: minimal 20 | override: true 21 | - name: Build 22 | run: cargo build --all-features --verbose 23 | - name: Run tests 24 | run: cargo test --all-features --verbose 25 | rustfmt: 26 | name: rustfmt 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v2 31 | - name: Install Rust 32 | uses: actions-rs/toolchain@v1 33 | with: 34 | toolchain: nightly 35 | profile: minimal 36 | override: true 37 | components: rustfmt 38 | - name: Check formatting 39 | uses: actions-rs/cargo@v1 40 | with: 41 | command: fmt 42 | args: --all -- --check 43 | clippy: 44 | name: clippy 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Checkout repository 48 | uses: actions/checkout@v2 49 | - name: Install Rust 50 | uses: actions-rs/toolchain@v1 51 | with: 52 | toolchain: nightly 53 | profile: minimal 54 | override: true 55 | components: clippy 56 | - name: Clippy Check 57 | uses: actions-rs/cargo@v1 58 | with: 59 | command: clippy 60 | args: --all-features -- -D warnings -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | hard_tabs = true -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug unit tests in library 'btree-range-map'", 11 | "cargo": { 12 | "args": [ 13 | "test", 14 | "--no-run", 15 | "--lib", 16 | "--package=btree-range-map" 17 | ], 18 | "filter": { 19 | "name": "btree-range-map", 20 | "kind": "lib" 21 | } 22 | }, 23 | "args": [], 24 | "cwd": "${workspaceFolder}" 25 | }, 26 | { 27 | "type": "lldb", 28 | "request": "launch", 29 | "name": "Debug integration test 'insert'", 30 | "cargo": { 31 | "args": [ 32 | "test", 33 | "--no-run", 34 | "--test=insert", 35 | "--package=btree-range-map" 36 | ], 37 | "filter": { 38 | "name": "insert", 39 | "kind": "test" 40 | } 41 | }, 42 | "args": [], 43 | "cwd": "${workspaceFolder}" 44 | }, 45 | { 46 | "type": "lldb", 47 | "request": "launch", 48 | "name": "Debug integration test 'remove'", 49 | "cargo": { 50 | "args": [ 51 | "test", 52 | "--no-run", 53 | "--test=remove", 54 | "--package=btree-range-map" 55 | ], 56 | "filter": { 57 | "name": "remove", 58 | "kind": "test" 59 | } 60 | }, 61 | "args": [], 62 | "cwd": "${workspaceFolder}" 63 | } 64 | ] 65 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "lldb.showDisassembly": "auto", 3 | "lldb.dereferencePointers": true 4 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "btree-range-map" 3 | version = "0.7.2" 4 | authors = ["Timothée Haudebourg "] 5 | edition = "2021" 6 | 7 | categories = ["data-structures"] 8 | keywords = ["btree", "range", "map", "set"] 9 | description = "B-tree range map implementation" 10 | repository = "https://github.com/timothee-haudebourg/btree-range-map" 11 | documentation = "https://docs.rs/btree-range-map" 12 | license = "MIT/Apache-2.0" 13 | readme = "README.md" 14 | 15 | [dependencies] 16 | cc-traits = "2.0.0" 17 | btree-slab = "0.6" 18 | slab = "0.4.5" 19 | range-traits = "0.3.0" 20 | ordered-float = { version = "3.0.0", optional = true } 21 | serde = { version = "1.0", optional = true } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # B-Tree range map 2 | 3 | [![CI](https://github.com/timothee-haudebourg/btree-range-map/workflows/CI/badge.svg)](https://github.com/timothee-haudebourg/btree-range-map/actions) 4 | [![Crate informations](https://img.shields.io/crates/v/btree-range-map.svg?style=flat-square)](https://crates.io/crates/btree-range-map) 5 | [![License](https://img.shields.io/crates/l/btree-range-map.svg?style=flat-square)](https://github.com/timothee-haudebourg/btree-range-map#license) 6 | [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square)](https://docs.rs/btree-range-map) 7 | 8 | A *range map* is a map where keys are aggregated into ranges of keys for 9 | efficient storage. Every time you need to store a large number numeric-keyed 10 | items in a map or set, a range map (or range set) should be used. 11 | 12 | This library provides a range map implementation based on 13 | [`btree-slab`](https://crates.io/crates/btree-slab)'s B-tree. 14 | It defines three basic types `RangeSet`, `RangeMap` and 15 | `RangeMultiMap`. 16 | 17 | ### Usage 18 | 19 | The `RangeSet` and `RangeMap` behave similarly to the standard 20 | `BTreeSet` and `BTreeMap` types. 21 | However in addition to `PartialOrd`, the key type must also implement the 22 | `Measure` trait defining how keys are merged into ranges. 23 | This trait is implemented by default for `char`, integer types and float 24 | types. 25 | 26 | ```rust 27 | use btree_range_map::RangeMap; 28 | 29 | let mut range_map: RangeMap = RangeMap::new(); 30 | range_map.insert(00..=05, true); 31 | range_map.insert(4, false); 32 | assert_eq!(range_map.range_count(), 3); 33 | assert_eq!(range_map.get(03), Some(&true)); 34 | assert_eq!(range_map.get(04), Some(&false)); 35 | assert_eq!(range_map.get(05), Some(&true)); 36 | ``` 37 | 38 | This library supports included and excluded bounds: 39 | 40 | ```rust 41 | range_map.insert(..1, true); 42 | range_map.insert(..=1, true); 43 | range_map.insert(2, true); 44 | range_map.insert(3..5, true); 45 | range_map.insert(5..=7, true); 46 | range_map.insert(7.., true); 47 | assert_eq!(range_map.range_count(), 1); 48 | ``` 49 | 50 | It also supports non standard ranges with excluded start bounds: 51 | 52 | ```rust 53 | use btree_range_map::{ 54 | RangeFromExcluded, 55 | RangeFromExcludedTo, 56 | RangeFromExcludedToIncluded 57 | }; 58 | 59 | // same as `4..` 60 | range_map.insert(RangeFromExcluded::new(3), true); 61 | 62 | // same as `3` 63 | range_map.insert(RangeFromExcludedTo::new(2, 4), true); 64 | 65 | // same as `1..=2` 66 | range_map.insert(RangeFromExcludedToIncluded::new(0, 2), true); 67 | 68 | assert_eq!(range_map.range_count(), 1); 69 | ``` 70 | 71 | #### Floats 72 | 73 | Floating point numbers `f32` and `f64` are handled as one might expect. 74 | 75 | ```rust 76 | use btree_range_map::{RangeMap, RangeFromExcluded}; 77 | let mut range_map: RangeMap = RangeMap::new(); 78 | 79 | // sets all `f32` below zero to `false`. 80 | range_map.insert(..0.0, false); 81 | 82 | // sets all `f32` above zero to `true`. 83 | range_map.insert(RangeFromExcluded::new(0.0), true); 84 | 85 | assert_eq!(range_map.range_count(), 2); 86 | assert_eq!(range_map.get(0.0), None); // only `0.0` is unmapped. 87 | ``` 88 | 89 | ## License 90 | 91 | Licensed under either of 92 | 93 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 94 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 95 | 96 | at your option. 97 | 98 | ### Contribution 99 | 100 | Unless you explicitly state otherwise, any contribution intentionally submitted 101 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 102 | additional terms or conditions. 103 | -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | # B-Tree range map 2 | 3 | [![CI](https://github.com/timothee-haudebourg/{{crate}}/workflows/CI/badge.svg)](https://github.com/timothee-haudebourg/{{crate}}/actions) 4 | [![Crate informations](https://img.shields.io/crates/v/{{crate}}.svg?style=flat-square)](https://crates.io/crates/{{crate}}) 5 | [![License](https://img.shields.io/crates/l/{{crate}}.svg?style=flat-square)](https://github.com/timothee-haudebourg/{{crate}}#license) 6 | [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square)](https://docs.rs/{{crate}}) 7 | 8 | {{readme}} 9 | 10 | ## License 11 | 12 | Licensed under either of 13 | 14 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 15 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 16 | 17 | at your option. 18 | 19 | ### Contribution 20 | 21 | Unless you explicitly state otherwise, any contribution intentionally submitted 22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 23 | additional terms or conditions. 24 | -------------------------------------------------------------------------------- /src/generic/map.rs: -------------------------------------------------------------------------------- 1 | use super::Node; 2 | use crate::{ 3 | range::{Difference, ProductArg}, 4 | AnyRange, AsRange, IntoRange, RangeOrdering, RangePartialOrd, 5 | }; 6 | use btree_slab::generic::{ 7 | map::{BTreeExt, BTreeExtMut, BTreeMap}, 8 | node::{Address, Item, Offset}, 9 | }; 10 | use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; 11 | use range_traits::{Bounded, Measure, PartialEnum}; 12 | use std::{ 13 | cmp::{Ord, Ordering, PartialOrd}, 14 | fmt, 15 | hash::{Hash, Hasher}, 16 | }; 17 | 18 | /// Range map. 19 | #[derive(Clone)] 20 | pub struct RangeMap { 21 | btree: BTreeMap, V, C>, 22 | } 23 | 24 | impl RangeMap { 25 | /// Create a new empty map. 26 | pub fn new() -> RangeMap 27 | where 28 | C: Default, 29 | { 30 | RangeMap { 31 | btree: BTreeMap::new(), 32 | } 33 | } 34 | } 35 | 36 | impl Default for RangeMap { 37 | fn default() -> Self { 38 | Self::new() 39 | } 40 | } 41 | 42 | impl, V>>> RangeMap 43 | where 44 | C: SimpleCollectionRef, 45 | { 46 | pub fn len(&self) -> K::Len 47 | where 48 | K: Measure + PartialEnum + Bounded, 49 | { 50 | let mut len = K::Len::default(); 51 | for (range, _) in self { 52 | len = len + range.len() 53 | } 54 | 55 | len 56 | } 57 | 58 | pub fn bounded_len(&self) -> Option 59 | where 60 | K: Measure + PartialEnum, 61 | { 62 | let mut len = K::Len::default(); 63 | for (range, _) in self { 64 | len = len + range.bounded_len()? 65 | } 66 | 67 | Some(len) 68 | } 69 | 70 | pub fn is_empty(&self) -> bool 71 | where 72 | K: Measure + PartialEnum, 73 | { 74 | self.bounded_len() == Some(K::Len::default()) 75 | } 76 | 77 | pub fn range_count(&self) -> usize { 78 | self.btree.len() 79 | } 80 | 81 | fn address_of(&self, key: &T, connected: bool) -> Result 82 | where 83 | K: PartialEnum + Measure, 84 | T: RangePartialOrd, 85 | { 86 | if connected { 87 | if let Ok(addr) = self.address_of(key, false) { 88 | return Ok(addr); 89 | } 90 | } 91 | 92 | match self.btree.root_id() { 93 | Some(id) => self.address_in(id, key, connected), 94 | None => Err(Address::nowhere()), 95 | } 96 | } 97 | 98 | fn address_in(&self, mut id: usize, key: &T, connected: bool) -> Result 99 | where 100 | K: PartialEnum + Measure, 101 | T: RangePartialOrd, 102 | { 103 | loop { 104 | match self.offset_in(id, key, connected) { 105 | Ok(offset) => return Ok(Address::new(id, offset)), 106 | Err((offset, None)) => return Err(Address::new(id, offset.into())), 107 | Err((_, Some(child_id))) => { 108 | id = child_id; 109 | } 110 | } 111 | } 112 | } 113 | 114 | fn offset_in( 115 | &self, 116 | id: usize, 117 | key: &T, 118 | connected: bool, 119 | ) -> Result)> 120 | where 121 | K: PartialEnum + Measure, 122 | T: RangePartialOrd, 123 | { 124 | match self.btree.node(id) { 125 | Node::Internal(node) => { 126 | let branches = node.branches(); 127 | match binary_search(branches, key, connected) { 128 | Some(i) => { 129 | let b = &branches[i]; 130 | if key 131 | .range_partial_cmp(b.item.key()) 132 | .unwrap_or(RangeOrdering::After(false)) 133 | .matches(connected) 134 | { 135 | Ok(i.into()) 136 | } else { 137 | Err((i + 1, Some(b.child))) 138 | } 139 | } 140 | None => Err((0, Some(node.first_child_id()))), 141 | } 142 | } 143 | Node::Leaf(leaf) => { 144 | let items = leaf.items(); 145 | match binary_search(items, key, connected) { 146 | Some(i) => { 147 | let item = &items[i]; 148 | let ord = key 149 | .range_partial_cmp(item.key()) 150 | .unwrap_or(RangeOrdering::After(false)); 151 | if ord.matches(connected) { 152 | Ok(i.into()) 153 | } else { 154 | Err((i + 1, None)) 155 | } 156 | } 157 | None => Err((0, None)), 158 | } 159 | } 160 | } 161 | } 162 | 163 | pub fn intersects>(&self, key: R) -> bool 164 | where 165 | K: PartialEnum + Measure, 166 | V: PartialEq, 167 | { 168 | // let key = AnyRange::from(key); 169 | 170 | if key.is_empty() { 171 | false 172 | } else { 173 | self.address_of(&key, false).is_ok() 174 | } 175 | } 176 | 177 | pub fn contains_key(&self, key: K) -> bool 178 | where 179 | K: PartialEnum + RangePartialOrd + Measure, 180 | { 181 | self.address_of(&key, false).is_ok() 182 | } 183 | 184 | pub fn get(&self, key: K) -> Option<&V> 185 | where 186 | K: PartialEnum + RangePartialOrd + Measure, 187 | { 188 | match self.address_of(&key, false) { 189 | Ok(addr) => Some(self.btree.item(addr).unwrap().value()), 190 | Err(_) => None, 191 | } 192 | } 193 | 194 | pub fn iter(&self) -> Iter { 195 | self.btree.iter() 196 | } 197 | 198 | /// Returns an iterator over the gaps (unbounded keys) of the map. 199 | pub fn gaps(&self) -> Gaps { 200 | Gaps { 201 | inner: self.btree.iter(), 202 | prev: None, 203 | done: false, 204 | } 205 | } 206 | } 207 | 208 | impl, V>>> fmt::Debug for RangeMap 209 | where 210 | C: SimpleCollectionRef, 211 | { 212 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 213 | write!(f, "{{")?; 214 | 215 | for (range, value) in self { 216 | write!(f, "{:?}=>{:?}", range, value)? 217 | } 218 | 219 | write!(f, "}}") 220 | } 221 | } 222 | 223 | impl, V>>, D: Slab, W>>> 224 | PartialEq> for RangeMap 225 | where 226 | L: Measure + PartialOrd + PartialEnum, 227 | K: PartialEnum, 228 | W: PartialEq, 229 | C: SimpleCollectionRef, 230 | D: SimpleCollectionRef, 231 | { 232 | fn eq(&self, other: &RangeMap) -> bool { 233 | self.btree == other.btree 234 | } 235 | } 236 | 237 | impl, V>>> Eq for RangeMap 238 | where 239 | K: Measure + PartialEnum + Ord, 240 | V: Eq, 241 | C: SimpleCollectionRef, 242 | { 243 | } 244 | 245 | impl, V>>, D: Slab, W>>> 246 | PartialOrd> for RangeMap 247 | where 248 | L: Measure + PartialOrd + PartialEnum, 249 | K: PartialEnum, 250 | W: PartialOrd, 251 | C: SimpleCollectionRef, 252 | D: SimpleCollectionRef, 253 | { 254 | fn partial_cmp(&self, other: &RangeMap) -> Option { 255 | self.btree.partial_cmp(&other.btree) 256 | } 257 | } 258 | 259 | impl, V>>> Ord for RangeMap 260 | where 261 | K: Measure + PartialEnum + Ord, 262 | V: Ord, 263 | C: SimpleCollectionRef, 264 | { 265 | fn cmp(&self, other: &Self) -> Ordering { 266 | self.btree.cmp(&other.btree) 267 | } 268 | } 269 | 270 | impl, V>>> Hash for RangeMap 271 | where 272 | K: Hash + PartialEnum, 273 | V: Hash, 274 | C: SimpleCollectionRef, 275 | { 276 | fn hash(&self, h: &mut H) { 277 | for range in self { 278 | range.hash(h) 279 | } 280 | } 281 | } 282 | 283 | impl<'a, K, V, C: Slab, V>>> IntoIterator for &'a RangeMap 284 | where 285 | C: SimpleCollectionRef, 286 | { 287 | type Item = (&'a AnyRange, &'a V); 288 | type IntoIter = Iter<'a, K, V, C>; 289 | 290 | fn into_iter(self) -> Self::IntoIter { 291 | self.iter() 292 | } 293 | } 294 | 295 | impl, V>>> RangeMap 296 | where 297 | C: SimpleCollectionRef, 298 | C: SimpleCollectionMut, 299 | { 300 | fn merge_forward(&mut self, addr: Address, next_addr: Option
) 301 | where 302 | K: Clone + PartialEnum + Measure, 303 | V: PartialEq, 304 | { 305 | if let Some(next_addr) = next_addr { 306 | let item = self.btree.item(addr).unwrap(); 307 | let next_item = self.btree.item(next_addr).unwrap(); 308 | if item.key().connected_to(next_item.key()) && item.value() == next_item.value() { 309 | let (removed_item, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); 310 | let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); 311 | let item = self.btree.item_mut(new_addr).unwrap(); 312 | item.key_mut().add(removed_item.key()); 313 | } 314 | } 315 | } 316 | 317 | fn set_item_key( 318 | &mut self, 319 | addr: Address, 320 | next_addr: Option
, 321 | new_key: AnyRange, 322 | ) -> (Address, Option
) 323 | where 324 | K: Clone + PartialEnum + Measure, 325 | V: PartialEq, 326 | { 327 | if let Some(next_addr) = next_addr { 328 | let next_item = self.btree.item(next_addr).unwrap(); 329 | if new_key.connected_to(next_item.key()) 330 | && next_item.value() == self.btree.item(addr).unwrap().value() 331 | { 332 | // Merge with the next item. 333 | let (_, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); 334 | let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); 335 | let item = self.btree.item_mut(new_addr).unwrap(); 336 | item.key_mut().add(&new_key); 337 | 338 | return (new_addr, self.btree.next_item_address(new_addr)); 339 | } 340 | } 341 | 342 | let item = self.btree.item_mut(addr).unwrap(); 343 | *item.key_mut() = new_key; 344 | (addr, next_addr) 345 | } 346 | 347 | fn set_item( 348 | &mut self, 349 | addr: Address, 350 | next_addr: Option
, 351 | new_key: AnyRange, 352 | new_value: V, 353 | ) -> (Address, Option
, V) 354 | where 355 | K: Clone + PartialEnum + Measure, 356 | V: PartialEq, 357 | { 358 | if let Some(next_addr) = next_addr { 359 | let next_item = self.btree.item(next_addr).unwrap(); 360 | if new_key.connected_to(next_item.key()) && *next_item.value() == new_value { 361 | // Merge with the next item. 362 | let (removed_item, non_normalized_new_addr) = self.btree.remove_at(addr).unwrap(); 363 | let new_addr = self.btree.normalize(non_normalized_new_addr).unwrap(); 364 | let item = self.btree.item_mut(new_addr).unwrap(); 365 | item.key_mut().add(&new_key); 366 | 367 | return ( 368 | new_addr, 369 | self.btree.next_item_address(new_addr), 370 | removed_item.into_value(), 371 | ); 372 | } 373 | } 374 | 375 | let item = self.btree.item_mut(addr).unwrap(); 376 | let removed_value = item.set_value(new_value); 377 | *item.key_mut() = new_key; 378 | (addr, next_addr, removed_value) 379 | } 380 | 381 | fn insert_item( 382 | &mut self, 383 | addr: Address, 384 | key: AnyRange, 385 | value: V, 386 | ) -> (Address, Option
) 387 | where 388 | K: Clone + PartialEnum + Measure, 389 | V: PartialEq, 390 | { 391 | let next_item = self.btree.item(addr).unwrap(); 392 | if key.connected_to(next_item.key()) && *next_item.value() == value { 393 | // Merge with the next item. 394 | let item = self.btree.item_mut(addr).unwrap(); 395 | item.key_mut().add(&key); 396 | 397 | return (addr, self.btree.next_item_address(addr)); 398 | } 399 | 400 | let new_addr = self.btree.insert_at(addr, Item::new(key, value)); 401 | (new_addr, self.btree.next_item_address(new_addr)) 402 | } 403 | 404 | fn remove_item(&mut self, addr: Address) -> (Address, Option
) { 405 | let (_, non_normalized_addr) = self.btree.remove_at(addr).unwrap(); 406 | let new_addr = self 407 | .btree 408 | .previous_item_address(non_normalized_addr) 409 | .unwrap(); 410 | (new_addr, self.btree.normalize(non_normalized_addr)) 411 | } 412 | 413 | pub fn update, F>(&mut self, key: R, f: F) 414 | where 415 | K: Clone + PartialEnum + Measure, 416 | F: Fn(Option<&V>) -> Option, 417 | V: PartialEq + Clone, 418 | { 419 | let mut key = AnyRange::from(key); 420 | 421 | if key.is_empty() { 422 | return; 423 | } 424 | 425 | match self.address_of(&key, true) { 426 | Ok(mut addr) => { 427 | let mut next_addr = self.btree.next_item_address(addr); 428 | 429 | loop { 430 | let (prev_addr, prev_next_addr) = { 431 | let product = key.product(self.btree.item(addr).unwrap().key()).cloned(); 432 | 433 | let mut removed_item_value = None; 434 | 435 | let (addr, next_addr) = match product.after { 436 | Some(ProductArg::Subject(key_after)) => { 437 | match f(None) { 438 | Some(value) => { 439 | let (new_addr, new_next_addr, removed_value) = 440 | self.set_item(addr, next_addr, key_after, value); 441 | removed_item_value = Some(removed_value); 442 | (new_addr, new_next_addr) 443 | } 444 | None => (addr, next_addr), // we wait the last minute to remove the item. 445 | } 446 | } 447 | Some(ProductArg::Object(item_after)) => { 448 | let item = self.btree.item_mut(addr).unwrap(); 449 | item.set_key(item_after); 450 | removed_item_value = Some(item.value().clone()); 451 | (addr, next_addr) 452 | } 453 | None => (addr, next_addr), // we wait the last minute to remove the item. 454 | }; 455 | 456 | let (addr, next_addr) = match product.intersection { 457 | Some(intersection) => { 458 | let new_value = match removed_item_value.as_ref() { 459 | Some(value) => f(Some(value)), 460 | None => f(Some(self.btree.item(addr).unwrap().value())), 461 | }; 462 | 463 | match new_value { 464 | Some(new_value) => { 465 | if removed_item_value.is_some() { 466 | let (new_addr, new_next_addr) = 467 | self.insert_item(addr, intersection, new_value); 468 | (new_addr, new_next_addr) 469 | } else { 470 | let (new_addr, new_next_addr, removed_value) = self 471 | .set_item(addr, next_addr, intersection, new_value); 472 | removed_item_value = Some(removed_value); 473 | (new_addr, new_next_addr) 474 | } 475 | } 476 | None => (addr, next_addr), // we wait the last minute to remove the item. 477 | } 478 | } 479 | None => (addr, next_addr), // we wait the last minute to remove the item. 480 | }; 481 | 482 | match product.before { 483 | Some(ProductArg::Subject(key_before)) => { 484 | match self.btree.previous_item_address(addr) { 485 | Some(prev_addr) 486 | if self 487 | .btree 488 | .item(prev_addr) 489 | .unwrap() 490 | .key() 491 | .connected_to(&key_before) => 492 | { 493 | let (prev_addr, addr) = if removed_item_value.is_none() { 494 | self.remove_item(addr) 495 | } else { 496 | (prev_addr, Some(addr)) 497 | }; 498 | 499 | // Let's go for another turn! 500 | // One item back this time. 501 | key = key_before; 502 | (prev_addr, addr) 503 | } 504 | _ => { 505 | // there is no previous connected item, we must insert here! 506 | match f(None) { 507 | Some(value) => { 508 | if removed_item_value.is_some() { 509 | // we cannot reuse the item 510 | // insert 511 | self.insert_item(addr, key_before, value); 512 | } else { 513 | // we can reuse the item 514 | // reuse 515 | self.set_item( 516 | addr, next_addr, key_before, value, 517 | ); 518 | } 519 | } 520 | None => { 521 | if removed_item_value.is_none() { 522 | self.btree.remove_at(addr); // finally remove the item. 523 | } 524 | } 525 | } 526 | 527 | break; 528 | } 529 | } 530 | } 531 | Some(ProductArg::Object(item_before)) => { 532 | match removed_item_value { 533 | Some(value) => { 534 | self.insert_item(addr, item_before, value); 535 | } 536 | None => { 537 | self.set_item_key(addr, next_addr, item_before); 538 | } 539 | } 540 | 541 | break; 542 | } 543 | None => { 544 | match self.btree.previous_item_address(addr) { 545 | Some(prev_addr) => { 546 | let (prev_addr, addr) = if removed_item_value.is_none() { 547 | self.remove_item(addr) 548 | } else { 549 | (prev_addr, Some(addr)) 550 | }; 551 | 552 | self.merge_forward(prev_addr, addr) 553 | } 554 | _ => { 555 | if removed_item_value.is_none() { 556 | self.btree.remove_at(addr).unwrap(); 557 | } 558 | } 559 | } 560 | 561 | break; 562 | } 563 | } 564 | }; 565 | 566 | addr = prev_addr; 567 | next_addr = prev_next_addr; 568 | } 569 | } 570 | Err(addr) => { 571 | // case (G) 572 | if let Some(new_value) = f(None) { 573 | self.btree.insert_at(addr, Item::new(key, new_value)); 574 | } 575 | } 576 | } 577 | 578 | for (range, _) in self.iter() { 579 | debug_assert!(!range.is_empty()); 580 | } 581 | } 582 | 583 | pub fn insert_disconnected>( 584 | &mut self, 585 | key: R, 586 | value: V, 587 | ) -> Result<(), (AnyRange, V)> 588 | where 589 | K: PartialEnum + Measure, 590 | { 591 | let key = key.into_range(); 592 | match self.address_of(&key, true) { 593 | Ok(_) => Err((key, value)), 594 | Err(addr) => { 595 | self.btree.insert_at(addr, Item::new(key, value)); 596 | Ok(()) 597 | } 598 | } 599 | } 600 | 601 | /// Insert a new key-value binding. 602 | pub fn insert>(&mut self, key: R, value: V) 603 | where 604 | K: Clone + PartialEnum + Measure, 605 | V: PartialEq + Clone, 606 | { 607 | let mut key = key.into_range(); 608 | 609 | if key.is_empty() { 610 | return; 611 | } 612 | 613 | match self.address_of(&key, true) { 614 | Ok(mut addr) => { 615 | // let mut value = Some(value); 616 | let mut next_addr = self.btree.next_item_address(addr); 617 | 618 | loop { 619 | let (prev_addr, prev_next_addr) = { 620 | let product = key.product(self.btree.item(addr).unwrap().key()).cloned(); 621 | 622 | let mut removed_item_value = None; 623 | 624 | if let Some(ProductArg::Object(item_after)) = product.after { 625 | let item = self.btree.item_mut(addr).unwrap(); 626 | item.set_key(item_after); 627 | removed_item_value = Some(item.value().clone()); 628 | } 629 | 630 | match product.before { 631 | Some(ProductArg::Object(item_before)) => { 632 | match removed_item_value { 633 | Some(old_value) => { 634 | if old_value == value { 635 | key.add(&item_before); 636 | self.insert_item(addr, key, value); 637 | } else { 638 | let (addr, _) = self.insert_item(addr, key, value); 639 | self.insert_item(addr, item_before, old_value); 640 | } 641 | } 642 | None => { 643 | if *self.btree.item(addr).unwrap().value() == value { 644 | key.add(&item_before); 645 | self.set_item_key(addr, next_addr, key); 646 | } else { 647 | let (_, _, old_value) = 648 | self.set_item(addr, next_addr, key, value); 649 | self.insert_item(addr, item_before, old_value); 650 | } 651 | } 652 | } 653 | 654 | break; 655 | } 656 | Some(ProductArg::Subject(_)) | None => { 657 | match self.btree.previous_item_address(addr) { 658 | Some(prev_addr) 659 | if self 660 | .btree 661 | .item(prev_addr) 662 | .unwrap() 663 | .key() 664 | .connected_to(&key) => 665 | { 666 | // We can move one to the previous item. 667 | let (prev_addr, addr) = if removed_item_value.is_none() { 668 | self.remove_item(addr) 669 | } else { 670 | (prev_addr, Some(addr)) 671 | }; 672 | 673 | (prev_addr, addr) 674 | } 675 | _ => { 676 | // There is no previous item, we must get it done now. 677 | if removed_item_value.is_some() { 678 | self.insert_item(addr, key, value); 679 | } else { 680 | self.set_item(addr, next_addr, key, value); 681 | } 682 | 683 | break; 684 | } 685 | } 686 | } 687 | } 688 | }; 689 | 690 | addr = prev_addr; 691 | next_addr = prev_next_addr; 692 | } 693 | } 694 | Err(addr) => { 695 | // case (G) 696 | self.btree.insert_at(addr, Item::new(key, value)); 697 | } 698 | } 699 | } 700 | 701 | /// Remove a key. 702 | pub fn remove>(&mut self, key: R) 703 | where 704 | K: Clone + PartialEnum + Measure, 705 | V: Clone, 706 | { 707 | let key = AnyRange::from(key); 708 | if let Ok(mut addr) = self.address_of(&key, false) { 709 | loop { 710 | if self 711 | .btree 712 | .item(addr) 713 | .map(|item| item.key().intersects(&key)) 714 | .unwrap_or(false) 715 | { 716 | match self.btree.item(addr).unwrap().key().without(&key) { 717 | Difference::Split(left, right) => { 718 | let left = left.cloned(); 719 | let right = right.cloned(); 720 | 721 | let right_value = { 722 | let item = self.btree.item_mut(addr).unwrap(); 723 | *item.key_mut() = right; 724 | item.value().clone() 725 | }; 726 | self.btree.insert_at(addr, Item::new(left, right_value)); 727 | break; // no need to go further, the removed range was totaly included in this one. 728 | } 729 | Difference::Before(left, _) => { 730 | let left = left.cloned(); 731 | let item = self.btree.item_mut(addr).unwrap(); 732 | *item.key_mut() = left; 733 | break; // no need to go further, the removed range does not intersect anything below this range. 734 | } 735 | Difference::After(right, _) => { 736 | let right = right.cloned(); 737 | let item = self.btree.item_mut(addr).unwrap(); 738 | *item.key_mut() = right; 739 | } 740 | Difference::Empty => { 741 | let (_, next_addr) = self.btree.remove_at(addr).unwrap(); 742 | addr = next_addr 743 | } 744 | } 745 | 746 | match self.btree.previous_item_address(addr) { 747 | Some(prev_addr) => addr = prev_addr, 748 | None => break, 749 | } 750 | } else { 751 | break; 752 | } 753 | } 754 | } 755 | } 756 | } 757 | 758 | impl, V>>> IntoIterator for RangeMap 759 | where 760 | C: SimpleCollectionRef, 761 | C: SimpleCollectionMut, 762 | { 763 | type Item = (AnyRange, V); 764 | type IntoIter = IntoIter; 765 | 766 | fn into_iter(self) -> Self::IntoIter { 767 | self.btree.into_iter() 768 | } 769 | } 770 | 771 | pub type Iter<'a, K, V, C> = btree_slab::generic::map::Iter<'a, AnyRange, V, C>; 772 | pub type IntoIter = btree_slab::generic::map::IntoIter, V, C>; 773 | 774 | /// Iterator over the gaps (unbound keys) of a `RangeMap`. 775 | pub struct Gaps<'a, K, V, C> { 776 | inner: Iter<'a, K, V, C>, 777 | prev: Option>, 778 | done: bool, 779 | } 780 | 781 | impl<'a, K: Measure + PartialEnum, V, C: Slab, V>>> Iterator for Gaps<'a, K, V, C> 782 | where 783 | C: SimpleCollectionRef, 784 | { 785 | type Item = AnyRange<&'a K>; 786 | 787 | fn next(&mut self) -> Option { 788 | use std::ops::{Bound, RangeBounds}; 789 | 790 | if self.done { 791 | None 792 | } else { 793 | loop { 794 | match self.inner.next() { 795 | Some((range, _)) => { 796 | let start = match self.prev.take() { 797 | Some(bound) => bound, 798 | None => Bound::Unbounded, 799 | }; 800 | 801 | self.prev = match range.end_bound() { 802 | Bound::Unbounded => { 803 | self.done = true; 804 | None 805 | } 806 | Bound::Included(t) => Some(Bound::Excluded(t)), 807 | Bound::Excluded(t) => Some(Bound::Included(t)), 808 | }; 809 | 810 | let end = match range.start_bound() { 811 | Bound::Unbounded => continue, 812 | Bound::Included(t) => Bound::Excluded(t), 813 | Bound::Excluded(t) => Bound::Included(t), 814 | }; 815 | 816 | let gap = AnyRange { start, end }; 817 | 818 | if !gap.ref_is_empty() { 819 | break Some(gap); 820 | } 821 | } 822 | None => { 823 | self.done = true; 824 | let start = self.prev.take(); 825 | match start { 826 | Some(bound) => { 827 | let gap = AnyRange { 828 | start: bound, 829 | end: Bound::Unbounded, 830 | }; 831 | 832 | break if gap.ref_is_empty() { None } else { Some(gap) }; 833 | } 834 | None => { 835 | break Some(AnyRange { 836 | start: Bound::Unbounded, 837 | end: Bound::Unbounded, 838 | }) 839 | } 840 | } 841 | } 842 | } 843 | } 844 | } 845 | } 846 | } 847 | 848 | /// Search for the index of the gratest item less/below or equal/including the given element. 849 | /// 850 | /// If `connected` is `true`, then it will search for the gratest item less/below or equal/including **or connected to** the given element. 851 | pub fn binary_search, V>>>( 852 | items: &[I], 853 | element: &U, 854 | connected: bool, 855 | ) -> Option 856 | where 857 | U: RangePartialOrd, 858 | { 859 | if items.is_empty() 860 | || element 861 | .range_partial_cmp(items[0].as_ref().key()) 862 | .unwrap_or(RangeOrdering::Before(false)) 863 | .is_before(connected) 864 | { 865 | None 866 | } else { 867 | let mut i = 0; 868 | let mut j = items.len() - 1; 869 | 870 | if !element 871 | .range_partial_cmp(items[j].as_ref().key()) 872 | .unwrap_or(RangeOrdering::After(false)) 873 | .is_before(connected) 874 | { 875 | return Some(j); 876 | } 877 | 878 | // invariants: 879 | // vec[i].as_ref().key() < range 880 | // vec[j].as_ref().key() >= range 881 | // j > i 882 | 883 | while j - i > 1 { 884 | let k = (i + j) / 2; 885 | 886 | if let Some(ord) = element.range_partial_cmp(items[k].as_ref().key()) { 887 | if ord.is_before(connected) { 888 | j = k; 889 | } else { 890 | i = k; 891 | } 892 | } else { 893 | return None; // FIXME: that's bad. Maybe we should expect a total order. 894 | } 895 | } 896 | 897 | Some(i) 898 | } 899 | } 900 | 901 | #[cfg(test)] 902 | mod tests { 903 | use std::{collections::HashSet, ops::Bound}; 904 | 905 | use super::*; 906 | 907 | macro_rules! items { 908 | [$($item:expr),*] => { 909 | &[ 910 | $( 911 | Item::new(AnyRange::from($item), ()) 912 | ),* 913 | ] 914 | }; 915 | } 916 | 917 | #[test] 918 | fn binary_search_disconnected_singletons() { 919 | assert_eq!(binary_search(items![0], &0, false), Some(0)); 920 | 921 | assert_eq!(binary_search(items![0, 2, 4], &0, false), Some(0)); 922 | assert_eq!(binary_search(items![0, 2, 4], &1, false), Some(0)); 923 | assert_eq!(binary_search(items![0, 2, 4], &2, false), Some(1)); 924 | assert_eq!(binary_search(items![0, 2, 4], &3, false), Some(1)); 925 | assert_eq!(binary_search(items![0, 2, 4], &4, false), Some(2)); 926 | assert_eq!(binary_search(items![0, 2, 4], &5, false), Some(2)); 927 | 928 | assert_eq!(binary_search(items![0, 3, 6], &0, false), Some(0)); 929 | assert_eq!(binary_search(items![0, 3, 6], &1, false), Some(0)); 930 | assert_eq!(binary_search(items![0, 3, 6], &2, false), Some(0)); 931 | assert_eq!(binary_search(items![0, 3, 6], &3, false), Some(1)); 932 | assert_eq!(binary_search(items![0, 3, 6], &4, false), Some(1)); 933 | assert_eq!(binary_search(items![0, 3, 6], &5, false), Some(1)); 934 | assert_eq!(binary_search(items![0, 3, 6], &6, false), Some(2)); 935 | assert_eq!(binary_search(items![0, 3, 6], &7, false), Some(2)); 936 | } 937 | 938 | #[test] 939 | fn binary_search_disconnected_singletons_float() { 940 | assert_eq!(binary_search(items![0.0], &0.0, false), Some(0)); 941 | 942 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &-1.0, false), None); 943 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &0.0, false), Some(0)); 944 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &1.0, false), Some(0)); 945 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &2.0, false), Some(1)); 946 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &3.0, false), Some(1)); 947 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &4.0, false), Some(2)); 948 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &5.0, false), Some(2)); 949 | 950 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &0.0, false), Some(0)); 951 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &1.0, false), Some(0)); 952 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &2.0, false), Some(0)); 953 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &3.0, false), Some(1)); 954 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &4.0, false), Some(1)); 955 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &5.0, false), Some(1)); 956 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &6.0, false), Some(2)); 957 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &7.0, false), Some(2)); 958 | } 959 | 960 | #[test] 961 | fn binary_search_connected_singletons() { 962 | assert_eq!(binary_search(items![0], &0, true), Some(0)); 963 | 964 | assert_eq!(binary_search(items![0, 2, 4], &0, true), Some(0)); 965 | assert_eq!(binary_search(items![0, 2, 4], &1, true), Some(1)); 966 | assert_eq!(binary_search(items![0, 2, 4], &2, true), Some(1)); 967 | assert_eq!(binary_search(items![0, 2, 4], &3, true), Some(2)); 968 | assert_eq!(binary_search(items![0, 2, 4], &4, true), Some(2)); 969 | assert_eq!(binary_search(items![0, 2, 4], &5, true), Some(2)); 970 | assert_eq!(binary_search(items![2, 4, 8], &0, true), None); 971 | 972 | assert_eq!(binary_search(items![0, 3, 6], &0, true), Some(0)); 973 | assert_eq!(binary_search(items![0, 3, 6], &1, true), Some(0)); 974 | assert_eq!(binary_search(items![0, 3, 6], &2, true), Some(1)); 975 | assert_eq!(binary_search(items![0, 3, 6], &3, true), Some(1)); 976 | assert_eq!(binary_search(items![0, 3, 6], &4, true), Some(1)); 977 | assert_eq!(binary_search(items![0, 3, 6], &5, true), Some(2)); 978 | assert_eq!(binary_search(items![0, 3, 6], &6, true), Some(2)); 979 | assert_eq!(binary_search(items![0, 3, 6], &7, true), Some(2)); 980 | } 981 | 982 | // for floats, connected or disconnected makes no difference for singletons. 983 | #[test] 984 | fn binary_search_connected_singletons_float() { 985 | assert_eq!(binary_search(items![0.0], &0.0, true), Some(0)); 986 | 987 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &-1.0, true), None); 988 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &0.0, true), Some(0)); 989 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &1.0, true), Some(0)); 990 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &2.0, true), Some(1)); 991 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &3.0, true), Some(1)); 992 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &4.0, true), Some(2)); 993 | assert_eq!(binary_search(items![0.0, 2.0, 4.0], &5.0, true), Some(2)); 994 | 995 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &0.0, true), Some(0)); 996 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &1.0, true), Some(0)); 997 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &2.0, true), Some(0)); 998 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &3.0, true), Some(1)); 999 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &4.0, true), Some(1)); 1000 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &5.0, true), Some(1)); 1001 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &6.0, true), Some(2)); 1002 | assert_eq!(binary_search(items![0.0, 3.0, 6.0], &7.0, true), Some(2)); 1003 | } 1004 | 1005 | #[test] 1006 | fn insert() { 1007 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1008 | 1009 | map.insert('+', 0); 1010 | map.insert('-', 1); 1011 | map.insert('0'..='9', 2); 1012 | map.insert('.', 3); 1013 | 1014 | assert_eq!(*map.get('.').unwrap(), 3) 1015 | } 1016 | 1017 | #[test] 1018 | fn insert_around() { 1019 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1020 | 1021 | map.insert(' ', 0); 1022 | map.insert('#', 1); 1023 | map.insert('e', 2); 1024 | map.insert('%', 3); 1025 | map.insert('A'..='Z', 4); 1026 | map.insert('a'..='z', 5); 1027 | 1028 | assert!(map.get('a').is_some()) 1029 | } 1030 | 1031 | #[test] 1032 | fn update_connected_after() { 1033 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1034 | 1035 | map.insert('+', 0); 1036 | map.insert('-', 1); 1037 | map.insert('0'..='9', 2); 1038 | map.update('.', |binding| { 1039 | assert!(binding.is_none()); 1040 | Some(3) 1041 | }); 1042 | 1043 | assert_eq!(*map.get('.').unwrap(), 3) 1044 | } 1045 | 1046 | #[test] 1047 | fn update_singleton() { 1048 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1049 | 1050 | map.insert('*', 0); 1051 | map.update('*', |_| Some(1)); 1052 | 1053 | assert_eq!(map.iter().count(), 1); 1054 | assert_eq!(map.get('*'), Some(&1)) 1055 | } 1056 | 1057 | #[test] 1058 | fn update_connected_before() { 1059 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1060 | 1061 | map.insert('+', 0); 1062 | map.insert('.', 1); 1063 | map.insert('0'..='9', 2); 1064 | map.update('-', |binding| { 1065 | assert!(binding.is_none()); 1066 | Some(3) 1067 | }); 1068 | 1069 | assert_eq!(map.iter().count(), 4); 1070 | assert_eq!(*map.get('-').unwrap(), 3) 1071 | } 1072 | 1073 | #[test] 1074 | fn update_around() { 1075 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1076 | 1077 | map.insert('e', 0); 1078 | map.update('a'..='z', |_| Some(1)); 1079 | 1080 | assert_eq!(map.iter().count(), 1); 1081 | assert_eq!(map.get('a'), Some(&1)) 1082 | } 1083 | 1084 | #[test] 1085 | fn update_stress() { 1086 | let ranges = [ 1087 | // 'A'..='Z', 1088 | // 'a'..='z', 1089 | // '0'..='9', 1090 | // '-'..='-', 1091 | // '.'..='.', 1092 | // '_'..='_', 1093 | // '~'..='~', 1094 | // '%'..='%', 1095 | // '!'..='!', 1096 | // '$'..='$', 1097 | // '&'..='&', 1098 | // '\''..='\'', 1099 | // '('..='(', 1100 | // ')'..=')', 1101 | // '*'..='*', 1102 | // '+'..='+', 1103 | ','..=',', 1104 | ';'..=';', 1105 | '='..='=', 1106 | ':'..=':', 1107 | // '@'..='@', 1108 | // '['..='[', 1109 | // '0'..='9', 1110 | // '1'..='9', 1111 | // '1'..='1', 1112 | // '2'..='2', 1113 | // '2'..='2', 1114 | // 'A'..='Z', 1115 | // 'a'..='z', 1116 | // '0'..='9', 1117 | // '-'..='-', 1118 | // '.'..='.', 1119 | // '_'..='_', 1120 | // '~'..='~', 1121 | // '%'..='%', 1122 | // '!'..='!', 1123 | // '$'..='$', 1124 | // '&'..='&', 1125 | '\''..='\'', 1126 | '('..='(', 1127 | ')'..=')', 1128 | '*'..='*', 1129 | '+'..='+', 1130 | // ','..=',', 1131 | 1132 | // ';'..=';', 1133 | // '='..='=', 1134 | // ':'..=':', 1135 | // '/'..='/', 1136 | // '?'..='?', 1137 | // '#'..='#' 1138 | ]; 1139 | 1140 | let mut map: crate::RangeMap> = crate::RangeMap::new(); 1141 | 1142 | for (i, range) in ranges.into_iter().enumerate() { 1143 | map.update(range, |current| { 1144 | let mut list = current.cloned().unwrap_or_default(); 1145 | list.push(i); 1146 | Some(list) 1147 | }); 1148 | } 1149 | 1150 | eprintln!("before: {map:?}"); 1151 | 1152 | map.update(','..=',', |current| { 1153 | let mut list = current.cloned().unwrap_or_default(); 1154 | list.push(9); 1155 | Some(list) 1156 | }); 1157 | 1158 | eprintln!("after: {map:?}"); 1159 | 1160 | let mut found_ranges = HashSet::new(); 1161 | for (range, _) in map.iter() { 1162 | eprintln!("looking for range: {range:?}"); 1163 | assert!(found_ranges.insert(range)) 1164 | } 1165 | } 1166 | 1167 | #[test] 1168 | fn update_stress2() { 1169 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1170 | 1171 | map.insert('+'..='+', 0); 1172 | map.insert(AnyRange::new(Bound::Excluded('+'), Bound::Included(',')), 1); 1173 | map.update(','..=',', |_| Some(2)); 1174 | 1175 | let mut found_ranges = HashSet::new(); 1176 | for (range, _) in map.iter() { 1177 | eprintln!("looking for range: {range:?}"); 1178 | assert!(found_ranges.insert(range)) 1179 | } 1180 | } 1181 | 1182 | #[test] 1183 | fn update_test() { 1184 | let mut map: crate::RangeMap = crate::RangeMap::new(); 1185 | 1186 | map.insert('0'..='9', 0); 1187 | map.insert( 1188 | AnyRange::new(Bound::Excluded('\''), Bound::Included('(')), 1189 | 1, 1190 | ); 1191 | map.insert(AnyRange::new(Bound::Excluded('('), Bound::Included(')')), 2); 1192 | map.insert(AnyRange::new(Bound::Excluded(')'), Bound::Included('*')), 3); 1193 | map.insert('+', 4); 1194 | map.insert(',', 5); 1195 | map.insert('-', 6); 1196 | map.insert('.', 7); 1197 | map.insert('/', 8); 1198 | 1199 | assert_eq!(map.range_count(), 9); 1200 | assert_eq!(map.iter().count(), 9); 1201 | 1202 | map.update( 1203 | AnyRange::new(Bound::Excluded('\''), Bound::Included('(')), 1204 | |_| Some(10), 1205 | ); 1206 | map.update( 1207 | AnyRange::new(Bound::Excluded('('), Bound::Included(')')), 1208 | |_| Some(11), 1209 | ); 1210 | map.update( 1211 | AnyRange::new(Bound::Excluded(')'), Bound::Included('*')), 1212 | |_| Some(12), 1213 | ); 1214 | 1215 | assert_eq!(map.range_count(), 9); 1216 | assert_eq!(map.iter().count(), 9); 1217 | 1218 | // let mut ranges = map.iter(); 1219 | // let (a, _) = ranges.next().unwrap(); 1220 | // assert_eq!(a.first(), Some('(')); 1221 | // assert_eq!(a.last(), Some(')')); 1222 | 1223 | // let (b, _) = ranges.next().unwrap(); 1224 | // assert_eq!(b.first(), Some('*')); 1225 | // assert_eq!(b.last(), Some('*')); 1226 | 1227 | // let (c, _) = ranges.next().unwrap(); 1228 | // assert_eq!(c.first(), Some('+')); 1229 | // assert_eq!(c.last(), Some('9')); 1230 | } 1231 | } 1232 | -------------------------------------------------------------------------------- /src/generic/mod.rs: -------------------------------------------------------------------------------- 1 | pub use btree_slab::generic::Node; 2 | 3 | pub mod map; 4 | pub mod multimap; 5 | pub mod set; 6 | 7 | pub use map::RangeMap; 8 | pub use multimap::RangeMultiMap; 9 | pub use set::RangeSet; 10 | -------------------------------------------------------------------------------- /src/generic/multimap.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | generic::{ 3 | map::{IntoIter, Iter}, 4 | RangeMap, 5 | }, 6 | AnyRange, AsRange, 7 | }; 8 | use btree_slab::generic::Node; 9 | use cc_traits::{SetMut, SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; 10 | use range_traits::{Measure, PartialEnum}; 11 | 12 | /// Multi map. 13 | /// 14 | /// In a multi map, each key is associated to a set of values. 15 | /// The type parameter `S` is the set type. It can be replaced by anything 16 | /// implementing the [`cc_traits::SetMut`] trait, such as the standard 17 | /// [`BTreeSet`](std::collections::BTreeSet) and [`HashSet`](std::collections::HashSet). 18 | #[derive(Clone)] 19 | pub struct RangeMultiMap { 20 | map: RangeMap, 21 | } 22 | 23 | impl RangeMultiMap { 24 | pub fn new() -> RangeMultiMap 25 | where 26 | C: Default, 27 | { 28 | RangeMultiMap { 29 | map: RangeMap::new(), 30 | } 31 | } 32 | } 33 | 34 | impl Default for RangeMultiMap { 35 | fn default() -> Self { 36 | Self::new() 37 | } 38 | } 39 | 40 | impl, S>>> RangeMultiMap 41 | where 42 | C: SimpleCollectionRef, 43 | { 44 | pub fn iter(&self) -> Iter { 45 | self.map.iter() 46 | } 47 | } 48 | 49 | impl<'a, K: Clone + PartialOrd + Measure, S, C: Slab, S>>> IntoIterator 50 | for &'a RangeMultiMap 51 | where 52 | C: SimpleCollectionRef, 53 | { 54 | type Item = (&'a AnyRange, &'a S); 55 | type IntoIter = Iter<'a, K, S, C>; 56 | 57 | fn into_iter(self) -> Self::IntoIter { 58 | self.iter() 59 | } 60 | } 61 | 62 | impl, S>>> RangeMultiMap 63 | where 64 | C: SimpleCollectionRef, 65 | C: SimpleCollectionMut, 66 | { 67 | pub fn insert, V>(&mut self, key: R, value: V) 68 | where 69 | K: Clone + PartialEnum + Measure, 70 | V: PartialEq + Clone, 71 | S: SetMut + PartialEq + Clone + Default, 72 | { 73 | self.map.update(key, |set_opt| { 74 | let mut result = match set_opt { 75 | Some(set) => set.clone(), 76 | None => S::default(), 77 | }; 78 | 79 | result.insert(value.clone()); 80 | Some(result) 81 | }) 82 | } 83 | 84 | pub fn remove, V>(&mut self, key: R, value: &V) 85 | where 86 | K: Clone + PartialEnum + Measure, 87 | V: PartialEq + Clone, 88 | S: SetMut + PartialEq + Clone + Default, 89 | { 90 | self.map.update(key, |set_opt| match set_opt { 91 | Some(set) => { 92 | let mut result = set.clone(); 93 | result.remove(value); 94 | if result.is_empty() { 95 | None 96 | } else { 97 | Some(result) 98 | } 99 | } 100 | None => None, 101 | }) 102 | } 103 | } 104 | 105 | impl, S>>> IntoIterator 106 | for RangeMultiMap 107 | where 108 | C: SimpleCollectionRef, 109 | C: SimpleCollectionMut, 110 | { 111 | type Item = (AnyRange, S); 112 | type IntoIter = IntoIter; 113 | 114 | fn into_iter(self) -> Self::IntoIter { 115 | self.map.into_iter() 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/generic/set.rs: -------------------------------------------------------------------------------- 1 | use crate::{generic::RangeMap, AnyRange, AsRange, IntoRange, RangePartialOrd}; 2 | use btree_slab::generic::Node; 3 | use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; 4 | use range_traits::{Bounded, Measure, PartialEnum}; 5 | use std::{ 6 | cmp::Ordering, 7 | fmt, 8 | hash::{Hash, Hasher}, 9 | }; 10 | 11 | /// Range set. 12 | /// 13 | /// This is based on a range map, where the values are `()`. 14 | #[derive(Clone)] 15 | pub struct RangeSet { 16 | map: RangeMap, 17 | } 18 | 19 | impl RangeSet { 20 | pub fn new() -> RangeSet 21 | where 22 | C: Default, 23 | { 24 | RangeSet { 25 | map: RangeMap::new(), 26 | } 27 | } 28 | } 29 | 30 | impl Default for RangeSet { 31 | fn default() -> Self { 32 | Self::new() 33 | } 34 | } 35 | 36 | impl, ()>>> RangeSet 37 | where 38 | C: SimpleCollectionRef, 39 | { 40 | pub fn range_count(&self) -> usize { 41 | self.map.range_count() 42 | } 43 | 44 | pub fn len(&self) -> T::Len 45 | where 46 | T: Measure + PartialEnum + Bounded, 47 | { 48 | self.map.len() 49 | } 50 | 51 | pub fn bounded_len(&self) -> Option 52 | where 53 | T: Measure + PartialEnum, 54 | { 55 | self.map.bounded_len() 56 | } 57 | 58 | pub fn is_empty(&self) -> bool 59 | where 60 | T: Measure + PartialEnum, 61 | { 62 | self.map.is_empty() 63 | } 64 | 65 | pub fn intersects>(&self, values: R) -> bool 66 | where 67 | T: Clone + PartialEnum + Measure, 68 | { 69 | self.map.intersects(values) 70 | } 71 | 72 | pub fn contains(&self, value: T) -> bool 73 | where 74 | T: Clone + PartialEnum + RangePartialOrd + Measure, 75 | { 76 | self.map.contains_key(value) 77 | } 78 | 79 | pub fn iter(&self) -> Iter { 80 | Iter { 81 | inner: self.map.iter(), 82 | } 83 | } 84 | 85 | /// Returns an iterator over the gaps (missing values) of the set. 86 | pub fn gaps(&self) -> Gaps { 87 | self.map.gaps() 88 | } 89 | } 90 | 91 | impl, ()>>> fmt::Debug for RangeSet 92 | where 93 | C: SimpleCollectionRef, 94 | { 95 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 96 | write!(f, "{{")?; 97 | 98 | for range in self { 99 | write!(f, "{:?}", range)? 100 | } 101 | 102 | write!(f, "}}") 103 | } 104 | } 105 | 106 | impl<'a, T, C: Slab, ()>>> IntoIterator for &'a RangeSet 107 | where 108 | C: SimpleCollectionRef, 109 | { 110 | type Item = &'a AnyRange; 111 | type IntoIter = Iter<'a, T, C>; 112 | 113 | fn into_iter(self) -> Self::IntoIter { 114 | self.iter() 115 | } 116 | } 117 | 118 | impl, ()>>> RangeSet 119 | where 120 | C: SimpleCollectionRef, 121 | C: SimpleCollectionMut, 122 | { 123 | pub fn insert>(&mut self, key: R) 124 | where 125 | T: Clone + PartialEnum + Measure, 126 | { 127 | self.map.insert(key, ()) 128 | } 129 | 130 | pub fn remove>(&mut self, key: R) 131 | where 132 | T: Clone + PartialEnum + Measure, 133 | { 134 | self.map.remove(key) 135 | } 136 | 137 | pub fn complement(&self) -> Self 138 | where 139 | T: Clone + Measure + PartialEnum, 140 | C: Default, 141 | { 142 | self.gaps().map(AnyRange::cloned).collect() 143 | } 144 | } 145 | 146 | impl, ()>>, D: Slab, ()>>> PartialEq> 147 | for RangeSet 148 | where 149 | L: Measure + PartialOrd + PartialEnum, 150 | K: PartialEnum, 151 | C: SimpleCollectionRef, 152 | D: SimpleCollectionRef, 153 | { 154 | fn eq(&self, other: &RangeSet) -> bool { 155 | self.map == other.map 156 | } 157 | } 158 | 159 | impl, ()>>> Eq for RangeSet 160 | where 161 | K: Measure + PartialEnum + Ord, 162 | C: SimpleCollectionRef, 163 | { 164 | } 165 | 166 | impl, ()>>, D: Slab, ()>>> 167 | PartialOrd> for RangeSet 168 | where 169 | L: Measure + PartialOrd + PartialEnum, 170 | K: PartialEnum, 171 | C: SimpleCollectionRef, 172 | D: SimpleCollectionRef, 173 | { 174 | fn partial_cmp(&self, other: &RangeSet) -> Option { 175 | self.map.partial_cmp(&other.map) 176 | } 177 | } 178 | 179 | impl, ()>>> Ord for RangeSet 180 | where 181 | K: Measure + PartialEnum + Ord, 182 | C: SimpleCollectionRef, 183 | { 184 | fn cmp(&self, other: &Self) -> Ordering { 185 | self.map.cmp(&other.map) 186 | } 187 | } 188 | 189 | impl, ()>>> Hash for RangeSet 190 | where 191 | K: Hash + PartialEnum, 192 | C: SimpleCollectionRef, 193 | { 194 | fn hash(&self, h: &mut H) { 195 | self.map.hash(h) 196 | } 197 | } 198 | 199 | impl, ()>>> IntoIterator for RangeSet 200 | where 201 | C: SimpleCollectionRef, 202 | C: SimpleCollectionMut, 203 | { 204 | type Item = AnyRange; 205 | type IntoIter = IntoIter; 206 | 207 | fn into_iter(self) -> Self::IntoIter { 208 | IntoIter { 209 | inner: self.map.into_iter(), 210 | } 211 | } 212 | } 213 | 214 | pub struct Iter<'a, T, C> { 215 | inner: crate::generic::map::Iter<'a, T, (), C>, 216 | } 217 | 218 | impl<'a, T, C: Slab, ()>>> Iterator for Iter<'a, T, C> 219 | where 220 | C: SimpleCollectionRef, 221 | { 222 | type Item = &'a AnyRange; 223 | 224 | fn next(&mut self) -> Option { 225 | match self.inner.next() { 226 | Some((range, ())) => Some(range), 227 | None => None, 228 | } 229 | } 230 | } 231 | 232 | pub struct IntoIter { 233 | inner: crate::generic::map::IntoIter, 234 | } 235 | 236 | impl, ()>>> Iterator for IntoIter 237 | where 238 | C: SimpleCollectionRef, 239 | C: SimpleCollectionMut, 240 | { 241 | type Item = AnyRange; 242 | 243 | fn next(&mut self) -> Option { 244 | self.inner.next().map(|(range, _)| range) 245 | } 246 | } 247 | 248 | /// Iterator over the gaps (unbound keys) of a `RangeSet`. 249 | pub type Gaps<'a, T, C> = crate::generic::map::Gaps<'a, T, (), C>; 250 | 251 | impl, ()>>> std::iter::Extend 252 | for RangeSet 253 | where 254 | R::Item: Clone + Measure + PartialOrd, 255 | C: SimpleCollectionRef, 256 | C: SimpleCollectionMut, 257 | { 258 | fn extend>(&mut self, iter: I) { 259 | for range in iter { 260 | self.insert(range) 261 | } 262 | } 263 | } 264 | 265 | impl, ()>>> FromIterator 266 | for RangeSet 267 | where 268 | R::Item: Clone + Measure + PartialOrd, 269 | C: SimpleCollectionRef, 270 | C: SimpleCollectionMut, 271 | { 272 | fn from_iter>(iter: I) -> Self { 273 | let mut result = Self::default(); 274 | result.extend(iter); 275 | result 276 | } 277 | } 278 | 279 | #[cfg(test)] 280 | mod test { 281 | use crate::{AnyRange, RangeSet}; 282 | 283 | #[test] 284 | fn gaps1() { 285 | let mut a: RangeSet = RangeSet::new(); 286 | let mut b: RangeSet = RangeSet::new(); 287 | 288 | a.insert(10..20); 289 | 290 | b.insert(0..10); 291 | b.insert(20..); 292 | 293 | assert_eq!(a.complement(), b) 294 | } 295 | 296 | #[test] 297 | fn gaps2() { 298 | let mut a: RangeSet = RangeSet::new(); 299 | let mut b: RangeSet = RangeSet::new(); 300 | 301 | a.insert(0..10); 302 | b.insert(10..); 303 | 304 | assert_eq!(a.complement(), b) 305 | } 306 | 307 | #[test] 308 | fn gaps3() { 309 | let mut a: RangeSet = RangeSet::new(); 310 | let mut b: RangeSet = RangeSet::new(); 311 | 312 | a.insert(20..); 313 | b.insert(0..=19); 314 | 315 | assert_eq!(a.complement(), b) 316 | } 317 | 318 | #[test] 319 | fn gaps4() { 320 | let mut a: RangeSet = RangeSet::new(); 321 | 322 | a.insert(10..20); 323 | 324 | let mut gaps = a.gaps().map(AnyRange::cloned); 325 | assert_eq!(gaps.next(), Some(AnyRange::from(..10u8))); 326 | assert_eq!(gaps.next(), Some(AnyRange::from(20u8..))); 327 | assert_eq!(gaps.next(), None) 328 | } 329 | 330 | #[test] 331 | fn gaps5() { 332 | let mut a: RangeSet = RangeSet::new(); 333 | 334 | a.insert(..10); 335 | a.insert(20..); 336 | 337 | let mut gaps = a.gaps().map(AnyRange::cloned); 338 | assert_eq!(gaps.next(), Some(AnyRange::from(10..20))); 339 | assert_eq!(gaps.next(), None) 340 | } 341 | 342 | #[test] 343 | fn gaps6() { 344 | let mut a: RangeSet = RangeSet::new(); 345 | 346 | a.insert(10..20); 347 | 348 | assert_eq!(a.complement().complement(), a) 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A *range map* is a map where keys are aggregated into ranges of keys for 2 | //! efficient storage. Every time you need to store a large number numeric-keyed 3 | //! items in a map or set, a range map (or range set) should be used. 4 | //! 5 | //! This library provides a range map implementation based on 6 | //! [`btree-slab`](https://crates.io/crates/btree-slab)'s B-tree. 7 | //! It defines three basic types `RangeSet`, `RangeMap` and 8 | //! `RangeMultiMap`. 9 | //! 10 | //! ## Usage 11 | //! 12 | //! The `RangeSet` and `RangeMap` behave similarly to the standard 13 | //! `BTreeSet` and `BTreeMap` types. 14 | //! However in addition to `PartialOrd`, the key type must also implement the 15 | //! `Measure` trait defining how keys are merged into ranges. 16 | //! This trait is implemented by default for `char`, integer types and float 17 | //! types. 18 | //! 19 | //! ``` 20 | //! use btree_range_map::RangeMap; 21 | //! 22 | //! let mut range_map: RangeMap = RangeMap::new(); 23 | //! range_map.insert(00..=05, true); 24 | //! range_map.insert(4, false); 25 | //! assert_eq!(range_map.range_count(), 3); 26 | //! assert_eq!(range_map.get(03), Some(&true)); 27 | //! assert_eq!(range_map.get(04), Some(&false)); 28 | //! assert_eq!(range_map.get(05), Some(&true)); 29 | //! ``` 30 | //! 31 | //! This library supports included and excluded bounds: 32 | //! 33 | //! ``` 34 | //! # use btree_range_map::RangeMap; 35 | //! # let mut range_map: RangeMap = RangeMap::new(); 36 | //! range_map.insert(..1, true); 37 | //! range_map.insert(..=1, true); 38 | //! range_map.insert(2, true); 39 | //! range_map.insert(3..5, true); 40 | //! range_map.insert(5..=7, true); 41 | //! range_map.insert(7.., true); 42 | //! assert_eq!(range_map.range_count(), 1); 43 | //! ``` 44 | //! 45 | //! It also supports non standard ranges with excluded start bounds: 46 | //! 47 | //! ``` 48 | //! # use btree_range_map::RangeMap; 49 | //! # let mut range_map: RangeMap = RangeMap::new(); 50 | //! use btree_range_map::{ 51 | //! RangeFromExcluded, 52 | //! RangeFromExcludedTo, 53 | //! RangeFromExcludedToIncluded 54 | //! }; 55 | //! 56 | //! // same as `4..` 57 | //! range_map.insert(RangeFromExcluded::new(3), true); 58 | //! 59 | //! // same as `3` 60 | //! range_map.insert(RangeFromExcludedTo::new(2, 4), true); 61 | //! 62 | //! // same as `1..=2` 63 | //! range_map.insert(RangeFromExcludedToIncluded::new(0, 2), true); 64 | //! 65 | //! assert_eq!(range_map.range_count(), 1); 66 | //! ``` 67 | //! 68 | //! ### Floats 69 | //! 70 | //! Floating point numbers `f32` and `f64` are handled as one might expect. 71 | //! 72 | //! ``` 73 | //! use btree_range_map::{RangeMap, RangeFromExcluded}; 74 | //! let mut range_map: RangeMap = RangeMap::new(); 75 | //! 76 | //! // sets all `f32` below zero to `false`. 77 | //! range_map.insert(..0.0, false); 78 | //! 79 | //! // sets all `f32` above zero to `true`. 80 | //! range_map.insert(RangeFromExcluded::new(0.0), true); 81 | //! 82 | //! assert_eq!(range_map.range_count(), 2); 83 | //! assert_eq!(range_map.get(0.0), None); // only `0.0` is unmapped. 84 | //! ``` 85 | pub mod generic; 86 | mod range; 87 | 88 | #[cfg(feature = "serde")] 89 | mod serde; 90 | 91 | pub use range::*; 92 | 93 | pub type DefaultSetContainer = slab::Slab, ()>>; 94 | pub type DefaultMapContainer = slab::Slab, V>>; 95 | 96 | pub type RangeSet = generic::RangeSet>; 97 | pub type RangeMap = generic::RangeMap>; 98 | pub type RangeMultiMap = generic::RangeMultiMap>; 99 | -------------------------------------------------------------------------------- /src/range.rs: -------------------------------------------------------------------------------- 1 | pub use range_traits::{Measure, PartialEnum}; 2 | use std::{ 3 | cmp::PartialOrd, 4 | ops::{Bound, RangeBounds}, 5 | }; 6 | 7 | mod bound; 8 | mod ordering; 9 | 10 | mod any; 11 | mod from_excluded; 12 | mod from_excluded_to; 13 | mod from_excluded_to_included; 14 | 15 | pub use any::*; 16 | pub use bound::*; 17 | pub use from_excluded::*; 18 | pub use from_excluded_to::*; 19 | pub use from_excluded_to_included::*; 20 | pub use ordering::*; 21 | 22 | /// Types that can be interpreted as ranges. 23 | pub trait AsRange: Sized { 24 | /// Type of the elements of the range. 25 | type Item: Measure + PartialEnum; 26 | 27 | /// Start bound of the range. 28 | fn start(&self) -> Bound<&Self::Item>; 29 | 30 | /// End bound of the range. 31 | fn end(&self) -> Bound<&Self::Item>; 32 | 33 | fn is_empty(&self) -> bool { 34 | is_range_empty(self.start(), self.end()) 35 | } 36 | 37 | fn intersects(&self, other: &R) -> bool 38 | where 39 | Self::Item: PartialOrd + Measure, 40 | { 41 | matches!( 42 | self.range_partial_cmp(other), 43 | Some(RangeOrdering::Intersecting(_, _)) 44 | ) 45 | } 46 | 47 | fn connected_to(&self, other: &R) -> bool 48 | where 49 | Self::Item: PartialOrd + Measure, 50 | { 51 | match self.range_partial_cmp(other) { 52 | Some(RangeOrdering::Intersecting(_, _)) => true, 53 | Some(RangeOrdering::Before(connected)) => connected, 54 | Some(RangeOrdering::After(connected)) => connected, 55 | _ => false, 56 | } 57 | } 58 | 59 | fn intersected_with<'a, R: AsRange>( 60 | &'a self, 61 | other: &'a R, 62 | ) -> AnyRange<&'a Self::Item> 63 | where 64 | Self::Item: PartialOrd + Measure, 65 | { 66 | AnyRange { 67 | start: max_bound(self.start(), other.start(), true), 68 | end: min_bound(self.end(), other.end(), false), 69 | } 70 | } 71 | 72 | fn without<'a, R: AsRange>( 73 | &'a self, 74 | other: &'a R, 75 | ) -> Difference<&'a Self::Item> 76 | where 77 | Self::Item: PartialOrd + Measure, 78 | { 79 | let left = match invert_bound(other.start()) { 80 | Some(inverted_other_start) => { 81 | if !is_range_empty(self.start(), inverted_other_start) { 82 | Some(AnyRange { 83 | start: self.start(), 84 | end: inverted_other_start, 85 | }) 86 | } else { 87 | None 88 | } 89 | } 90 | None => None, 91 | }; 92 | 93 | let right = match invert_bound(other.end()) { 94 | Some(inverted_other_end) => { 95 | if !is_range_empty(inverted_other_end, self.end()) { 96 | Some(AnyRange { 97 | start: inverted_other_end, 98 | end: self.end(), 99 | }) 100 | } else { 101 | None 102 | } 103 | } 104 | None => None, 105 | }; 106 | 107 | match (left, right) { 108 | (Some(left), None) => Difference::Before( 109 | left, 110 | Directed::End(left.end) >= Directed::Start(other.start()), 111 | ), 112 | (None, Some(right)) => Difference::After( 113 | right, 114 | Directed::Start(right.start) <= Directed::End(other.end()), 115 | ), 116 | (Some(left), Some(right)) => Difference::Split(left, right), 117 | (None, None) => Difference::Empty, 118 | } 119 | } 120 | 121 | fn product<'a, R: AsRange>(&'a self, other: &'a R) -> Product<&'a Self::Item> 122 | where 123 | Self::Item: PartialOrd + Measure, 124 | { 125 | let before = match crop_right(self, other.start()) { 126 | Some(self_before) => Some(ProductArg::Subject(self_before)), 127 | None => crop_right(other, self.start()).map(ProductArg::Object), 128 | }; 129 | 130 | let intersection = self.intersected_with(other); 131 | let intersection = if is_range_empty(intersection.start, intersection.end) { 132 | None 133 | } else { 134 | Some(intersection) 135 | }; 136 | 137 | let after = match crop_left(self, other.end()) { 138 | Some(self_after) => Some(ProductArg::Subject(self_after)), 139 | None => crop_left(other, self.end()).map(ProductArg::Object), 140 | }; 141 | 142 | Product { 143 | before, 144 | intersection, 145 | after, 146 | } 147 | } 148 | } 149 | 150 | pub trait IntoRange: AsRange { 151 | fn into_range(self) -> AnyRange; 152 | } 153 | 154 | fn crop_left<'a, R: AsRange>( 155 | range: &'a R, 156 | other_end: Bound<&'a R::Item>, 157 | ) -> Option> { 158 | match invert_bound(other_end) { 159 | Some(inverted_other_end) => { 160 | let max_start = max_bound(range.start(), inverted_other_end, true); 161 | if !is_range_empty(max_start, range.end()) { 162 | Some(AnyRange { 163 | start: inverted_other_end, 164 | end: range.end(), 165 | }) 166 | } else { 167 | None 168 | } 169 | } 170 | None => None, 171 | } 172 | } 173 | 174 | fn crop_right<'a, R: AsRange>( 175 | range: &'a R, 176 | other_start: Bound<&'a R::Item>, 177 | ) -> Option> { 178 | match invert_bound(other_start) { 179 | Some(inverted_other_start) => { 180 | let min_end = min_bound(range.end(), inverted_other_start, false); 181 | if !is_range_empty(range.start(), min_end) { 182 | Some(AnyRange { 183 | start: range.start(), 184 | end: min_end, 185 | }) 186 | } else { 187 | None 188 | } 189 | } 190 | None => None, 191 | } 192 | } 193 | 194 | /// Part of the result of a `product` operation. 195 | pub enum ProductArg { 196 | /// A part of the subject, `self`. 197 | Subject(AnyRange), 198 | 199 | /// A part of the object, `other`. 200 | Object(AnyRange), 201 | } 202 | 203 | impl<'a, T: Clone> ProductArg<&'a T> { 204 | pub fn cloned(&self) -> ProductArg { 205 | match self { 206 | ProductArg::Subject(range) => ProductArg::Subject(range.cloned()), 207 | ProductArg::Object(range) => ProductArg::Object(range.cloned()), 208 | } 209 | } 210 | } 211 | 212 | /// Result of a `product` operation. 213 | pub struct Product { 214 | /// What is left of `self` and `other` before their intersection. 215 | pub before: Option>, 216 | 217 | /// The intersection of `self` and `other`, if not empty. 218 | pub intersection: Option>, 219 | 220 | /// What is left of `self` and `other` after their intersection. 221 | pub after: Option>, 222 | } 223 | 224 | impl<'a, T: Clone> Product<&'a T> { 225 | pub fn cloned(&self) -> Product { 226 | Product { 227 | before: self.before.as_ref().map(|r| r.cloned()), 228 | intersection: self.intersection.as_ref().map(|r| r.cloned()), 229 | after: self.after.as_ref().map(|r| r.cloned()), 230 | } 231 | } 232 | } 233 | 234 | pub enum RelativePosition { 235 | Before, 236 | After, 237 | } 238 | 239 | /// Result of a `without` operation. 240 | pub enum Difference { 241 | /// The end of the range may intersects `other`. The boolean is set to true if it does. 242 | Before(AnyRange, bool), 243 | 244 | /// The begining of the range may intersects `other`. The boolean is set to true if it does. 245 | After(AnyRange, bool), 246 | 247 | /// The `other` range if fully included. 248 | Split(AnyRange, AnyRange), 249 | 250 | /// The range is fully included in `other`. 251 | Empty, 252 | } 253 | 254 | macro_rules! singleton_range { 255 | ($ty:ident) => { 256 | impl AsRange for $ty { 257 | type Item = Self; 258 | 259 | fn start(&self) -> Bound<&Self::Item> { 260 | Bound::Included(self) 261 | } 262 | 263 | fn end(&self) -> Bound<&Self::Item> { 264 | Bound::Included(self) 265 | } 266 | } 267 | 268 | impl IntoRange for $ty { 269 | fn into_range(self) -> AnyRange { 270 | AnyRange::new(Bound::Included(self), Bound::Included(self)) 271 | } 272 | } 273 | }; 274 | } 275 | 276 | singleton_range!(u8); 277 | singleton_range!(i8); 278 | singleton_range!(u16); 279 | singleton_range!(i16); 280 | singleton_range!(u32); 281 | singleton_range!(i32); 282 | singleton_range!(u64); 283 | singleton_range!(i64); 284 | // singleton_range!(u128); 285 | // singleton_range!(i128); 286 | singleton_range!(usize); 287 | // singleton_range!(isize); 288 | singleton_range!(f32); 289 | singleton_range!(f64); 290 | singleton_range!(char); 291 | 292 | macro_rules! standard_range { 293 | ($ty:path, |$this:ident| $into_range:expr) => { 294 | impl AsRange for $ty { 295 | type Item = T; 296 | 297 | fn start(&self) -> Bound<&Self::Item> { 298 | self.start_bound() 299 | } 300 | 301 | fn end(&self) -> Bound<&Self::Item> { 302 | self.end_bound() 303 | } 304 | } 305 | 306 | impl IntoRange for $ty { 307 | fn into_range($this) -> AnyRange { 308 | $into_range 309 | } 310 | } 311 | }; 312 | } 313 | 314 | standard_range!(std::ops::Range, |self| AnyRange::new( 315 | Bound::Included(self.start), 316 | Bound::Excluded(self.end) 317 | )); 318 | standard_range!(std::ops::RangeInclusive, |self| { 319 | let (a, b) = self.into_inner(); 320 | AnyRange::new(Bound::Included(a), Bound::Included(b)) 321 | }); 322 | standard_range!(std::ops::RangeFrom, |self| AnyRange::new( 323 | Bound::Included(self.start), 324 | Bound::Unbounded 325 | )); 326 | standard_range!(std::ops::RangeTo, |self| AnyRange::new( 327 | Bound::Unbounded, 328 | Bound::Excluded(self.end) 329 | )); 330 | standard_range!(std::ops::RangeToInclusive, |self| AnyRange::new( 331 | Bound::Unbounded, 332 | Bound::Included(self.end) 333 | )); 334 | standard_range!(AnyRange, |self| self); 335 | standard_range!(RangeFromExcluded, |self| AnyRange::new( 336 | Bound::Excluded(self.start), 337 | Bound::Unbounded 338 | )); 339 | standard_range!(RangeFromExcludedTo, |self| AnyRange::new( 340 | Bound::Excluded(self.start), 341 | Bound::Excluded(self.end) 342 | )); 343 | standard_range!(RangeFromExcludedToIncluded, |self| AnyRange::new( 344 | Bound::Excluded(self.start), 345 | Bound::Included(self.end) 346 | )); 347 | 348 | #[inline(always)] 349 | fn is_range_empty(start: Bound<&T>, end: Bound<&U>) -> bool 350 | where 351 | T: PartialOrd + Measure + PartialEnum, 352 | U: PartialEnum, 353 | { 354 | Directed::Start(start) > Directed::End(end) 355 | } 356 | 357 | #[cfg(test)] 358 | mod tests { 359 | use crate::RangeSet; 360 | 361 | use super::*; 362 | use std::cmp::Ordering; 363 | 364 | macro_rules! make_bound { 365 | ([= $v:literal ..]) => { 366 | Directed::Start(Bound::Included(&$v)) 367 | }; 368 | ([$v:literal ..]) => { 369 | Directed::Start(Bound::Excluded(&$v)) 370 | }; 371 | ([~ ..]) => { 372 | Directed::Start(Bound::Unbounded) 373 | }; 374 | ([..= $v:literal]) => { 375 | Directed::End(Bound::Included(&$v)) 376 | }; 377 | ([.. $v:literal]) => { 378 | Directed::End(Bound::Excluded(&$v)) 379 | }; 380 | ([.. ~]) => { 381 | Directed::End(Bound::Unbounded) 382 | }; 383 | } 384 | 385 | macro_rules! test_bound_cmp { 386 | (@assert $ty:ty, $a:tt, $b:tt, $expected:ident) => { 387 | assert_eq!(> as PartialOrd>::partial_cmp(&make_bound!($a), &make_bound!($b)), Some(Ordering::$expected)); 388 | }; 389 | ($ty:ty, $a:tt < $b:tt) => { 390 | test_bound_cmp!(@assert $ty, $a, $b, Less) 391 | }; 392 | ($ty:ty, $a:tt == $b:tt) => { 393 | test_bound_cmp!(@assert $ty, $a, $b, Equal) 394 | }; 395 | ($ty:ty, $a:tt > $b:tt) => { 396 | test_bound_cmp!(@assert $ty, $a, $b, Greater) 397 | } 398 | } 399 | 400 | #[test] 401 | fn issue_2() { 402 | let k = AnyRange { 403 | start: Bound::Excluded(0u32), 404 | end: Bound::Unbounded, 405 | }; 406 | assert!(!k.is_empty()); 407 | 408 | let mut ids: RangeSet = RangeSet::new(); 409 | ids.insert(0u32); 410 | 411 | let mut gaps = ids.gaps(); 412 | assert_eq!( 413 | gaps.next().unwrap().cloned(), 414 | AnyRange::new(Bound::Excluded(0), Bound::Unbounded) 415 | ); 416 | assert_eq!(gaps.next().map(AnyRange::cloned), None); 417 | } 418 | 419 | #[test] 420 | fn unsigned_integer_bound_partial_less() { 421 | test_bound_cmp!(u32, [=0..] < [=1..]); 422 | test_bound_cmp!(u32, [=0..] < [0..]); 423 | test_bound_cmp!(u32, [=0..] < [..=1]); 424 | test_bound_cmp!(u32, [=0..] < [..2]); 425 | test_bound_cmp!(u32, [=0..] < [..~]); 426 | 427 | test_bound_cmp!(u32, [0..] < [=2..]); 428 | test_bound_cmp!(u32, [0..] < [1..]); 429 | test_bound_cmp!(u32, [0..] < [..=2]); 430 | test_bound_cmp!(u32, [0..] < [..3]); 431 | test_bound_cmp!(u32, [0..] < [..~]); 432 | 433 | test_bound_cmp!(u32, [~..] < [..=0]); 434 | test_bound_cmp!(u32, [~..] < [..~]); 435 | 436 | test_bound_cmp!(u32, [..=0] < [=1..]); 437 | test_bound_cmp!(u32, [..=0] < [0..]); 438 | test_bound_cmp!(u32, [..=0] < [..=1]); 439 | test_bound_cmp!(u32, [..=0] < [..2]); 440 | test_bound_cmp!(u32, [..=0] < [..~]); 441 | 442 | test_bound_cmp!(u32, [..1] < [=1..]); 443 | test_bound_cmp!(u32, [..1] < [0..]); 444 | test_bound_cmp!(u32, [..1] < [..=1]); 445 | test_bound_cmp!(u32, [..1] < [..2]); 446 | test_bound_cmp!(u32, [..0] < [..~]); 447 | } 448 | 449 | #[test] 450 | fn unsigned_integer_bound_partial_eq() { 451 | test_bound_cmp!(u32, [~..] == [=0..]); 452 | } 453 | 454 | #[test] 455 | fn unsigned_integer_bound_partial_greater() { 456 | test_bound_cmp!(u32, [~..] > [..0]); 457 | } 458 | 459 | #[test] 460 | fn integer_bound_partial_less() { 461 | test_bound_cmp!(i32, [=0..] < [=1..]); 462 | test_bound_cmp!(i32, [=0..] < [0..]); 463 | test_bound_cmp!(i32, [=0..] < [..=1]); 464 | test_bound_cmp!(i32, [=0..] < [..2]); 465 | test_bound_cmp!(i32, [=0..] < [..~]); 466 | 467 | test_bound_cmp!(i32, [0..] < [=2..]); 468 | test_bound_cmp!(i32, [0..] < [1..]); 469 | test_bound_cmp!(i32, [0..] < [..=2]); 470 | test_bound_cmp!(i32, [0..] < [..3]); 471 | test_bound_cmp!(i32, [0..] < [..~]); 472 | test_bound_cmp!(i32, [-2_147_483_648i32..] < [..~]); 473 | 474 | test_bound_cmp!(i32, [~..] < [=0..]); 475 | test_bound_cmp!(i32, [~..] < [..=0]); 476 | test_bound_cmp!(i32, [~..] < [..0]); 477 | test_bound_cmp!(i32, [~..] < [..~]); 478 | 479 | test_bound_cmp!(i32, [..=0] < [=1..]); 480 | test_bound_cmp!(i32, [..=0] < [0..]); 481 | test_bound_cmp!(i32, [..=0] < [..=1]); 482 | test_bound_cmp!(i32, [..=0] < [..2]); 483 | test_bound_cmp!(i32, [..=0] < [..~]); 484 | 485 | test_bound_cmp!(i32, [..1] < [=1..]); 486 | test_bound_cmp!(i32, [..1] < [0..]); 487 | test_bound_cmp!(i32, [..1] < [..=1]); 488 | test_bound_cmp!(i32, [..1] < [..2]); 489 | test_bound_cmp!(i32, [..0] < [..~]); 490 | } 491 | 492 | #[test] 493 | fn integer_bound_partial_eq() { 494 | test_bound_cmp!(i32, [=0..] == [=0..]); 495 | test_bound_cmp!(i32, [=1..] == [0..]); 496 | test_bound_cmp!(i32, [=0..] == [..=0]); 497 | test_bound_cmp!(i32, [=0..] == [..1]); 498 | 499 | test_bound_cmp!(i32, [0..] == [=1..]); 500 | test_bound_cmp!(i32, [0..] == [0..]); 501 | test_bound_cmp!(i32, [0..] == [..=1]); 502 | test_bound_cmp!(i32, [0..] == [..2]); 503 | 504 | test_bound_cmp!(i32, [~..] == [~..]); 505 | 506 | test_bound_cmp!(i32, [..=0] == [=0..]); 507 | test_bound_cmp!(i32, [..=1] == [0..]); 508 | test_bound_cmp!(i32, [..=0] == [..=0]); 509 | test_bound_cmp!(i32, [..=0] == [..1]); 510 | 511 | test_bound_cmp!(i32, [..1] == [=0..]); 512 | test_bound_cmp!(i32, [..2] == [0..]); 513 | test_bound_cmp!(i32, [..1] == [..=0]); 514 | test_bound_cmp!(i32, [..0] == [..0]); 515 | 516 | test_bound_cmp!(i32, [..~] == [..~]); 517 | } 518 | 519 | #[test] 520 | fn integer_bound_partial_greater() { 521 | test_bound_cmp!(i32, [=1..] > [=0..]); 522 | test_bound_cmp!(i32, [0..] > [=0..]); 523 | test_bound_cmp!(i32, [..=1] > [=0..]); 524 | test_bound_cmp!(i32, [..2] > [=0..]); 525 | test_bound_cmp!(i32, [..~] > [=0..]); 526 | 527 | test_bound_cmp!(i32, [=2..] > [0..]); 528 | test_bound_cmp!(i32, [1..] > [0..]); 529 | test_bound_cmp!(i32, [..=2] > [0..]); 530 | test_bound_cmp!(i32, [..3] > [0..]); 531 | test_bound_cmp!(i32, [..~] > [0..]); 532 | 533 | test_bound_cmp!(i32, [=0..] > [~..]); 534 | test_bound_cmp!(i32, [..=0] > [~..]); 535 | test_bound_cmp!(i32, [..0] > [~..]); 536 | test_bound_cmp!(i32, [..~] > [~..]); 537 | 538 | test_bound_cmp!(i32, [=1..] > [..=0]); 539 | test_bound_cmp!(i32, [0..] > [..=0]); 540 | test_bound_cmp!(i32, [..=1] > [..=0]); 541 | test_bound_cmp!(i32, [..2] > [..=0]); 542 | test_bound_cmp!(i32, [..~] > [..=0]); 543 | 544 | test_bound_cmp!(i32, [=1..] > [..1]); 545 | test_bound_cmp!(i32, [0..] > [..1]); 546 | test_bound_cmp!(i32, [..=1] > [..1]); 547 | test_bound_cmp!(i32, [..2] > [..1]); 548 | test_bound_cmp!(i32, [..~] > [..0]); 549 | } 550 | 551 | #[test] 552 | fn float_bound_partial_less() { 553 | test_bound_cmp!(f32, [=0.0..] < [=1.0..]); 554 | test_bound_cmp!(f32, [=0.0..] < [0.0..]); 555 | test_bound_cmp!(f32, [=0.0..] < [..=1.0]); 556 | test_bound_cmp!(f32, [=0.0..] < [..2.0]); 557 | test_bound_cmp!(f32, [=0.0..] < [..~]); 558 | 559 | test_bound_cmp!(f32, [0.0..] < [=2.0..]); 560 | test_bound_cmp!(f32, [0.0..] < [1.0..]); 561 | test_bound_cmp!(f32, [0.0..] < [..1.0]); // different from the int behavior 562 | test_bound_cmp!(f32, [0.0..] < [..=2.0]); 563 | test_bound_cmp!(f32, [0.0..] < [..3.0]); 564 | test_bound_cmp!(f32, [0.0..] < [..~]); 565 | 566 | test_bound_cmp!(f32, [~..] < [=0.0..]); 567 | test_bound_cmp!(f32, [~..] < [..=0.0]); 568 | test_bound_cmp!(f32, [~..] < [..0.0]); 569 | test_bound_cmp!(f32, [~..] < [..~]); 570 | 571 | test_bound_cmp!(f32, [..=0.0] < [=1.0..]); 572 | test_bound_cmp!(f32, [..=0.0] < [0.0..]); 573 | test_bound_cmp!(f32, [..=0.0] < [..=1.0]); 574 | test_bound_cmp!(f32, [..=0.0] < [..2.0]); 575 | test_bound_cmp!(f32, [..=0.0] < [..~]); 576 | 577 | test_bound_cmp!(f32, [..1.0] < [=1.0..]); 578 | test_bound_cmp!(f32, [..1.0] < [1.0..]); 579 | test_bound_cmp!(f32, [..1.0] < [..=1.0]); 580 | test_bound_cmp!(f32, [..1.0] < [..2.0]); 581 | test_bound_cmp!(f32, [..0.0] < [..~]); 582 | } 583 | 584 | #[test] 585 | fn float_bound_partial_eq() { 586 | test_bound_cmp!(f32, [=0.0..] == [=0.0..]); 587 | test_bound_cmp!(f32, [=1.0..] > [0.0..]); // different from the int behavior 588 | test_bound_cmp!(f32, [=0.0..] == [..=0.0]); 589 | test_bound_cmp!(f32, [=0.0..] < [..1.0]); // different from the int behavior 590 | 591 | test_bound_cmp!(f32, [0.0..] < [=1.0..]); // different from the int behavior 592 | test_bound_cmp!(f32, [0.0..] == [0.0..]); 593 | test_bound_cmp!(f32, [0.0..] < [..=1.0]); // different from the int behavior 594 | test_bound_cmp!(f32, [0.0..] < [..2.0]); // different from the int behavior 595 | 596 | test_bound_cmp!(f32, [~..] == [~..]); 597 | 598 | test_bound_cmp!(f32, [..=0.0] == [=0.0..]); 599 | test_bound_cmp!(f32, [..=1.0] > [0.0..]); // different from the int behavior 600 | test_bound_cmp!(f32, [..=0.0] == [..=0.0]); 601 | test_bound_cmp!(f32, [..=0.0] < [..1.0]); // different from the int behavior 602 | 603 | test_bound_cmp!(f32, [..1.0] > [=0.0..]); // different from the int behavior 604 | test_bound_cmp!(f32, [..2.0] > [0.0..]); // different from the int behavior 605 | test_bound_cmp!(f32, [..1.0] > [..=0.0]); // different from the int behavior 606 | test_bound_cmp!(f32, [..0.0] == [..0.0]); 607 | 608 | test_bound_cmp!(f32, [..~] == [..~]); 609 | } 610 | 611 | #[test] 612 | fn float_bound_partial_greater() { 613 | test_bound_cmp!(f32, [=1.0..] > [=0.0..]); 614 | test_bound_cmp!(f32, [0.0..] > [=0.0..]); 615 | test_bound_cmp!(f32, [..=1.0] > [=0.0..]); 616 | test_bound_cmp!(f32, [..2.0] > [=0.0..]); 617 | test_bound_cmp!(f32, [..~] > [=0.0..]); 618 | 619 | test_bound_cmp!(f32, [=2.0..] > [0.0..]); 620 | test_bound_cmp!(f32, [1.0..] > [0.0..]); 621 | test_bound_cmp!(f32, [..1.0] > [0.0..]); // different from the int behavior 622 | test_bound_cmp!(f32, [..=2.0] > [0.0..]); 623 | test_bound_cmp!(f32, [..3.0] > [0.0..]); 624 | test_bound_cmp!(f32, [..~] > [0.0..]); 625 | 626 | test_bound_cmp!(f32, [=0.0..] > [~..]); 627 | test_bound_cmp!(f32, [..=0.0] > [~..]); 628 | test_bound_cmp!(f32, [..0.0] > [~..]); 629 | test_bound_cmp!(f32, [..~] > [~..]); 630 | 631 | test_bound_cmp!(f32, [=1.0..] > [..=0.0]); 632 | test_bound_cmp!(f32, [0.0..] > [..=0.0]); 633 | test_bound_cmp!(f32, [..=1.0] > [..=0.0]); 634 | test_bound_cmp!(f32, [..2.0] > [..=0.0]); 635 | test_bound_cmp!(f32, [..~] > [..=0.0]); 636 | 637 | test_bound_cmp!(f32, [=1.0..] > [..1.0]); 638 | test_bound_cmp!(f32, [1.0..] > [..1.0]); 639 | test_bound_cmp!(f32, [..=1.0] > [..1.0]); 640 | test_bound_cmp!(f32, [..2.0] > [..1.0]); 641 | test_bound_cmp!(f32, [..~] > [..0.0]); 642 | } 643 | 644 | #[test] 645 | fn int_intersection() { 646 | assert!((0..10).intersects(&(5..100))); 647 | } 648 | 649 | // Intersecting ranges are connected. 650 | #[test] 651 | fn int_connected_intersection() { 652 | assert!((0..10).connected_to(&(5..100))); 653 | } 654 | 655 | #[test] 656 | fn int_connected() { 657 | assert!((0..10).connected_to(&(10..20))); 658 | assert!((10..20).connected_to(&(0..10))); 659 | assert!((0..=10).connected_to(&(RangeFromExcludedTo::new(10, 20)))); 660 | } 661 | 662 | #[test] 663 | fn int_disconnected() { 664 | assert!(!(0..10).connected_to(&(11..20))); 665 | assert!(!(11..20).connected_to(&(0..10))); 666 | assert!(!(0..10).connected_to(&(RangeFromExcludedTo::new(10, 20)))); 667 | } 668 | 669 | #[test] 670 | fn float_connected() { 671 | assert!((0.0..10.0).connected_to(&(10.0..20.0))); 672 | assert!((0.0..=10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); 673 | } 674 | 675 | #[test] 676 | fn float_disconnected() { 677 | assert!(!(0.0..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); 678 | assert!(!(..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0)))); 679 | assert!(!(0.0..10.0).connected_to(&(RangeFromExcluded::new(10.0)))); 680 | assert!(!(..10.0).connected_to(&(RangeFromExcluded::new(10.0)))); 681 | } 682 | } 683 | -------------------------------------------------------------------------------- /src/range/any.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | direct_bound_cmp, direct_bound_partial_cmp, direct_bound_partial_eq, is_range_empty, max_bound, 3 | min_bound, AsRange, Bound, BoundOrdering, Directed, Measure, 4 | }; 5 | use range_traits::{Bounded, MaybeBounded, PartialEnum}; 6 | use std::{ 7 | cmp::{Ord, Ordering, PartialOrd}, 8 | fmt, 9 | hash::{Hash, Hasher}, 10 | ops::RangeBounds, 11 | }; 12 | 13 | #[derive(Clone, Copy)] 14 | pub struct AnyRange { 15 | pub start: Bound, 16 | pub end: Bound, 17 | } 18 | 19 | impl AnyRange { 20 | pub fn new(start: Bound, end: Bound) -> Self { 21 | Self { start, end } 22 | } 23 | 24 | pub fn from>(range: R) -> AnyRange 25 | where 26 | T: Clone, 27 | { 28 | AnyRange { 29 | start: range.start().cloned(), 30 | end: range.end().cloned(), 31 | } 32 | } 33 | 34 | pub fn into_bounds(self) -> (Bound, Bound) { 35 | (self.start, self.end) 36 | } 37 | 38 | pub fn is_empty(&self) -> bool 39 | where 40 | T: Measure + PartialEnum, 41 | { 42 | is_range_empty(self.start_bound(), self.end_bound()) 43 | } 44 | 45 | pub fn len(&self) -> T::Len 46 | where 47 | T: Measure + Bounded, 48 | { 49 | match (self.start_bound(), self.end_bound()) { 50 | (Bound::Included(a), Bound::Included(b)) => a.distance(b) + b.len(), 51 | (Bound::Included(a), Bound::Excluded(b)) => a.distance(b), 52 | (Bound::Included(a), Bound::Unbounded) => a.distance(&T::max()), 53 | (Bound::Excluded(a), Bound::Included(b)) => a.distance(b) - a.len() + b.len(), 54 | (Bound::Excluded(a), Bound::Excluded(b)) => a.distance(b) - a.len(), 55 | (Bound::Excluded(a), Bound::Unbounded) => a.distance(&T::max()) - a.len(), 56 | (Bound::Unbounded, Bound::Included(b)) => T::min().distance(b) + b.len(), 57 | (Bound::Unbounded, Bound::Excluded(b)) => T::min().distance(b), 58 | (Bound::Unbounded, Bound::Unbounded) => T::min().distance(&T::max()), 59 | } 60 | } 61 | 62 | pub fn bounded_len(&self) -> Option 63 | where 64 | T: Measure + MaybeBounded, 65 | { 66 | match (self.start_bound(), self.end_bound()) { 67 | (Bound::Included(a), Bound::Included(b)) => Some(a.distance(b) + b.len()), 68 | (Bound::Included(a), Bound::Excluded(b)) => Some(a.distance(b)), 69 | (Bound::Included(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m)), 70 | (Bound::Excluded(a), Bound::Included(b)) => Some(a.distance(b) - a.len() + b.len()), 71 | (Bound::Excluded(a), Bound::Excluded(b)) => Some(a.distance(b) - a.len()), 72 | (Bound::Excluded(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m) - a.len()), 73 | (Bound::Unbounded, Bound::Included(b)) => T::min().map(|m| m.distance(b) + b.len()), 74 | (Bound::Unbounded, Bound::Excluded(b)) => T::min().map(|m| m.distance(b)), 75 | (Bound::Unbounded, Bound::Unbounded) => { 76 | T::min().and_then(|min| T::max().map(|max| min.distance(&max))) 77 | } 78 | } 79 | } 80 | 81 | pub fn pick(&self) -> Option 82 | where 83 | T: Clone + Measure + PartialEnum + Bounded, 84 | { 85 | self.first().or_else(|| self.last()) 86 | } 87 | 88 | /// Get the first element of the range if there is one. 89 | pub fn first(&self) -> Option 90 | where 91 | T: Clone + Measure + PartialEnum + Bounded, 92 | { 93 | if self.is_empty() { 94 | None 95 | } else { 96 | match self.start_bound() { 97 | Bound::Included(a) => Some(a.clone()), 98 | Bound::Excluded(a) => a.succ(), 99 | Bound::Unbounded => Some(::min()), 100 | } 101 | } 102 | } 103 | 104 | /// Get the last element of the range if there is one. 105 | pub fn last(&self) -> Option 106 | where 107 | T: Clone + Measure + PartialEnum + Bounded, 108 | { 109 | if self.is_empty() { 110 | None 111 | } else { 112 | match self.end_bound() { 113 | Bound::Included(a) => Some(a.clone()), 114 | Bound::Excluded(a) => a.pred(), 115 | Bound::Unbounded => Some(::max()), 116 | } 117 | } 118 | } 119 | 120 | pub fn add(&mut self, other: &S) 121 | where 122 | T: Clone + Measure + PartialEnum, 123 | S: RangeBounds, 124 | { 125 | self.start = min_bound(self.start_bound(), other.start_bound(), true).cloned(); 126 | self.end = max_bound(self.end_bound(), other.end_bound(), false).cloned(); 127 | } 128 | 129 | pub fn intersects(&self, other: &S) -> bool 130 | where 131 | T: Measure + PartialEnum, 132 | S: RangeBounds, 133 | { 134 | Directed::End(self.end_bound()) >= Directed::Start(other.start_bound()) 135 | && Directed::End(other.end_bound()) >= Directed::Start(self.start_bound()) 136 | } 137 | 138 | pub fn intersection(&self, other: &Self) -> Self 139 | where 140 | T: Clone + Measure + PartialEnum, 141 | { 142 | Self { 143 | start: max_bound(self.start_bound(), other.start_bound(), true).cloned(), 144 | end: min_bound(self.end_bound(), other.end_bound(), false).cloned(), 145 | } 146 | } 147 | 148 | // pub fn pick_in_intersection(&self, other: &S) -> Option 149 | // where 150 | // T: Clone + Measure + PartialEnum, 151 | // S: AsRange + RangeBounds, 152 | // { 153 | // if self.intersects(other) { 154 | // if Directed::End(self.end_bound()) <= Directed::End(other.end_bound()) { 155 | // if other.is_empty() { 156 | // None 157 | // } else { 158 | // // pick between other.start and self.end 159 | // Some(match other.start_bound() { 160 | // Bound::Included(a) => a.clone(), 161 | // Bound::Excluded(a) => a.succ().unwrap(), 162 | // Bound::Unbounded => T::MIN, 163 | // }) 164 | // } 165 | // } else if self.is_empty() { 166 | // None 167 | // } else { 168 | // // pick between self.start and other.end 169 | // Some(match self.start_bound() { 170 | // Bound::Included(a) => a.clone(), 171 | // Bound::Excluded(a) => a.succ().unwrap(), 172 | // Bound::Unbounded => T::MIN, 173 | // }) 174 | // } 175 | // } else { 176 | // None 177 | // } 178 | // } 179 | } 180 | 181 | impl fmt::Debug for AnyRange { 182 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 183 | match &self.start { 184 | Bound::Included(v) => v.fmt(f)?, 185 | Bound::Excluded(v) => write!(f, "{:?}.", v)?, 186 | Bound::Unbounded => write!(f, ".")?, 187 | } 188 | 189 | match &self.end { 190 | Bound::Included(v) => write!(f, "..={:?}", v), 191 | Bound::Excluded(v) => write!(f, "..{:?}", v), 192 | Bound::Unbounded => write!(f, ".."), 193 | } 194 | } 195 | } 196 | 197 | impl<'a, T> AnyRange<&'a T> { 198 | pub fn ref_is_empty(&self) -> bool 199 | where 200 | T: PartialEnum + Measure, 201 | { 202 | is_range_empty(self.start_bound().cloned(), self.end_bound().cloned()) 203 | } 204 | } 205 | 206 | impl PartialEq> for AnyRange 207 | where 208 | T: Measure + PartialOrd + PartialEnum, 209 | U: PartialEnum, 210 | { 211 | fn eq(&self, other: &AnyRange) -> bool { 212 | direct_bound_partial_eq(self.start_bound(), other.start_bound(), true) 213 | && direct_bound_partial_eq(self.end_bound(), other.end_bound(), false) 214 | } 215 | } 216 | 217 | impl Eq for AnyRange where T: Measure + PartialEnum + Ord {} 218 | 219 | impl PartialOrd> for AnyRange 220 | where 221 | T: Measure + PartialOrd + PartialEnum, 222 | U: PartialEnum, 223 | { 224 | fn partial_cmp(&self, other: &AnyRange) -> Option { 225 | // Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound())) 226 | match direct_bound_partial_cmp(self.start_bound(), other.start_bound(), true) { 227 | Some(BoundOrdering::Excluded(_)) => Some(Ordering::Less), 228 | Some(BoundOrdering::Included(false)) => Some(Ordering::Greater), 229 | Some(BoundOrdering::Included(true)) => { 230 | match direct_bound_partial_cmp(self.end_bound(), other.end_bound(), false) { 231 | Some(BoundOrdering::Excluded(_)) => Some(Ordering::Greater), 232 | Some(BoundOrdering::Included(false)) => Some(Ordering::Less), 233 | Some(BoundOrdering::Included(true)) => Some(Ordering::Equal), 234 | None => None, 235 | } 236 | } 237 | None => None, 238 | } 239 | } 240 | } 241 | 242 | impl Ord for AnyRange 243 | where 244 | T: Measure + PartialEnum + Ord, 245 | { 246 | fn cmp(&self, other: &Self) -> Ordering { 247 | // Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound())) 248 | match direct_bound_cmp(self.start_bound(), other.start_bound(), true) { 249 | BoundOrdering::Excluded(_) => Ordering::Less, 250 | BoundOrdering::Included(false) => Ordering::Greater, 251 | BoundOrdering::Included(true) => { 252 | match direct_bound_cmp(self.end_bound(), other.end_bound(), false) { 253 | BoundOrdering::Excluded(_) => Ordering::Greater, 254 | BoundOrdering::Included(false) => Ordering::Less, 255 | BoundOrdering::Included(true) => Ordering::Equal, 256 | } 257 | } 258 | } 259 | } 260 | } 261 | 262 | impl Hash for AnyRange 263 | where 264 | T: Hash + PartialEnum, 265 | { 266 | fn hash(&self, h: &mut H) { 267 | Directed::Start(self.start_bound()).hash(h); 268 | Directed::End(self.end_bound()).hash(h); 269 | } 270 | } 271 | 272 | impl AnyRange<&T> { 273 | pub fn cloned(self) -> AnyRange { 274 | AnyRange { 275 | start: self.start.cloned(), 276 | end: self.end.cloned(), 277 | } 278 | } 279 | } 280 | 281 | impl RangeBounds for AnyRange { 282 | fn start_bound(&self) -> Bound<&T> { 283 | match &self.start { 284 | Bound::Included(v) => Bound::Included(v), 285 | Bound::Excluded(v) => Bound::Excluded(v), 286 | Bound::Unbounded => Bound::Unbounded, 287 | } 288 | } 289 | 290 | fn end_bound(&self) -> Bound<&T> { 291 | match &self.end { 292 | Bound::Included(v) => Bound::Included(v), 293 | Bound::Excluded(v) => Bound::Excluded(v), 294 | Bound::Unbounded => Bound::Unbounded, 295 | } 296 | } 297 | } 298 | 299 | impl From> for AnyRange { 300 | fn from(value: std::ops::Range) -> Self { 301 | Self { 302 | start: Bound::Included(value.start), 303 | end: Bound::Excluded(value.end), 304 | } 305 | } 306 | } 307 | 308 | impl From> for AnyRange { 309 | fn from(value: std::ops::RangeInclusive) -> Self { 310 | let (start, end) = value.into_inner(); 311 | 312 | Self { 313 | start: Bound::Included(start), 314 | end: Bound::Included(end), 315 | } 316 | } 317 | } 318 | 319 | impl From> for AnyRange { 320 | fn from(value: std::ops::RangeFrom) -> Self { 321 | Self { 322 | start: Bound::Included(value.start), 323 | end: Bound::Unbounded, 324 | } 325 | } 326 | } 327 | 328 | impl From> for AnyRange { 329 | fn from(value: std::ops::RangeTo) -> Self { 330 | Self { 331 | start: Bound::Unbounded, 332 | end: Bound::Excluded(value.end), 333 | } 334 | } 335 | } 336 | 337 | impl From> for AnyRange { 338 | fn from(value: std::ops::RangeToInclusive) -> Self { 339 | Self { 340 | start: Bound::Unbounded, 341 | end: Bound::Included(value.end), 342 | } 343 | } 344 | } 345 | 346 | impl From for AnyRange { 347 | fn from(_: std::ops::RangeFull) -> Self { 348 | Self { 349 | start: Bound::Unbounded, 350 | end: Bound::Unbounded, 351 | } 352 | } 353 | } 354 | 355 | #[cfg(test)] 356 | mod tests { 357 | use super::*; 358 | 359 | #[test] 360 | fn intersection_test1() { 361 | let a: AnyRange = ('A'..='A').into(); 362 | assert!(a.intersects(&a)) 363 | } 364 | 365 | #[test] 366 | fn intersection_test2() { 367 | let a: AnyRange = ('A'..='A').into(); 368 | let b: AnyRange = ('B'..='B').into(); 369 | assert!(!a.intersects(&b)) 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /src/range/bound.rs: -------------------------------------------------------------------------------- 1 | use super::{direct_bound_partial_cmp, BoundOrd, BoundOrdering, BoundPartialOrd, Measure}; 2 | use range_traits::PartialEnum; 3 | use std::{ 4 | cmp::Ordering, 5 | hash::{Hash, Hasher}, 6 | ops::Bound, 7 | }; 8 | 9 | /// Types that can be interpreted as range bounds. 10 | pub trait AsBound { 11 | type Item; 12 | 13 | fn bound(&self) -> Bound<&Self::Item>; 14 | } 15 | 16 | impl AsBound for u8 { 17 | type Item = u8; 18 | 19 | fn bound(&self) -> Bound<&u8> { 20 | Bound::Included(self) 21 | } 22 | } 23 | 24 | impl<'a, T> AsBound for Bound<&'a T> { 25 | type Item = T; 26 | 27 | fn bound(&self) -> Bound<&T> { 28 | *self 29 | } 30 | } 31 | 32 | #[inline(always)] 33 | pub(crate) fn invert_bound(bound: Bound) -> Option> { 34 | match bound { 35 | Bound::Unbounded => None, 36 | Bound::Included(t) => Some(Bound::Excluded(t)), 37 | Bound::Excluded(t) => Some(Bound::Included(t)), 38 | } 39 | } 40 | 41 | #[derive(Clone, Copy, Debug)] 42 | pub enum Directed { 43 | Start(T), 44 | End(T), 45 | } 46 | 47 | impl Directed { 48 | /// Returns the directed value, without direction. 49 | pub fn unwrap(self) -> T { 50 | match self { 51 | Self::Start(t) => t, 52 | Self::End(t) => t, 53 | } 54 | } 55 | 56 | /// Returns a reference to the directed value, without direction. 57 | pub fn value(&self) -> &T { 58 | match self { 59 | Self::Start(t) => t, 60 | Self::End(t) => t, 61 | } 62 | } 63 | } 64 | 65 | impl Directed> { 66 | pub fn as_ref(&self) -> Directed> { 67 | match self { 68 | Directed::Start(b) => Directed::Start(match b { 69 | Bound::Included(b) => Bound::Included(b), 70 | Bound::Excluded(b) => Bound::Excluded(b), 71 | Bound::Unbounded => Bound::Unbounded, 72 | }), 73 | Directed::End(b) => Directed::End(match b { 74 | Bound::Included(b) => Bound::Included(b), 75 | Bound::Excluded(b) => Bound::Excluded(b), 76 | Bound::Unbounded => Bound::Unbounded, 77 | }), 78 | } 79 | } 80 | } 81 | 82 | impl<'a, T: Hash + PartialEnum> Hash for Directed> { 83 | fn hash(&self, h: &mut H) { 84 | match self { 85 | Directed::Start(b) => match b { 86 | Bound::Included(b) => b.hash(h), 87 | Bound::Excluded(b) => match b.succ() { 88 | Some(c) => c.hash(h), 89 | None => b.hash(h), 90 | }, 91 | Bound::Unbounded => (), 92 | }, 93 | Directed::End(b) => match b { 94 | Bound::Included(b) => b.hash(h), 95 | Bound::Excluded(b) => match b.pred() { 96 | Some(c) => c.hash(h), 97 | None => b.hash(h), 98 | }, 99 | Bound::Unbounded => (), 100 | }, 101 | } 102 | } 103 | } 104 | 105 | impl PartialEq>> for Directed> 106 | where 107 | T: Measure + PartialOrd + PartialEnum, 108 | U: PartialEnum, 109 | { 110 | fn eq(&self, other: &Directed>) -> bool { 111 | self.partial_cmp(other) == Some(Ordering::Equal) 112 | } 113 | } 114 | 115 | impl Eq for Directed> where T: Measure + Ord + PartialEnum {} 116 | 117 | impl PartialOrd>> for Directed> 118 | where 119 | T: Measure + PartialOrd + PartialEnum, 120 | U: PartialEnum, 121 | { 122 | fn partial_cmp(&self, other: &Directed>) -> Option { 123 | match self.bound_partial_cmp(other) { 124 | Some(BoundOrdering::Included(true)) => Some(Ordering::Equal), 125 | Some(BoundOrdering::Included(false)) => match other { 126 | Directed::Start(_) => Some(Ordering::Greater), 127 | Directed::End(_) => Some(Ordering::Less), 128 | }, 129 | Some(BoundOrdering::Excluded(_)) => match other { 130 | Directed::Start(_) => Some(Ordering::Less), 131 | Directed::End(_) => Some(Ordering::Greater), 132 | }, 133 | None => None, 134 | } 135 | } 136 | } 137 | 138 | impl Ord for Directed> 139 | where 140 | T: Measure + Ord + PartialEnum, 141 | { 142 | fn cmp(&self, other: &Directed>) -> Ordering { 143 | match self.bound_cmp(other) { 144 | BoundOrdering::Included(true) => Ordering::Equal, 145 | BoundOrdering::Included(false) => match other { 146 | Directed::Start(_) => Ordering::Greater, 147 | Directed::End(_) => Ordering::Less, 148 | }, 149 | BoundOrdering::Excluded(_) => match other { 150 | Directed::Start(_) => Ordering::Less, 151 | Directed::End(_) => Ordering::Greater, 152 | }, 153 | } 154 | } 155 | } 156 | 157 | pub(crate) fn min_bound<'a, T: Measure + PartialOrd + PartialEnum>( 158 | a: Bound<&'a T>, 159 | b: Bound<&'a T>, 160 | start: bool, 161 | ) -> Bound<&'a T> { 162 | match direct_bound_partial_cmp(a, b, start) { 163 | Some(BoundOrdering::Included(_)) => { 164 | if start { 165 | b 166 | } else { 167 | a 168 | } 169 | } 170 | _ => { 171 | if start { 172 | a 173 | } else { 174 | b 175 | } 176 | } 177 | } 178 | } 179 | 180 | pub(crate) fn max_bound<'a, T: Measure + PartialOrd + PartialEnum>( 181 | a: Bound<&'a T>, 182 | b: Bound<&'a T>, 183 | start: bool, 184 | ) -> Bound<&'a T> { 185 | match direct_bound_partial_cmp(a, b, start) { 186 | Some(BoundOrdering::Included(_)) => { 187 | if start { 188 | a 189 | } else { 190 | b 191 | } 192 | } 193 | _ => { 194 | if start { 195 | b 196 | } else { 197 | a 198 | } 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/range/from_excluded.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Bound, RangeBounds}; 2 | 3 | /// Range with only an start bound, excluded. 4 | pub struct RangeFromExcluded { 5 | pub start: T, 6 | } 7 | 8 | impl RangeFromExcluded { 9 | pub const fn new(start: T) -> RangeFromExcluded { 10 | RangeFromExcluded { start } 11 | } 12 | } 13 | 14 | impl RangeBounds for RangeFromExcluded { 15 | fn start_bound(&self) -> Bound<&T> { 16 | Bound::Excluded(&self.start) 17 | } 18 | 19 | fn end_bound(&self) -> Bound<&T> { 20 | Bound::Unbounded 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/range/from_excluded_to.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Bound, RangeBounds}; 2 | 3 | /// Range where both bounds are excluded. 4 | pub struct RangeFromExcludedTo { 5 | pub start: T, 6 | pub end: T, 7 | } 8 | 9 | impl RangeFromExcludedTo { 10 | pub const fn new(start: T, end: T) -> RangeFromExcludedTo { 11 | RangeFromExcludedTo { start, end } 12 | } 13 | } 14 | 15 | impl RangeBounds for RangeFromExcludedTo { 16 | fn start_bound(&self) -> Bound<&T> { 17 | Bound::Excluded(&self.start) 18 | } 19 | 20 | fn end_bound(&self) -> Bound<&T> { 21 | Bound::Excluded(&self.end) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/range/from_excluded_to_included.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Bound, RangeBounds}; 2 | 3 | /// Range with an excluded start bound and included end bound. 4 | pub struct RangeFromExcludedToIncluded { 5 | pub start: T, 6 | pub end: T, 7 | } 8 | 9 | impl RangeFromExcludedToIncluded { 10 | pub const fn new(start: T, end: T) -> RangeFromExcludedToIncluded { 11 | RangeFromExcludedToIncluded { start, end } 12 | } 13 | } 14 | 15 | impl RangeBounds for RangeFromExcludedToIncluded { 16 | fn start_bound(&self) -> Bound<&T> { 17 | Bound::Excluded(&self.start) 18 | } 19 | 20 | fn end_bound(&self) -> Bound<&T> { 21 | Bound::Included(&self.end) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/range/ordering.rs: -------------------------------------------------------------------------------- 1 | use super::{AsBound, AsRange, Directed, Measure}; 2 | use range_traits::{MaybeBounded, PartialEnum}; 3 | use std::{ 4 | cmp::{Ordering, PartialOrd}, 5 | ops::Bound, 6 | }; 7 | 8 | #[derive(Debug)] 9 | pub enum RangeOrdering { 10 | Before(bool), 11 | Intersecting(bool, bool), 12 | After(bool), 13 | } 14 | 15 | impl RangeOrdering { 16 | pub fn is_before(&self, connected: bool) -> bool { 17 | match self { 18 | RangeOrdering::Before(c) => !*c || !connected, 19 | _ => false, 20 | } 21 | } 22 | 23 | pub fn is_after(&self, connected: bool) -> bool { 24 | match self { 25 | RangeOrdering::After(c) => !*c || !connected, 26 | _ => false, 27 | } 28 | } 29 | 30 | pub fn matches(&self, connected: bool) -> bool { 31 | match self { 32 | RangeOrdering::Before(c) => *c && connected, 33 | RangeOrdering::After(c) => *c && connected, 34 | RangeOrdering::Intersecting(_, _) => true, 35 | } 36 | } 37 | } 38 | 39 | pub trait RangePartialOrd { 40 | fn range_partial_cmp>(&self, other: &R) -> Option; 41 | } 42 | 43 | impl RangePartialOrd for R 44 | where 45 | R::Item: PartialOrd + Measure, 46 | U: PartialEnum, 47 | { 48 | fn range_partial_cmp>(&self, other: &S) -> Option { 49 | match direct_bound_partial_cmp(self.start(), other.start(), true) { 50 | Some(BoundOrdering::Included(limit_before)) => { 51 | match inverse_bound_partial_cmp(self.start(), other.end(), false) { 52 | Some(BoundOrdering::Included(_)) => { 53 | match direct_bound_partial_cmp(self.end(), other.end(), false) { 54 | Some(BoundOrdering::Included(limit_after)) => { 55 | Some(RangeOrdering::Intersecting(limit_before, limit_after)) 56 | } 57 | Some(BoundOrdering::Excluded(_)) => { 58 | Some(RangeOrdering::Intersecting(limit_before, false)) 59 | } 60 | None => None, 61 | } 62 | } 63 | Some(BoundOrdering::Excluded(limit_after)) => { 64 | Some(RangeOrdering::After(limit_after)) 65 | } 66 | None => None, 67 | } 68 | } 69 | Some(BoundOrdering::Excluded(_)) => { 70 | match inverse_bound_partial_cmp(self.end(), other.start(), true) { 71 | Some(BoundOrdering::Included(_)) => { 72 | match direct_bound_partial_cmp(self.end(), other.end(), false) { 73 | Some(BoundOrdering::Included(limit_after)) => { 74 | Some(RangeOrdering::Intersecting(false, limit_after)) 75 | } 76 | Some(BoundOrdering::Excluded(_)) => { 77 | Some(RangeOrdering::Intersecting(false, false)) 78 | } 79 | None => None, 80 | } 81 | } 82 | Some(BoundOrdering::Excluded(limit_before)) => { 83 | Some(RangeOrdering::Before(limit_before)) 84 | } 85 | None => None, 86 | } 87 | } 88 | None => None, 89 | } 90 | } 91 | } 92 | 93 | pub enum BoundOrdering { 94 | Included(bool), 95 | Excluded(bool), 96 | } 97 | 98 | pub trait BoundPartialOrd { 99 | fn bound_partial_cmp>(&self, other: &Directed) 100 | -> Option; 101 | } 102 | 103 | impl BoundPartialOrd for Directed 104 | where 105 | B::Item: PartialOrd + Measure + PartialEnum, 106 | U: PartialEnum, 107 | { 108 | fn bound_partial_cmp>( 109 | &self, 110 | other: &Directed, 111 | ) -> Option { 112 | match (self, other) { 113 | (Directed::Start(a), Directed::Start(b)) => { 114 | direct_bound_partial_cmp(a.bound(), b.bound(), true) 115 | } 116 | (Directed::Start(a), Directed::End(b)) => { 117 | inverse_bound_partial_cmp(a.bound(), b.bound(), false) 118 | } 119 | (Directed::End(a), Directed::Start(b)) => { 120 | inverse_bound_partial_cmp(a.bound(), b.bound(), true) 121 | } 122 | (Directed::End(a), Directed::End(b)) => { 123 | direct_bound_partial_cmp(a.bound(), b.bound(), false) 124 | } 125 | } 126 | } 127 | } 128 | 129 | pub trait BoundOrd { 130 | fn bound_cmp>(&self, other: &Directed) -> BoundOrdering; 131 | } 132 | 133 | impl BoundOrd for Directed 134 | where 135 | B::Item: Ord + Measure + PartialEnum, 136 | { 137 | fn bound_cmp>(&self, other: &Directed) -> BoundOrdering { 138 | match (self, other) { 139 | (Directed::Start(a), Directed::Start(b)) => { 140 | direct_bound_cmp(a.bound(), b.bound(), true) 141 | } 142 | (Directed::Start(a), Directed::End(b)) => { 143 | inverse_bound_cmp(a.bound(), b.bound(), false) 144 | } 145 | (Directed::End(a), Directed::Start(b)) => inverse_bound_cmp(a.bound(), b.bound(), true), 146 | (Directed::End(a), Directed::End(b)) => direct_bound_cmp(a.bound(), b.bound(), false), 147 | } 148 | } 149 | } 150 | 151 | pub enum Dist { 152 | Equals, 153 | Zero, 154 | One, 155 | More, 156 | } 157 | 158 | fn dist(t: &T, u: &U) -> Dist 159 | where 160 | T: PartialEnum + PartialEq, 161 | { 162 | if t == u { 163 | return Dist::Equals; 164 | } 165 | 166 | if let Some(s) = t.succ() { 167 | if s == *u { 168 | return Dist::Zero; 169 | } else { 170 | match s.succ() { 171 | Some(ss) if ss == *u => return Dist::One, 172 | _ => (), 173 | } 174 | } 175 | } 176 | 177 | if let Some(s) = t.pred() { 178 | if s == *u { 179 | return Dist::Zero; 180 | } else { 181 | match s.pred() { 182 | Some(ss) if ss == *u => return Dist::One, 183 | _ => (), 184 | } 185 | } 186 | } 187 | 188 | Dist::More 189 | } 190 | 191 | fn distance_zero(t: &T, u: &U) -> bool 192 | where 193 | T: PartialEnum + PartialEq, 194 | { 195 | match t.succ() { 196 | Some(s) if s == *u => return true, 197 | _ => (), 198 | } 199 | 200 | match t.pred() { 201 | Some(p) if p == *u => return true, 202 | _ => (), 203 | } 204 | 205 | false 206 | } 207 | 208 | pub(crate) fn direct_bound_partial_cmp( 209 | b1: Bound<&T>, 210 | b2: Bound<&U>, 211 | start: bool, 212 | ) -> Option 213 | where 214 | T: Measure + PartialOrd + PartialEnum, 215 | U: PartialEnum, 216 | { 217 | let included_ord = if start { 218 | Ordering::Greater 219 | } else { 220 | Ordering::Less 221 | }; 222 | 223 | match (b1, b2) { 224 | (Bound::Included(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { 225 | Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), 226 | Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), 227 | Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), 228 | None => None, 229 | }, 230 | (Bound::Included(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { 231 | Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), 232 | Some(ord) if ord == included_ord => { 233 | Some(BoundOrdering::Included(distance_zero(v1, v2))) 234 | } 235 | Some(_) => Some(BoundOrdering::Excluded(false)), 236 | None => None, 237 | }, 238 | (Bound::Included(v1), Bound::Unbounded) => Some(BoundOrdering::Included( 239 | (start && U::min().map(|m| *v1 == m).unwrap_or(false)) 240 | || (!start && U::max().map(|m| *v1 == m).unwrap_or(false)), 241 | )), 242 | (Bound::Excluded(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { 243 | Some(Ordering::Equal) => Some(BoundOrdering::Included(false)), 244 | Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), 245 | Some(_) => match dist(v1, v2) { 246 | Dist::Zero => Some(BoundOrdering::Included(true)), 247 | Dist::One => Some(BoundOrdering::Excluded(true)), 248 | _ => Some(BoundOrdering::Excluded(false)), 249 | }, 250 | None => None, 251 | }, 252 | (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { 253 | Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), 254 | Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), 255 | Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), 256 | None => None, 257 | }, 258 | (Bound::Excluded(_), Bound::Unbounded) => Some(BoundOrdering::Included(false)), 259 | (Bound::Unbounded, Bound::Included(v2)) => { 260 | if (start && U::min().map(|m| *v2 == m).unwrap_or(false)) 261 | || (!start && U::max().map(|m| *v2 == m).unwrap_or(false)) 262 | { 263 | Some(BoundOrdering::Included(true)) 264 | } else { 265 | Some(BoundOrdering::Excluded( 266 | (start 267 | && v2 268 | .pred() 269 | .and_then(|pred| U::min().map(|m| pred == m)) 270 | .unwrap_or(false)) || (!start 271 | && v2 272 | .succ() 273 | .and_then(|succ| U::min().map(|m| succ == m)) 274 | .unwrap_or(false)), 275 | )) 276 | } 277 | } 278 | (Bound::Unbounded, Bound::Excluded(_)) => Some(BoundOrdering::Excluded(false)), 279 | (Bound::Unbounded, Bound::Unbounded) => Some(BoundOrdering::Included(true)), 280 | } 281 | } 282 | 283 | pub(crate) fn direct_bound_cmp(b1: Bound<&T>, b2: Bound<&T>, start: bool) -> BoundOrdering 284 | where 285 | T: Measure + PartialEnum + Ord, 286 | { 287 | let included_ord = if start { 288 | Ordering::Greater 289 | } else { 290 | Ordering::Less 291 | }; 292 | 293 | match (b1, b2) { 294 | (Bound::Included(v1), Bound::Included(v2)) => match v1.cmp(v2) { 295 | Ordering::Equal => BoundOrdering::Included(true), 296 | ord if ord == included_ord => BoundOrdering::Included(false), 297 | _ => BoundOrdering::Excluded(distance_zero(v1, v2)), 298 | }, 299 | (Bound::Included(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { 300 | Ordering::Equal => BoundOrdering::Excluded(true), 301 | ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), 302 | _ => BoundOrdering::Excluded(false), 303 | }, 304 | (Bound::Included(v1), Bound::Unbounded) => BoundOrdering::Included( 305 | (start && Some(v1) == ::min().as_ref()) 306 | || (!start && Some(v1) == ::max().as_ref()), 307 | ), 308 | (Bound::Excluded(v1), Bound::Included(v2)) => match v1.cmp(v2) { 309 | Ordering::Equal => BoundOrdering::Included(false), 310 | ord if ord == included_ord => BoundOrdering::Included(false), 311 | _ => match dist(v1, v2) { 312 | Dist::Zero => BoundOrdering::Included(true), 313 | Dist::One => BoundOrdering::Excluded(true), 314 | _ => BoundOrdering::Excluded(false), 315 | }, 316 | }, 317 | (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { 318 | Ordering::Equal => BoundOrdering::Included(true), 319 | ord if ord == included_ord => BoundOrdering::Included(false), 320 | _ => BoundOrdering::Excluded(distance_zero(v1, v2)), 321 | }, 322 | (Bound::Excluded(_), Bound::Unbounded) => BoundOrdering::Included(false), 323 | (Bound::Unbounded, Bound::Included(v2)) => { 324 | if (start && ::min().as_ref() == Some(v2)) 325 | || (!start && ::max().as_ref() == Some(v2)) 326 | { 327 | BoundOrdering::Included(true) 328 | } else { 329 | BoundOrdering::Excluded( 330 | (start 331 | && v2 332 | .pred() 333 | .map(|pred| ::min() == Some(pred)) 334 | .unwrap_or(false)) || (!start 335 | && v2 336 | .succ() 337 | .map(|succ| ::min() == Some(succ)) 338 | .unwrap_or(false)), 339 | ) 340 | } 341 | } 342 | (Bound::Unbounded, Bound::Excluded(_)) => BoundOrdering::Excluded(false), 343 | (Bound::Unbounded, Bound::Unbounded) => BoundOrdering::Included(true), 344 | } 345 | } 346 | 347 | pub(crate) fn direct_bound_partial_eq(b1: Bound<&T>, b2: Bound<&U>, start: bool) -> bool 348 | where 349 | T: Measure + PartialOrd + PartialEnum, 350 | U: PartialEnum, 351 | { 352 | match direct_bound_partial_cmp(b1, b2, start) { 353 | Some(BoundOrdering::Included(eq)) => eq, 354 | _ => false, 355 | } 356 | } 357 | 358 | // pub(crate) fn direct_bound_eq(b1: Bound<&T>, b2: Bound<&T>, start: bool) -> bool where T: Measure + Ord { 359 | // match direct_bound_cmp(b1, b2, start) { 360 | // BoundOrdering::Included(eq) => eq, 361 | // _ => false 362 | // } 363 | // } 364 | 365 | pub(crate) fn inverse_bound_partial_cmp( 366 | b1: Bound<&T>, 367 | b2: Bound<&U>, 368 | b2_start: bool, 369 | ) -> Option 370 | where 371 | T: Measure + PartialOrd + PartialEnum, 372 | U: PartialEnum, 373 | { 374 | let included_ord = if b2_start { 375 | Ordering::Greater 376 | } else { 377 | Ordering::Less 378 | }; 379 | 380 | match (b1, b2) { 381 | (Bound::Included(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { 382 | Some(Ordering::Equal) => Some(BoundOrdering::Included(true)), 383 | Some(ord) if ord == included_ord => Some(BoundOrdering::Included(false)), 384 | Some(_) => Some(BoundOrdering::Excluded(distance_zero(v1, v2))), 385 | None => None, 386 | }, 387 | (Bound::Included(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { 388 | Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), 389 | Some(ord) if ord == included_ord => { 390 | Some(BoundOrdering::Included(distance_zero(v1, v2))) 391 | } 392 | Some(_) => Some(BoundOrdering::Excluded(false)), 393 | None => None, 394 | }, 395 | (Bound::Included(_), Bound::Unbounded) => Some(BoundOrdering::Included(false)), 396 | (Bound::Excluded(v1), Bound::Included(v2)) => match v1.partial_cmp(v2) { 397 | Some(Ordering::Equal) => Some(BoundOrdering::Excluded(true)), // []v2=v1 398 | Some(ord) if ord == included_ord => { 399 | Some(BoundOrdering::Included(distance_zero(v1, v2))) 400 | } 401 | Some(_) => Some(BoundOrdering::Excluded(false)), 402 | None => None, 403 | }, 404 | (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.partial_cmp(v2) { 405 | Some(Ordering::Equal) => Some(BoundOrdering::Excluded(false)), 406 | Some(ord) if ord == included_ord => match dist(v1, v2) { 407 | Dist::Zero => Some(BoundOrdering::Excluded(true)), // v2 [] v1 408 | Dist::One => Some(BoundOrdering::Included(true)), // v2 [ x ] v1 409 | _ => Some(BoundOrdering::Included(false)), // v2 [ x .. y ] v1 410 | }, 411 | Some(_) => Some(BoundOrdering::Excluded(false)), // ] v1 v2 [ 412 | None => None, 413 | }, 414 | (Bound::Excluded(v1), Bound::Unbounded) => { 415 | if (!b2_start && U::max().map(|m| *v1 == m).unwrap_or(false)) 416 | || (b2_start && U::min().map(|m| *v1 == m).unwrap_or(false)) 417 | { 418 | Some(BoundOrdering::Excluded(true)) 419 | } else { 420 | Some(BoundOrdering::Included( 421 | (!b2_start 422 | && v1 423 | .pred() 424 | .map(|pred| U::min().map(|m| pred == m).unwrap_or(false)) 425 | .unwrap_or(false)) || (b2_start 426 | && v1 427 | .succ() 428 | .map(|succ| U::max().map(|m| succ == m).unwrap_or(false)) 429 | .unwrap_or(false)), 430 | )) 431 | } 432 | } 433 | (Bound::Unbounded, Bound::Included(_)) => Some(BoundOrdering::Included(false)), 434 | (Bound::Unbounded, Bound::Excluded(v2)) => { 435 | if (!b2_start && U::min().map(|m| *v2 == m).unwrap_or(false)) 436 | || (b2_start && U::max().map(|m| *v2 == m).unwrap_or(false)) 437 | { 438 | Some(BoundOrdering::Excluded(true)) 439 | } else { 440 | Some(BoundOrdering::Included( 441 | (!b2_start 442 | && v2 443 | .pred() 444 | .map(|pred| U::min().map(|m| pred == m).unwrap_or(false)) 445 | .unwrap_or(false)) || (b2_start 446 | && v2 447 | .succ() 448 | .map(|succ| U::max().map(|m| succ == m).unwrap_or(false)) 449 | .unwrap_or(false)), 450 | )) 451 | } 452 | } 453 | (Bound::Unbounded, Bound::Unbounded) => Some(BoundOrdering::Included(false)), 454 | } 455 | } 456 | 457 | pub(crate) fn inverse_bound_cmp(b1: Bound<&T>, b2: Bound<&T>, b2_start: bool) -> BoundOrdering 458 | where 459 | T: Measure + Ord + PartialEnum, 460 | { 461 | let included_ord = if b2_start { 462 | Ordering::Greater 463 | } else { 464 | Ordering::Less 465 | }; 466 | 467 | match (b1, b2) { 468 | (Bound::Included(v1), Bound::Included(v2)) => match v1.cmp(v2) { 469 | Ordering::Equal => BoundOrdering::Included(true), 470 | ord if ord == included_ord => BoundOrdering::Included(false), 471 | _ => BoundOrdering::Excluded(distance_zero(v1, v2)), 472 | }, 473 | (Bound::Included(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { 474 | Ordering::Equal => BoundOrdering::Excluded(true), 475 | ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), 476 | _ => BoundOrdering::Excluded(false), 477 | }, 478 | (Bound::Included(_), Bound::Unbounded) => BoundOrdering::Included(false), 479 | (Bound::Excluded(v1), Bound::Included(v2)) => match v1.cmp(v2) { 480 | Ordering::Equal => BoundOrdering::Excluded(true), // []v2=v1 481 | ord if ord == included_ord => BoundOrdering::Included(distance_zero(v1, v2)), 482 | _ => BoundOrdering::Excluded(false), 483 | }, 484 | (Bound::Excluded(v1), Bound::Excluded(v2)) => match v1.cmp(v2) { 485 | Ordering::Equal => BoundOrdering::Excluded(false), 486 | ord if ord == included_ord => match dist(v1, v2) { 487 | Dist::Zero => BoundOrdering::Excluded(true), // v2 [] v1 488 | Dist::One => BoundOrdering::Included(true), // v2 [ x ] v1 489 | _ => BoundOrdering::Included(false), // v2 [ x .. y ] v1 490 | }, 491 | _ => BoundOrdering::Excluded(false), // ] v1 v2 [ 492 | }, 493 | (Bound::Excluded(v1), Bound::Unbounded) => { 494 | if (!b2_start 495 | && ::max() 496 | .map(|m| *v1 == m) 497 | .unwrap_or(false)) 498 | || (b2_start 499 | && ::min() 500 | .map(|m| *v1 == m) 501 | .unwrap_or(false)) 502 | { 503 | BoundOrdering::Excluded(true) 504 | } else { 505 | BoundOrdering::Included( 506 | (!b2_start 507 | && v1 508 | .pred() 509 | .map(|pred| { 510 | ::min() 511 | .map(|m| pred == m) 512 | .unwrap_or(false) 513 | }) 514 | .unwrap_or(false)) || (b2_start 515 | && v1 516 | .succ() 517 | .map(|succ| { 518 | ::max() 519 | .map(|m| succ == m) 520 | .unwrap_or(false) 521 | }) 522 | .unwrap_or(false)), 523 | ) 524 | } 525 | } 526 | (Bound::Unbounded, Bound::Included(_)) => BoundOrdering::Included(false), 527 | (Bound::Unbounded, Bound::Excluded(v2)) => { 528 | if (!b2_start 529 | && ::min() 530 | .map(|m| *v2 == m) 531 | .unwrap_or(false)) 532 | || (b2_start 533 | && ::max() 534 | .map(|m| *v2 == m) 535 | .unwrap_or(false)) 536 | { 537 | BoundOrdering::Excluded(true) 538 | } else { 539 | BoundOrdering::Included( 540 | (!b2_start 541 | && v2 542 | .pred() 543 | .map(|pred| { 544 | ::min() 545 | .map(|m| pred == m) 546 | .unwrap_or(false) 547 | }) 548 | .unwrap_or(false)) || (b2_start 549 | && v2 550 | .succ() 551 | .map(|succ| { 552 | ::max() 553 | .map(|m| succ == m) 554 | .unwrap_or(false) 555 | }) 556 | .unwrap_or(false)), 557 | ) 558 | } 559 | } 560 | (Bound::Unbounded, Bound::Unbounded) => BoundOrdering::Included(false), 561 | } 562 | } 563 | 564 | // fn inverse_bound_partial_eq(b1: Bound<&T>, b2: Bound<&U>, start: bool) -> bool where T: Measure + PartialOrd { 565 | // match inverse_bound_partial_cmp(b1, b2, start) { 566 | // Some(BoundOrdering::Included(eq)) => eq, 567 | // _ => false 568 | // } 569 | // } 570 | -------------------------------------------------------------------------------- /src/serde.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use btree_slab::generic::Node; 4 | use cc_traits::{SimpleCollectionMut, SimpleCollectionRef, Slab, SlabMut}; 5 | use range_traits::{Measure, PartialEnum}; 6 | use serde::{ 7 | de::Error, 8 | ser::{SerializeMap, SerializeSeq, SerializeTuple}, 9 | Deserialize, Serialize, 10 | }; 11 | 12 | use crate::{generic, AnyRange}; 13 | 14 | impl Serialize for AnyRange { 15 | fn serialize(&self, serializer: S) -> Result 16 | where 17 | S: serde::Serializer, 18 | { 19 | let mut t = serializer.serialize_tuple(2)?; 20 | t.serialize_element(&self.start)?; 21 | t.serialize_element(&self.end)?; 22 | t.end() 23 | } 24 | } 25 | 26 | impl<'de, T: Deserialize<'de>> Deserialize<'de> for AnyRange { 27 | fn deserialize(deserializer: D) -> Result 28 | where 29 | D: serde::Deserializer<'de>, 30 | { 31 | struct Visitor(PhantomData); 32 | 33 | impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for Visitor { 34 | type Value = AnyRange; 35 | 36 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 37 | write!(formatter, "any range") 38 | } 39 | 40 | fn visit_seq(self, mut seq: A) -> Result 41 | where 42 | A: serde::de::SeqAccess<'de>, 43 | { 44 | let start = seq 45 | .next_element()? 46 | .ok_or_else(|| A::Error::custom("missing start bound"))?; 47 | let end = seq 48 | .next_element()? 49 | .ok_or_else(|| A::Error::custom("missing end bound"))?; 50 | Ok(AnyRange { start, end }) 51 | } 52 | } 53 | 54 | deserializer.deserialize_tuple(2, Visitor(PhantomData)) 55 | } 56 | } 57 | 58 | impl, ()>>> Serialize 59 | for generic::RangeSet 60 | { 61 | fn serialize(&self, serializer: S) -> Result 62 | where 63 | S: serde::Serializer, 64 | { 65 | let mut seq = serializer.serialize_seq(Some(self.range_count()))?; 66 | 67 | for range in self { 68 | seq.serialize_element(range)?; 69 | } 70 | 71 | seq.end() 72 | } 73 | } 74 | 75 | impl< 76 | 'de, 77 | T: Clone + PartialEnum + Measure + Deserialize<'de>, 78 | C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, ()>>, 79 | > Deserialize<'de> for generic::RangeSet 80 | { 81 | fn deserialize(deserializer: D) -> Result 82 | where 83 | D: serde::Deserializer<'de>, 84 | { 85 | struct Visitor(PhantomData<(T, C)>); 86 | 87 | impl< 88 | 'de, 89 | T: Clone + PartialEnum + Measure + Deserialize<'de>, 90 | C: Default 91 | + SimpleCollectionRef 92 | + SimpleCollectionMut 93 | + SlabMut, ()>>, 94 | > serde::de::Visitor<'de> for Visitor 95 | { 96 | type Value = generic::RangeSet; 97 | 98 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 99 | write!(formatter, "a range set") 100 | } 101 | 102 | fn visit_seq(self, mut seq: A) -> Result 103 | where 104 | A: serde::de::SeqAccess<'de>, 105 | { 106 | let mut result = generic::RangeSet::new(); 107 | 108 | while let Some(range) = seq.next_element::>()? { 109 | result.insert(range); 110 | } 111 | 112 | Ok(result) 113 | } 114 | } 115 | 116 | deserializer.deserialize_seq(Visitor(PhantomData)) 117 | } 118 | } 119 | 120 | impl, V>>> Serialize 121 | for generic::RangeMap 122 | { 123 | fn serialize(&self, serializer: S) -> Result 124 | where 125 | S: serde::Serializer, 126 | { 127 | let mut map = serializer.serialize_map(Some(self.range_count()))?; 128 | 129 | for (range, value) in self { 130 | map.serialize_entry(range, value)?; 131 | } 132 | 133 | map.end() 134 | } 135 | } 136 | 137 | impl< 138 | 'de, 139 | K: PartialEnum + Measure + Deserialize<'de>, 140 | V: Deserialize<'de>, 141 | C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, V>>, 142 | > Deserialize<'de> for generic::RangeMap 143 | { 144 | fn deserialize(deserializer: D) -> Result 145 | where 146 | D: serde::Deserializer<'de>, 147 | { 148 | struct Visitor(PhantomData<(K, V, C)>); 149 | 150 | impl< 151 | 'de, 152 | K: PartialEnum + Measure + Deserialize<'de>, 153 | V: Deserialize<'de>, 154 | C: Default + SimpleCollectionRef + SimpleCollectionMut + SlabMut, V>>, 155 | > serde::de::Visitor<'de> for Visitor 156 | { 157 | type Value = generic::RangeMap; 158 | 159 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 160 | write!(formatter, "a range map") 161 | } 162 | 163 | fn visit_map(self, mut map: A) -> Result 164 | where 165 | A: serde::de::MapAccess<'de>, 166 | { 167 | let mut result = generic::RangeMap::new(); 168 | 169 | while let Some((range, value)) = map.next_entry::, V>()? { 170 | if result.insert_disconnected(range, value).is_err() { 171 | return Err(A::Error::custom("unexpected connected range")); 172 | } 173 | } 174 | 175 | Ok(result) 176 | } 177 | } 178 | 179 | deserializer.deserialize_map(Visitor(PhantomData)) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /tests/insert.rs: -------------------------------------------------------------------------------- 1 | use btree_range_map::{RangeMap, RangeSet}; 2 | 3 | #[test] 4 | fn insert_single() { 5 | let mut range_map: RangeMap = RangeMap::new(); 6 | range_map.insert(00..05, true); 7 | assert_eq!(range_map.range_count(), 1); 8 | assert_eq!(range_map.get(02), Some(&true)); 9 | } 10 | 11 | /// Testing case (G) only. 12 | #[test] 13 | fn insert_exclusive_ranges() { 14 | let mut range_map: RangeMap = RangeMap::new(); 15 | 16 | range_map.insert(00..05, true); 17 | range_map.insert(10..15, false); 18 | range_map.insert(20..25, true); 19 | range_map.insert(30..35, false); 20 | range_map.insert(40..45, true); 21 | range_map.insert(50..55, false); 22 | range_map.insert(60..65, true); 23 | range_map.insert(70..75, false); 24 | range_map.insert(80..85, true); 25 | range_map.insert(90..95, false); 26 | 27 | assert_eq!(range_map.range_count(), 10); 28 | assert_eq!(range_map.get(02), Some(&true)); 29 | assert_eq!(range_map.get(07), None); 30 | assert_eq!(range_map.get(12), Some(&false)); 31 | assert_eq!(range_map.get(17), None); 32 | assert_eq!(range_map.get(22), Some(&true)); 33 | assert_eq!(range_map.get(27), None); 34 | assert_eq!(range_map.get(32), Some(&false)); 35 | assert_eq!(range_map.get(37), None); 36 | assert_eq!(range_map.get(42), Some(&true)); 37 | assert_eq!(range_map.get(47), None); 38 | assert_eq!(range_map.get(52), Some(&false)); 39 | assert_eq!(range_map.get(57), None); 40 | assert_eq!(range_map.get(62), Some(&true)); 41 | assert_eq!(range_map.get(67), None); 42 | assert_eq!(range_map.get(72), Some(&false)); 43 | assert_eq!(range_map.get(77), None); 44 | assert_eq!(range_map.get(82), Some(&true)); 45 | assert_eq!(range_map.get(87), None); 46 | assert_eq!(range_map.get(92), Some(&false)); 47 | assert_eq!(range_map.get(97), None); 48 | } 49 | 50 | #[test] 51 | fn insert_inclusive_ranges_a() { 52 | let mut range_map: RangeMap = RangeMap::new(); 53 | 54 | range_map.insert(00..20, true); // case (G) 55 | range_map.insert(05..15, false); // case (A) 56 | 57 | assert_eq!(range_map.range_count(), 3); 58 | assert_eq!(range_map.get(00), Some(&true)); 59 | assert_eq!(range_map.get(04), Some(&true)); 60 | assert_eq!(range_map.get(05), Some(&false)); 61 | assert_eq!(range_map.get(14), Some(&false)); 62 | assert_eq!(range_map.get(19), Some(&true)); 63 | assert_eq!(range_map.get(20), None); 64 | } 65 | 66 | #[test] 67 | fn insert_inclusive_ranges_b() { 68 | let mut range_map: RangeMap = RangeMap::new(); 69 | 70 | range_map.insert(00..20, true); // case (G) 71 | range_map.insert(10..30, false); // case (B) 72 | 73 | assert_eq!(range_map.range_count(), 2); 74 | assert_eq!(range_map.get(00), Some(&true)); 75 | assert_eq!(range_map.get(09), Some(&true)); 76 | assert_eq!(range_map.get(10), Some(&false)); 77 | assert_eq!(range_map.get(19), Some(&false)); 78 | assert_eq!(range_map.get(29), Some(&false)); 79 | assert_eq!(range_map.get(30), None); 80 | } 81 | 82 | #[test] 83 | fn insert_inclusive_ranges_ce() { 84 | let mut range_map: RangeMap = RangeMap::new(); 85 | 86 | range_map.insert(10..30, true); // case (G) 87 | range_map.insert(00..20, false); // cases (C) and (E) 88 | 89 | assert_eq!(range_map.range_count(), 2); 90 | assert_eq!(range_map.get(00), Some(&false)); 91 | assert_eq!(range_map.get(09), Some(&false)); 92 | assert_eq!(range_map.get(10), Some(&false)); 93 | assert_eq!(range_map.get(19), Some(&false)); 94 | assert_eq!(range_map.get(20), Some(&true)); 95 | assert_eq!(range_map.get(29), Some(&true)); 96 | assert_eq!(range_map.get(30), None); 97 | } 98 | 99 | #[test] 100 | fn insert_inclusive_ranges_bcd() { 101 | let mut range_map: RangeMap = RangeMap::new(); 102 | 103 | range_map.insert(10..15, true); // case (G) 104 | range_map.insert(20..25, true); // case (G) 105 | range_map.insert(30..35, true); // case (G) 106 | range_map.insert(10..35, false); // case (B, C, D) 107 | 108 | assert_eq!(range_map.range_count(), 1); 109 | assert_eq!(range_map.get(10), Some(&false)); 110 | assert_eq!(range_map.get(14), Some(&false)); 111 | assert_eq!(range_map.get(17), Some(&false)); 112 | assert_eq!(range_map.get(20), Some(&false)); 113 | assert_eq!(range_map.get(24), Some(&false)); 114 | assert_eq!(range_map.get(27), Some(&false)); 115 | assert_eq!(range_map.get(30), Some(&false)); 116 | assert_eq!(range_map.get(34), Some(&false)); 117 | assert_eq!(range_map.get(35), None); 118 | } 119 | 120 | #[test] 121 | fn insert_inclusive_ranges_cf() { 122 | let mut range_map: RangeMap = RangeMap::new(); 123 | 124 | range_map.insert(0..10, true); // case (G) 125 | range_map.insert(20..30, true); // case (G) 126 | range_map.insert(15..25, false); // case (C, F) 127 | 128 | assert_eq!(range_map.range_count(), 3); 129 | assert_eq!(range_map.get(0), Some(&true)); 130 | assert_eq!(range_map.get(9), Some(&true)); 131 | assert_eq!(range_map.get(10), None); 132 | assert_eq!(range_map.get(15), Some(&false)); 133 | assert_eq!(range_map.get(24), Some(&false)); 134 | assert_eq!(range_map.get(25), Some(&true)); 135 | assert_eq!(range_map.get(29), Some(&true)); 136 | assert_eq!(range_map.get(30), None); 137 | } 138 | 139 | #[test] 140 | fn insert_merge_ranges() { 141 | let mut range_map: RangeMap = RangeMap::new(); 142 | 143 | range_map.insert(00..10, true); 144 | range_map.insert(10..20, true); 145 | 146 | assert_eq!(range_map.range_count(), 1); 147 | assert_eq!(range_map.get(0), Some(&true)); 148 | assert_eq!(range_map.get(19), Some(&true)); 149 | assert_eq!(range_map.get(20), None); 150 | } 151 | 152 | #[test] 153 | fn insert_merge_ranges2() { 154 | let mut range_map: RangeMap = RangeMap::new(); 155 | 156 | range_map.insert(00..10, true); 157 | range_map.insert(10..20, false); 158 | range_map.insert(10..15, true); 159 | 160 | assert_eq!(range_map.range_count(), 2); 161 | assert_eq!(range_map.get(0), Some(&true)); 162 | assert_eq!(range_map.get(9), Some(&true)); 163 | assert_eq!(range_map.get(10), Some(&true)); 164 | assert_eq!(range_map.get(14), Some(&true)); 165 | assert_eq!(range_map.get(15), Some(&false)); 166 | assert_eq!(range_map.get(19), Some(&false)); 167 | assert_eq!(range_map.get(20), None); 168 | } 169 | 170 | #[test] 171 | fn update_merge_ranges() { 172 | let mut range_map: RangeMap = RangeMap::new(); 173 | 174 | range_map.insert(00..10, true); 175 | range_map.update(10..20, |_| Some(true)); 176 | 177 | assert_eq!(range_map.range_count(), 1); 178 | assert_eq!(range_map.get(0), Some(&true)); 179 | assert_eq!(range_map.get(19), Some(&true)); 180 | assert_eq!(range_map.get(20), None); 181 | } 182 | 183 | #[test] 184 | fn update_merge_ranges2() { 185 | let mut range_map: RangeMap = RangeMap::new(); 186 | 187 | range_map.insert(0..10, true); 188 | range_map.insert(10..20, false); 189 | range_map.update(10..15, |_| Some(true)); 190 | 191 | assert_eq!(range_map.range_count(), 2); 192 | assert_eq!(range_map.get(0), Some(&true)); 193 | assert_eq!(range_map.get(9), Some(&true)); 194 | assert_eq!(range_map.get(10), Some(&true)); 195 | assert_eq!(range_map.get(14), Some(&true)); 196 | assert_eq!(range_map.get(15), Some(&false)); 197 | assert_eq!(range_map.get(19), Some(&false)); 198 | assert_eq!(range_map.get(20), None); 199 | } 200 | 201 | #[test] 202 | fn insert_merge_ranges_rev() { 203 | let mut range_map: RangeMap = RangeMap::new(); 204 | 205 | range_map.insert(10..20, true); 206 | range_map.insert(00..10, true); 207 | 208 | assert_eq!(range_map.range_count(), 1); 209 | assert_eq!(range_map.get(0), Some(&true)); 210 | assert_eq!(range_map.get(19), Some(&true)); 211 | assert_eq!(range_map.get(20), None); 212 | } 213 | 214 | #[test] 215 | fn insert_merge_ranges_rev2() { 216 | let mut range_map: RangeMap = RangeMap::new(); 217 | 218 | range_map.insert(0..10, true); 219 | range_map.insert(10..20, false); 220 | range_map.insert(5..10, false); 221 | 222 | assert_eq!(range_map.range_count(), 2); 223 | assert_eq!(range_map.get(0), Some(&true)); 224 | assert_eq!(range_map.get(4), Some(&true)); 225 | assert_eq!(range_map.get(5), Some(&false)); 226 | assert_eq!(range_map.get(9), Some(&false)); 227 | assert_eq!(range_map.get(10), Some(&false)); 228 | assert_eq!(range_map.get(19), Some(&false)); 229 | assert_eq!(range_map.get(20), None); 230 | } 231 | 232 | #[test] 233 | fn update_merge_ranges_rev() { 234 | let mut range_map: RangeMap = RangeMap::new(); 235 | 236 | range_map.insert(10..20, true); 237 | range_map.update(0..10, |_| Some(true)); 238 | 239 | assert_eq!(range_map.range_count(), 1); 240 | assert_eq!(range_map.get(0), Some(&true)); 241 | assert_eq!(range_map.get(19), Some(&true)); 242 | assert_eq!(range_map.get(20), None); 243 | } 244 | 245 | #[test] 246 | fn update_merge_ranges_rev2() { 247 | let mut range_map: RangeMap = RangeMap::new(); 248 | 249 | range_map.insert(0..10, true); 250 | range_map.insert(10..20, false); 251 | range_map.update(5..10, |_| Some(false)); 252 | 253 | assert_eq!(range_map.range_count(), 2); 254 | assert_eq!(range_map.get(0), Some(&true)); 255 | assert_eq!(range_map.get(4), Some(&true)); 256 | assert_eq!(range_map.get(5), Some(&false)); 257 | assert_eq!(range_map.get(9), Some(&false)); 258 | assert_eq!(range_map.get(10), Some(&false)); 259 | assert_eq!(range_map.get(19), Some(&false)); 260 | assert_eq!(range_map.get(20), None); 261 | } 262 | 263 | #[test] 264 | fn insert_chars() { 265 | let mut charset = RangeSet::new(); 266 | charset.insert('c'); 267 | charset.insert('a'); 268 | charset.insert('b'); 269 | assert_eq!(charset.range_count(), 1); 270 | assert_eq!(charset.len(), 3); 271 | } 272 | 273 | #[test] 274 | fn insert_chars2() { 275 | let mut charset = RangeSet::new(); 276 | charset.insert('%'); 277 | charset.insert('$'); 278 | assert_eq!(charset.range_count(), 1); 279 | assert_eq!(charset.len(), 2); 280 | assert!(charset.contains('%')); 281 | assert!(charset.contains('$')) 282 | } 283 | -------------------------------------------------------------------------------- /tests/remove.rs: -------------------------------------------------------------------------------- 1 | use btree_range_map::RangeMap; 2 | 3 | #[test] 4 | fn remove_range() { 5 | let mut range_map: RangeMap = RangeMap::new(); 6 | 7 | range_map.insert(00..10, true); 8 | range_map.remove(1..9); 9 | 10 | assert_eq!(range_map.range_count(), 2); 11 | assert_eq!(range_map.get(0), Some(&true)); 12 | assert_eq!(range_map.get(1), None); 13 | assert_eq!(range_map.get(8), None); 14 | assert_eq!(range_map.get(9), Some(&true)); 15 | assert_eq!(range_map.get(10), None); 16 | } 17 | --------------------------------------------------------------------------------