├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── bench_script.sh ├── gen-bench-data ├── Cargo.toml └── src │ └── main.rs ├── gen_graphs.sh ├── graph.plt ├── loop_qc.sh ├── misc ├── difference.png ├── intersection.png ├── symmetric_difference.png └── union.png └── src ├── collection.rs ├── duo ├── difference.rs ├── difference_by_key.rs ├── intersection.rs ├── mod.rs ├── symmetric_difference.rs └── union.rs ├── lib.rs ├── multi ├── difference.rs ├── difference_by_key.rs ├── intersection.rs ├── mod.rs ├── symmetric_difference.rs └── union.rs ├── set.rs └── two_minimums.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | /*.data 5 | /*.bench 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdset" 3 | description = """ 4 | Set operations for sorted and deduplicated slices. 5 | Much performances! Such Wow! 6 | """ 7 | version = "0.4.0" 8 | documentation = "https://docs.rs/sdset" 9 | repository = "https://github.com/Kerollmops/sdset" 10 | authors = ["Kerollmops "] 11 | license = "MIT" 12 | readme = "README.md" 13 | keywords = ["set", "operation", "slice", "sort", "dedup"] 14 | categories = ["algorithms"] 15 | edition = "2018" 16 | 17 | [dependencies] 18 | serde = { version = "1.0", features = ["derive"], optional = true } 19 | 20 | [dev-dependencies] 21 | quickcheck = "0.6" 22 | fnv = "1.0" 23 | 24 | [features] 25 | unstable = [] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Clément Renault 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SdSet 2 | 3 | [![SdSet crate](https://img.shields.io/crates/v/sdset.svg)](https://crates.io/crates/sdset) 4 | [![SdSet documentation](https://docs.rs/sdset/badge.svg)](https://docs.rs/sdset) 5 | 6 | Set theory applied on sorted and deduplicated slices. Much performance! Such Wow! 7 | 8 | [API Documentation can be found on docs.rs](https://docs.rs/sdset). 9 | 10 | `sdset` stands for `sorted-deduplicated-slices-set` which is a little bit too long. 11 | 12 | ## Performances 13 | 14 | Note about the tests, which are done on ranges of integer, if it ends with: 15 | - `two_slices_big`, the first slice contains `0..100` and the second has `1..101` 16 | - `two_slices_big2`, the first contains `0..100` and the second has `51..151` 17 | - `two_slices_big3`, the first contains `0..100` and the second has `100..200` 18 | - `three_slices_big`, the first contains `0..100`, the second has `1..101` and the third has `2..102` 19 | - `three_slices_big2`, the first contains `0..100`, the second has `34..134` and the third has `67..167` 20 | - `three_slices_big3`, the first contains `0..100`, the second has `100..200` and the third has `200..300` 21 | 22 | These slices of runs of integer are useful when they overlap, we can see how performances changes when different parts of the slices overlaps. 23 | 24 | For more informations on "Why is there no really big slices benchmarks ?", you can see [my response on /r/rust](https://www.reddit.com/r/rust/comments/98ahv5/sdset_set_theory_applied_on_sorted_and/e4ervlc/). 25 | 26 | To run the benchmarks you must enable the `unstable` feature. 27 | 28 | ```bash 29 | $ cargo bench --features unstable 30 | ``` 31 | 32 | Note that the `sdset` set operations does not need many allocations so it starts with a serious advantage. For more information you can see the benchmarks variance. 33 | 34 | `_btree` are benchmarks that uses *two* or *three* `BTreeSet`s which contains runs of integers (see above), the `BTreeSet`s creations are not taken into account. The set operations are done on these sets and the result is accumulated in a final `Vec`. 35 | 36 | `_fnv` are benchmarks that uses *two* or *three* `HashSet`s which contains runs of integers (see above), it uses [a custom `Hasher` named `fnv`](https://github.com/servo/rust-fnv) that is specialized for little values like integers, the `HashSet`s creations are not taken into account. The set operations are done on these sets and the result is accumulated in a final `Vec`. 37 | 38 | The `_vec` benchmarks are available for the union set operation only, it consist of a `Vec` which is populated with the elements of *two* or *three* slices (see above), sorted and deduplicated. 39 | 40 | The `duo` and `multi` measurements are the implementations that are part of this crate, the first one can only do set operations on **two** sets and the second one can be used for any given number of sets. 41 | 42 | ### Histograms 43 | 44 | Histograms can be generated using the benchmarks by executing the following command: 45 | 46 | ```bash 47 | $ export CARGO_BENCH_CMD='cargo bench --features unstable' 48 | $ ./gen_graphs.sh xxx.bench 49 | ``` 50 | 51 | This is much more easier to read statistics and to see how `sdset` is more performant on already sorted and deduplicated slices than any other kind of collection. 52 | 53 | ![difference benchmarks](misc/difference.png) 54 | 55 | ![intersection benchmarks](misc/intersection.png) 56 | 57 | ![union benchmarks](misc/union.png) 58 | 59 | ![symmetric difference benchmarks](misc/symmetric_difference.png) 60 | -------------------------------------------------------------------------------- /bench_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This env variable is here to permit 4 | # to use a custom `cargo bench` command if needed 5 | CARGO_BENCH_CMD=${CARGO_BENCH_CMD:-cargo bench --features unstable} 6 | 7 | if [ $# -eq 0 ]; then 8 | echo "comparing benchmarks of HEAD~1 and HEAD..." 9 | OLD=$(git rev-parse --short 'HEAD~1') 10 | NEW=$(git rev-parse --short 'HEAD') 11 | elif [ $# -eq 1 ]; then 12 | echo "comparing benchmarks of $1 and HEAD..." 13 | OLD=$(git rev-parse --short $1) 14 | NEW=$(git rev-parse --short 'HEAD') 15 | elif [ $# -eq 2 ]; then 16 | echo "comparing benchmarks of $1 and $2..." 17 | OLD=$(git rev-parse --short $1) 18 | NEW=$(git rev-parse --short $2) 19 | else 20 | echo 'Usage: bench_script.sh [$OLD] [$NEW]' 21 | exit 1 22 | fi 23 | 24 | exit_if_dirty() { 25 | if ! git diff-files --quiet; then 26 | echo 'Your repository must not be dirty' 27 | exit 1 28 | fi 29 | } 30 | 31 | if [ ! -f $NEW.bench ]; then 32 | exit_if_dirty 33 | git checkout $NEW 34 | $CARGO_BENCH_CMD > $NEW.bench 35 | git checkout - 36 | fi 37 | 38 | if [ ! -f $OLD.bench ]; then 39 | exit_if_dirty 40 | git checkout $OLD 41 | $CARGO_BENCH_CMD > $OLD.bench 42 | git checkout - 43 | fi 44 | 45 | cargo benchcmp --threshold 5 $OLD.bench $NEW.bench 46 | -------------------------------------------------------------------------------- /gen-bench-data/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gen-bench-data" 3 | version = "0.1.0" 4 | authors = ["Kerollmops "] 5 | 6 | [dependencies] 7 | lazy_static = "1.1" 8 | ndarray = "0.11" 9 | regex = "1.0" 10 | -------------------------------------------------------------------------------- /gen-bench-data/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(pattern)] 2 | 3 | #[macro_use] extern crate lazy_static; 4 | extern crate ndarray; 5 | extern crate regex; 6 | 7 | use std::{cmp, env, fs, mem}; 8 | use std::io::{self, BufRead, Write}; 9 | use std::str::FromStr; 10 | use std::collections::{BTreeSet, BTreeMap, HashMap}; 11 | use regex::Regex; 12 | 13 | /// All extractable data from a single micro-benchmark. 14 | #[derive(Clone, Debug)] 15 | pub struct Benchmark { 16 | pub name: String, 17 | pub ns: u64, 18 | pub variance: u64, 19 | pub throughput: Option, 20 | } 21 | 22 | impl Eq for Benchmark {} 23 | 24 | impl PartialEq for Benchmark { 25 | fn eq(&self, other: &Benchmark) -> bool { 26 | self.name == other.name 27 | } 28 | } 29 | 30 | impl Ord for Benchmark { 31 | fn cmp(&self, other: &Benchmark) -> cmp::Ordering { 32 | self.partial_cmp(other).unwrap() 33 | } 34 | } 35 | 36 | impl PartialOrd for Benchmark { 37 | fn partial_cmp(&self, other: &Benchmark) -> Option { 38 | self.name.partial_cmp(&other.name) 39 | } 40 | } 41 | 42 | lazy_static! { 43 | static ref BENCHMARK_REGEX: Regex = Regex::new(r##"(?x) 44 | test\s+(?P\S+) # test mod::test_name 45 | \s+...\sbench:\s+(?P[0-9,]+)\s+ns/iter # ... bench: 1234 ns/iter 46 | \s+\(\+/-\s+(?P[0-9,]+)\) # (+/- 4321) 47 | (?:\s+=\s+(?P[0-9,]+)\sMB/s)? # = 2314 MB/s 48 | "##).unwrap(); 49 | } 50 | 51 | impl FromStr for Benchmark { 52 | type Err = (); 53 | 54 | /// Parses a single benchmark line into a Benchmark. 55 | fn from_str(line: &str) -> Result { 56 | let caps = match BENCHMARK_REGEX.captures(line) { 57 | None => return Err(()), 58 | Some(caps) => caps, 59 | }; 60 | let ns = match parse_commas(&caps["ns"]) { 61 | None => return Err(()), 62 | Some(ns) => ns, 63 | }; 64 | let variance = match parse_commas(&caps["variance"]) { 65 | None => return Err(()), 66 | Some(variance) => variance, 67 | }; 68 | let throughput = caps.name("throughput").and_then(|m| parse_commas(m.as_str())); 69 | Ok(Benchmark { 70 | name: caps["name"].to_string(), 71 | ns: ns, 72 | variance: variance, 73 | throughput: throughput, 74 | }) 75 | } 76 | } 77 | 78 | fn main() { 79 | let filename = env::args().nth(1).expect("Missing benchmarks file"); 80 | let file = fs::File::open(filename).unwrap(); 81 | let file = io::BufReader::new(file); 82 | 83 | let mut tests = HashMap::new(); 84 | for line in file.lines() { 85 | let line = line.unwrap(); 86 | 87 | if let Ok(mut bench) = Benchmark::from_str(&line) { 88 | bench.name = bench.name.replace("bench::", ""); 89 | 90 | // extract: btree, vec, multi, duo... 91 | match extract_first_module(&mut bench.name) { 92 | Some(module) => { 93 | // extract: difference, intersection, union... 94 | match extract_first_module(&mut bench.name) { 95 | Some(test) => { 96 | let modules = tests.entry(test).or_insert(BTreeMap::new()); 97 | let map = modules.entry(module).or_insert(HashMap::new()); 98 | map.insert(bench.name.clone(), bench); 99 | }, 100 | None => eprintln!("No test found for bench {:?}", bench.name), 101 | } 102 | }, 103 | None => eprintln!("No module found for bench {:?}", bench.name), 104 | } 105 | } 106 | } 107 | 108 | // generate the arrays of the form 109 | // 110 | // difference.data 111 | // 112 | // Title btree multi duo 113 | // "two slices big" 799 821 498 114 | // "two slices big2" 1152 474 288 115 | // "two slices big3" 1223 108 75 116 | // "three slices big" 932 1210 NaN 117 | // "three slices big2" 2954 819 NaN 118 | // "three slices big3" 7191 111 NaN 119 | 120 | for (test, modules) in &tests { 121 | let filename = format!("{}.data", test); 122 | let mut file = fs::File::create(filename).unwrap(); 123 | 124 | // `+ 1` for titles and benchmark names 125 | let row = modules.iter().map(|(_, b)| b.len()).max().unwrap_or(0) + 1; 126 | let col = modules.len() + 1; 127 | let mut array = vec![vec![String::new(); col]; row]; 128 | 129 | // write titles 130 | array[0][0].push_str("Title"); 131 | for (x, (title, _)) in array[0].iter_mut().skip(1).zip(modules.iter()) { 132 | x.push_str(title); 133 | } 134 | 135 | let mut benchmarks = BTreeSet::new(); 136 | for (_, benches) in modules { 137 | for (_, bench) in benches { 138 | benchmarks.insert(bench.name.clone()); 139 | } 140 | } 141 | 142 | // write benchmarks names 143 | for (row, benchname) in array.iter_mut().skip(1).zip(benchmarks.iter()) { 144 | let name = format!("{:?}", benchname.replace("_", " ")); 145 | row[0].push_str(&name); 146 | for (tile, (_, benches)) in row.iter_mut().skip(1).zip(modules.iter()) { 147 | match benches.get(benchname) { 148 | Some(bench) => tile.push_str(&bench.ns.to_string()), 149 | None => tile.push_str("NaN"), 150 | } 151 | } 152 | } 153 | 154 | // write to file 155 | let mut aligns = vec![0; col]; 156 | for i in 0..col { 157 | if let Some(align) = array.iter().map(|v| v[i].len()).max() { 158 | aligns[i] = align; 159 | } 160 | } 161 | 162 | for row in array { 163 | for (i, tile) in row.iter().enumerate() { 164 | write!(&mut file, "{1:0$} ", aligns[i] + 3, tile).unwrap(); 165 | } 166 | writeln!(&mut file).unwrap(); 167 | } 168 | } 169 | } 170 | 171 | fn extract_first_module(s: &mut String) -> Option { 172 | match s.find("::") { 173 | Some(i) => { 174 | let mut name = s.split_off(i + 2); 175 | mem::swap(s, &mut name); 176 | 177 | let new_len = name.len() - 2; 178 | name.truncate(new_len); 179 | Some(name) 180 | }, 181 | None => None, 182 | } 183 | } 184 | 185 | /// Drops all commas in a string and parses it as a unsigned integer 186 | fn parse_commas(s: &str) -> Option { 187 | drop_commas(s).parse().ok() 188 | } 189 | 190 | /// Drops all commas in a string 191 | fn drop_commas(s: &str) -> String { 192 | s.chars().filter(|&b| b != ',').collect() 193 | } 194 | 195 | #[cfg(test)] 196 | mod tests { 197 | use super::*; 198 | 199 | #[test] 200 | fn extract_first_module_easy() { 201 | let mut name = "vec::kiki::koko".to_string(); 202 | let module = extract_first_module(&mut name); 203 | assert_eq!(Some("vec".into()), module); 204 | assert_eq!("kiki::koko".to_string(), name); 205 | } 206 | 207 | #[test] 208 | fn extract_first_module_no_module() { 209 | let mut name = "koko".to_string(); 210 | let module = extract_first_module(&mut name); 211 | assert_eq!(None, module); 212 | assert_eq!("koko".to_string(), name); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /gen_graphs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | 5 | # This env variable is here to permit 6 | # to use a custom `cargo bench` command if needed 7 | CARGO_BENCH_CMD=${CARGO_BENCH_CMD:-cargo bench} 8 | 9 | if [ $# -eq 1 ]; then 10 | $CARGO_BENCH_CMD > $1.bench 11 | else 12 | echo 'Usage: gen_graphs.sh $BENCH_FILE' 13 | exit 1 14 | fi 15 | 16 | cargo run --release --manifest-path gen-bench-data/Cargo.toml -- $1.bench 17 | 18 | gnuplot -e "benchname='difference'" graph.plt > misc/difference.png 19 | gnuplot -e "benchname='intersection'" graph.plt > misc/intersection.png 20 | gnuplot -e "benchname='union'" graph.plt > misc/union.png 21 | gnuplot -e "benchname='symmetric_difference'" graph.plt > misc/symmetric_difference.png 22 | 23 | echo "Graphs successfully generated!" 24 | -------------------------------------------------------------------------------- /graph.plt: -------------------------------------------------------------------------------- 1 | # run this script: `-e "benchname='intersection'"` 2 | 3 | textcolor = "#1a1a1a" 4 | 5 | set title benchname tc rgb textcolor 6 | 7 | # stdout a png image 8 | set terminal png size 720,480 noenhanced 9 | 10 | set auto x 11 | set auto y 12 | 13 | set ylabel "ns/iter" tc rgb textcolor 14 | 15 | set key tc rgb textcolor 16 | 17 | set style data histogram 18 | set style histogram cluster gap 4 19 | set style fill transparent solid 0.5 20 | 21 | set boxwidth 3.5 22 | 23 | set xtic scale 0 24 | set xtics rotate by -45 offset 0,-0.5 25 | set tics textcolor rgb textcolor 26 | 27 | file = benchname.".data" 28 | 29 | NC = system("awk 'NR==1{print NF}' ".file) 30 | 31 | plot for [col=2:NC] file using col:xtic(1) ti col 32 | -------------------------------------------------------------------------------- /loop_qc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | while true 4 | do 5 | cargo test qc_ 6 | if [[ x$? != x0 ]] ; then 7 | exit $? 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /misc/difference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kerollmops/sdset/e86d44b195061834acf5d40b0d947262237b9edc/misc/difference.png -------------------------------------------------------------------------------- /misc/intersection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kerollmops/sdset/e86d44b195061834acf5d40b0d947262237b9edc/misc/intersection.png -------------------------------------------------------------------------------- /misc/symmetric_difference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kerollmops/sdset/e86d44b195061834acf5d40b0d947262237b9edc/misc/symmetric_difference.png -------------------------------------------------------------------------------- /misc/union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kerollmops/sdset/e86d44b195061834acf5d40b0d947262237b9edc/misc/union.png -------------------------------------------------------------------------------- /src/collection.rs: -------------------------------------------------------------------------------- 1 | use std::hash::Hash; 2 | use std::collections::{HashSet, BTreeSet}; 3 | use std::marker; 4 | use std::convert::Infallible; 5 | 6 | /// This trait is meant to abstract any kind of collection 7 | /// (i.e. [`Vec`], [`HashSet`]). 8 | /// 9 | /// This is particularly helpful when you want particular behavior 10 | /// when inserting elements, the [`Counter`] struct is a good example 11 | /// of a custom implementation of the [`Collection`] trait, it is used to only 12 | /// count the number of elements of a set operation. 13 | pub trait Collection { 14 | 15 | /// Error type associated with the [`Collection`]. 16 | type Error; 17 | 18 | /// Insert one element into the collection. 19 | fn push(&mut self, elem: T) -> Result<(), Self::Error>; 20 | 21 | /// Extend the collection by cloning the elements. 22 | fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), Self::Error> 23 | where T: Clone; 24 | 25 | /// Extend the collection by inserting the elements from the given [`Iterator`]. 26 | fn extend(&mut self, elems: I) -> Result<(), Self::Error> 27 | where I: IntoIterator; 28 | 29 | /// Reserve enough space in the collection for `size` elements. 30 | fn reserve(&mut self, _size: usize) -> Result<(), Self::Error> { 31 | Ok(()) 32 | } 33 | } 34 | 35 | impl Collection for Vec { 36 | 37 | type Error = Infallible; 38 | 39 | fn push(&mut self, elem: T) -> Result<(), Self::Error> { 40 | Vec::push(self, elem); 41 | Ok(()) 42 | } 43 | 44 | fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), Self::Error> 45 | where T: Clone 46 | { 47 | Vec::extend_from_slice(self, elems); 48 | Ok(()) 49 | } 50 | 51 | fn extend(&mut self, elems: I) -> Result<(), Self::Error> 52 | where I: IntoIterator 53 | { 54 | Extend::extend(self, elems); 55 | Ok(()) 56 | } 57 | 58 | fn reserve(&mut self, size: usize) -> Result<(), Self::Error> { 59 | Vec::reserve(self, size); 60 | Ok(()) 61 | } 62 | } 63 | 64 | impl Collection for HashSet { 65 | 66 | type Error = Infallible; 67 | 68 | fn push(&mut self, elem: T) -> Result<(), Self::Error> { 69 | HashSet::insert(self, elem); 70 | Ok(()) 71 | } 72 | 73 | fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), Self::Error> 74 | where T: Clone 75 | { 76 | Collection::extend(self, elems.iter().cloned()) 77 | } 78 | 79 | fn extend(&mut self, elems: I) -> Result<(), Self::Error> 80 | where I: IntoIterator 81 | { 82 | Extend::extend(self, elems); 83 | Ok(()) 84 | } 85 | 86 | fn reserve(&mut self, size: usize) -> Result<(), Self::Error> { 87 | HashSet::reserve(self, size); 88 | Ok(()) 89 | } 90 | } 91 | 92 | impl Collection for BTreeSet { 93 | 94 | type Error = Infallible; 95 | 96 | fn push(&mut self, elem: T) -> Result<(), Self::Error> { 97 | BTreeSet::insert(self, elem); 98 | Ok(()) 99 | } 100 | 101 | fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), Self::Error> 102 | where T: Clone 103 | { 104 | Collection::extend(self, elems.iter().cloned()) 105 | } 106 | 107 | fn extend(&mut self, elems: I) -> Result<(), Self::Error> 108 | where I: IntoIterator 109 | { 110 | Extend::extend(self, elems); 111 | Ok(()) 112 | } 113 | } 114 | 115 | /// A [`Collection`] that only counts the final size of a set operation. 116 | /// 117 | /// It is meant to be used to avoid unecessary allocations. 118 | /// 119 | /// ``` 120 | /// # use sdset::Error; 121 | /// # fn try_main() -> Result<(), Error> { 122 | /// use sdset::duo::OpBuilder; 123 | /// use sdset::{SetOperation, Set, SetBuf, Counter}; 124 | /// 125 | /// let a = Set::new(&[1, 2, 4, 6, 7])?; 126 | /// let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 127 | /// 128 | /// let op = OpBuilder::new(a, b).union(); 129 | /// 130 | /// let mut counter = Counter::::default(); 131 | /// op.extend_collection(&mut counter); 132 | /// 133 | /// assert_eq!(counter.get(), 7); 134 | /// # Ok(()) } 135 | /// # try_main().unwrap(); 136 | /// ``` 137 | 138 | pub struct Counter { 139 | count: usize, 140 | _phantom: marker::PhantomData, 141 | } 142 | 143 | impl Default for Counter { 144 | fn default() -> Counter { 145 | Counter { 146 | count: 0, 147 | _phantom: marker::PhantomData, 148 | } 149 | } 150 | } 151 | 152 | impl Counter { 153 | /// Create a new [`Counter`] initialized with 0. 154 | pub fn new() -> Self { 155 | Self::default() 156 | } 157 | 158 | /// Returns the count for the [`Operation`]. 159 | pub fn get(&self) -> usize { 160 | self.count 161 | } 162 | } 163 | 164 | impl Collection for Counter { 165 | 166 | type Error = Infallible; 167 | 168 | fn push(&mut self, _elem: T) -> Result<(), Self::Error> { 169 | self.count = self.count.saturating_add(1); 170 | Ok(()) 171 | } 172 | 173 | fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), Self::Error> 174 | where T: Clone 175 | { 176 | self.count = self.count.saturating_add(elems.len()); 177 | Ok(()) 178 | } 179 | 180 | fn extend(&mut self, elems: I) -> Result<(), Self::Error> 181 | where I: IntoIterator 182 | { 183 | self.count = self.count.saturating_add(elems.into_iter().count()); 184 | Ok(()) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/duo/difference.rs: -------------------------------------------------------------------------------- 1 | use crate::set::Set; 2 | use crate::{exponential_offset_ge, SetOperation, Collection}; 3 | 4 | /// Represent the _difference_ set operation that will be applied to two slices. 5 | /// 6 | /// # Examples 7 | /// ``` 8 | /// # use sdset::Error; 9 | /// # fn try_main() -> Result<(), Error> { 10 | /// use sdset::duo::OpBuilder; 11 | /// use sdset::{SetOperation, Set, SetBuf}; 12 | /// 13 | /// let a = Set::new(&[1, 2, 4, 6, 7])?; 14 | /// let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 15 | /// 16 | /// let op = OpBuilder::new(a, b).difference(); 17 | /// 18 | /// let res: SetBuf = op.into_set_buf(); 19 | /// assert_eq!(&res[..], &[1]); 20 | /// # Ok(()) } 21 | /// # try_main().unwrap(); 22 | /// ``` 23 | #[derive(Copy, Clone)] 24 | pub struct Difference<'a, T: 'a> { 25 | a: &'a [T], 26 | b: &'a [T], 27 | } 28 | 29 | impl<'a, T> Difference<'a, T> { 30 | /// Construct one with slices checked to be sorted and deduplicated. 31 | pub fn new(a: &'a Set, b: &'a Set) -> Self { 32 | Self { 33 | a: a.as_slice(), 34 | b: b.as_slice(), 35 | } 36 | } 37 | } 38 | 39 | impl<'a, T: Ord> Difference<'a, T> { 40 | #[inline] 41 | fn extend_collection(mut self, output: &mut C, extend: F) -> Result<(), C::Error> 42 | where C: Collection, 43 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 44 | { 45 | while let Some(first) = self.a.first() { 46 | self.b = exponential_offset_ge(self.b, first); 47 | let minimum = self.b.first(); 48 | 49 | match minimum { 50 | Some(min) if min == first => { 51 | self.a = &self.a[1..]; 52 | self.b = &self.b[1..]; 53 | }, 54 | Some(min) => { 55 | let off = self.a.iter().take_while(|&x| x < min).count(); 56 | extend(output, &self.a[..off])?; 57 | 58 | self.a = &self.a[off..]; 59 | }, 60 | None => { 61 | extend(output, self.a)?; 62 | break; 63 | }, 64 | } 65 | } 66 | Ok(()) 67 | } 68 | 69 | fn iter(&self) -> DifferenceIter<'a, T> 70 | { 71 | DifferenceIter { 72 | a: self.a, 73 | b: self.b 74 | } 75 | } 76 | } 77 | 78 | impl<'a, T: Ord + Clone> SetOperation for Difference<'a, T> { 79 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 80 | where C: Collection 81 | { 82 | self.extend_collection(output, Collection::extend_from_slice) 83 | } 84 | } 85 | 86 | impl<'a, T: Ord> SetOperation<&'a T> for Difference<'a, T> { 87 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 88 | where C: Collection<&'a T> 89 | { 90 | self.extend_collection(output, Collection::extend) 91 | } 92 | } 93 | 94 | impl<'a, T: Ord> IntoIterator for Difference<'a, T> { 95 | type Item = &'a T; 96 | type IntoIter = DifferenceIter<'a, T>; 97 | fn into_iter(self) -> Self::IntoIter { 98 | self.iter() 99 | } 100 | } 101 | 102 | impl<'a, T: Ord> IntoIterator for &'a Difference<'a, T> { 103 | type Item = &'a T; 104 | type IntoIter = DifferenceIter<'a, T>; 105 | fn into_iter(self) -> Self::IntoIter { 106 | self.iter() 107 | } 108 | } 109 | 110 | pub struct DifferenceIter<'a, T> { 111 | a: &'a [T], 112 | b: &'a [T], 113 | } 114 | 115 | impl<'a, T: Ord> Iterator for DifferenceIter<'a, T> { 116 | type Item = &'a T; 117 | 118 | fn next(&mut self) -> Option { 119 | loop { 120 | if self.a.is_empty() { 121 | return None; 122 | } 123 | let first_a = &self.a[0]; 124 | self.b = exponential_offset_ge(self.b, first_a); 125 | if self.b.is_empty() { 126 | self.a = &self.a[1..]; 127 | return Some(first_a); 128 | } 129 | if first_a == &self.b[0] { 130 | self.a = &self.a[1..]; 131 | self.b = &self.b[1..]; 132 | continue; 133 | } else { // b > a 134 | self.a = &self.a[1..]; 135 | return Some(first_a); 136 | } 137 | } 138 | } 139 | } 140 | 141 | #[cfg(test)] 142 | mod tests { 143 | mod set_to_set { 144 | use super::super::*; 145 | use crate::set::{sort_dedup_vec, SetBuf}; 146 | #[test] 147 | fn two_slices() { 148 | let a = &[1, 2, 3]; 149 | let b = &[2, 4]; 150 | 151 | let diff: SetBuf = Difference { a: a, b: b }.into_set_buf(); 152 | assert_eq!(&diff[..], &[1, 3]); 153 | } 154 | 155 | #[test] 156 | fn two_slices_special_case() { 157 | let a = &[1, 2, 3]; 158 | let b = &[3]; 159 | 160 | let diff: SetBuf = Difference { a: a, b: b }.into_set_buf(); 161 | assert_eq!(&diff[..], &[1, 2]); 162 | } 163 | 164 | quickcheck! { 165 | fn qc_difference(a: Vec, b: Vec) -> bool { 166 | use std::collections::BTreeSet; 167 | use std::iter::FromIterator; 168 | 169 | let mut a = a; 170 | let mut b = b; 171 | 172 | sort_dedup_vec(&mut a); 173 | sort_dedup_vec(&mut b); 174 | 175 | let x: SetBuf = Difference { a: &a, b: &b }.into_set_buf(); 176 | 177 | let a = BTreeSet::from_iter(a); 178 | let b = BTreeSet::from_iter(b); 179 | let y = a.difference(&b); 180 | let y: Vec<_> = y.cloned().collect(); 181 | 182 | x.as_slice() == y.as_slice() 183 | } 184 | } 185 | } 186 | 187 | mod set_to_iter { 188 | use super::super::*; 189 | use crate::set::sort_dedup_vec; 190 | #[test] 191 | fn two_slices() { 192 | let a = &[1, 2, 3]; 193 | let b = &[2, 4]; 194 | 195 | let diff: Vec = Difference { a: a, b: b }.into_iter().cloned().collect(); 196 | assert_eq!(&diff[..], &[1, 3]); 197 | } 198 | 199 | #[test] 200 | fn two_slices_special_case() { 201 | let a = &[1, 2, 3]; 202 | let b = &[3]; 203 | 204 | let diff: Vec = Difference { a: a, b: b }.into_iter().cloned().collect(); 205 | assert_eq!(&diff[..], &[1, 2]); 206 | } 207 | 208 | quickcheck! { 209 | fn qc_difference(a: Vec, b: Vec) -> bool { 210 | use std::collections::BTreeSet; 211 | use std::iter::FromIterator; 212 | 213 | let mut a = a; 214 | let mut b = b; 215 | 216 | sort_dedup_vec(&mut a); 217 | sort_dedup_vec(&mut b); 218 | 219 | let x: Vec = Difference { a: &a, b: &b }.into_iter().cloned().collect(); 220 | 221 | let a = BTreeSet::from_iter(a); 222 | let b = BTreeSet::from_iter(b); 223 | let y = a.difference(&b); 224 | let y: Vec<_> = y.cloned().collect(); 225 | 226 | x.as_slice() == y.as_slice() 227 | } 228 | } 229 | } 230 | } 231 | 232 | #[cfg(all(feature = "unstable", test))] 233 | mod bench { 234 | extern crate test; 235 | use super::*; 236 | use self::test::Bencher; 237 | use crate::set::SetBuf; 238 | 239 | #[bench] 240 | fn two_slices_big(bench: &mut Bencher) { 241 | let a: Vec<_> = (0..100).collect(); 242 | let b: Vec<_> = (1..101).collect(); 243 | 244 | bench.iter(|| { 245 | let difference_: SetBuf = Difference { a: &a, b: &b }.into_set_buf(); 246 | test::black_box(|| difference_); 247 | }); 248 | } 249 | 250 | #[bench] 251 | fn two_slices_big2(bench: &mut Bencher) { 252 | let a: Vec<_> = (0..100).collect(); 253 | let b: Vec<_> = (51..151).collect(); 254 | 255 | bench.iter(|| { 256 | let difference_: SetBuf = Difference { a: &a, b: &b }.into_set_buf(); 257 | test::black_box(|| difference_); 258 | }); 259 | } 260 | 261 | #[bench] 262 | fn two_slices_big3(bench: &mut Bencher) { 263 | let a: Vec<_> = (0..100).collect(); 264 | let b: Vec<_> = (100..200).collect(); 265 | 266 | bench.iter(|| { 267 | let difference_: SetBuf = Difference { a: &a, b: &b }.into_set_buf(); 268 | test::black_box(|| difference_); 269 | }); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/duo/difference_by_key.rs: -------------------------------------------------------------------------------- 1 | use crate::set::Set; 2 | use crate::{exponential_offset_ge_by_key, SetOperation, Collection}; 3 | 4 | /// Represent the _difference_ set operation that will be applied to two slices of different types. 5 | /// 6 | /// # Examples 7 | /// ``` 8 | /// # use sdset::Error; 9 | /// # fn try_main() -> Result<(), Error> { 10 | /// use sdset::duo::OpBuilderByKey; 11 | /// use sdset::{SetOperation, Set, SetBuf}; 12 | /// 13 | /// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 14 | /// struct Foo { a: i32, b: u8 } 15 | /// 16 | /// let a = Set::new(&[ 17 | /// Foo{ a: 1, b: 6 }, 18 | /// Foo{ a: 1, b: 7 }, 19 | /// Foo{ a: 1, b: 8 }, 20 | /// Foo{ a: 2, b: 9 }, 21 | /// Foo{ a: 2, b: 10 }, 22 | /// Foo{ a: 3, b: 10 }, 23 | /// ])?; 24 | /// let b = Set::new(&[1, 3, 4, 5]).unwrap(); 25 | /// 26 | /// // Return the field of Foo that will be used for comparison 27 | /// let f = |x: &Foo| x.a; 28 | /// 29 | /// // directly use the i32 for comparison 30 | /// let g = |x: &i32| *x; 31 | /// 32 | /// let op = OpBuilderByKey::new(a, b, f, g).difference(); 33 | /// let res: SetBuf = op.into_set_buf(); 34 | /// 35 | /// assert_eq!(res.as_slice(), &[Foo{ a: 2, b: 9 }, Foo{ a: 2, b: 10 }][..]); 36 | /// # Ok(()) } 37 | /// # try_main().unwrap(); 38 | /// ``` 39 | #[derive(Copy, Clone)] 40 | pub struct DifferenceByKey<'a, T, U, F, G, K> 41 | where 42 | T: 'a, 43 | U: 'a, 44 | F: Fn(&T) -> K, 45 | G: Fn(&U) -> K, 46 | K: Ord, 47 | { 48 | a: &'a [T], 49 | b: &'a [U], 50 | f: F, 51 | g: G, 52 | } 53 | 54 | impl<'a, T, U, F, G, K> DifferenceByKey<'a, T, U, F, G, K> 55 | where 56 | T: 'a, 57 | U: 'a, 58 | F: Fn(&T) -> K, 59 | G: Fn(&U) -> K, 60 | K: Ord, 61 | { 62 | /// Construct one with slices checked to be sorted and deduplicated. 63 | pub fn new(a: &'a Set, b: &'a Set, f: F, g: G) -> Self { 64 | Self { 65 | a: a.as_slice(), 66 | b: b.as_slice(), 67 | f: f, 68 | g: g, 69 | } 70 | } 71 | } 72 | 73 | impl<'a, T, U, F, G, K> DifferenceByKey<'a, T, U, F, G, K> 74 | where F: Fn(&T) -> K, 75 | G: Fn(&U) -> K, 76 | K: Ord, 77 | { 78 | fn extend_collection(mut self, output: &mut C, extend: E) -> Result<(), C::Error> 79 | where C: Collection, 80 | E: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 81 | { 82 | while let Some(first_a) = self.a.first().map(|x| (self.f)(x)) { 83 | self.b = exponential_offset_ge_by_key(self.b, &first_a, &self.g); 84 | 85 | match self.b.first().map(|x| (self.g)(x)) { 86 | Some(min) => { 87 | if min == first_a { 88 | self.a = &self.a[1..]; 89 | // cannot advance b since we support duplicate relations 90 | } else { 91 | let off = self.a.iter().take_while(|&x| (self.f)(x) < min).count(); 92 | extend(output, &self.a[..off])?; 93 | 94 | self.a = &self.a[off..] 95 | } 96 | }, 97 | None => { 98 | extend(output, self.a)?; 99 | break; 100 | }, 101 | } 102 | } 103 | Ok(()) 104 | } 105 | 106 | fn iter(&'a self) -> DifferenceByKeyIter<'a, T, U, F, G, K> 107 | { 108 | DifferenceByKeyIter { 109 | a: self.a, 110 | b: self.b, 111 | f: &self.f, 112 | g: &self.g 113 | } 114 | } 115 | } 116 | 117 | impl<'a, T, U, F, G, K> SetOperation for DifferenceByKey<'a, T, U, F, G, K> 118 | where T: Clone, 119 | F: Fn(&T) -> K, 120 | G: Fn(&U) -> K, 121 | K: Ord, 122 | { 123 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 124 | where C: Collection, 125 | { 126 | self.extend_collection(output, Collection::extend_from_slice) 127 | } 128 | } 129 | 130 | impl<'a, T, U, F, G, K> SetOperation<&'a T> for DifferenceByKey<'a, T, U, F, G, K> 131 | where F: Fn(&T) -> K, 132 | G: Fn(&U) -> K, 133 | K: Ord, 134 | { 135 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 136 | where C: Collection<&'a T>, 137 | { 138 | self.extend_collection(output, Collection::extend) 139 | } 140 | } 141 | 142 | // This version of IntoIterator takes references to the functions (f/g). 143 | // The separate structs are required to not break the public API which takes the functions 144 | // by value instead of by reference, and doesn't require them to implement Copy/Clone. 145 | impl<'a, T, U, F, G, K> IntoIterator for &'a DifferenceByKey<'a, T, U, F, G, K> 146 | where F: Fn(&T) -> K, 147 | G: Fn(&U) -> K, 148 | K: Ord, 149 | { 150 | type Item = &'a T; 151 | type IntoIter = DifferenceByKeyIter<'a, T, U, F, G, K>; 152 | fn into_iter(self) -> Self::IntoIter { 153 | self.iter() 154 | } 155 | } 156 | 157 | pub struct DifferenceByKeyIter<'a, T, U, F, G, K> 158 | where 159 | T: 'a, 160 | U: 'a, 161 | F: Fn(&T) -> K, 162 | G: Fn(&U) -> K, 163 | K: Ord, 164 | { 165 | a: &'a [T], 166 | b: &'a [U], 167 | f: &'a F, 168 | g: &'a G, 169 | } 170 | 171 | impl<'a, T, U, F, G, K> Iterator for DifferenceByKeyIter<'a, T, U, F, G, K> 172 | where 173 | T: 'a, 174 | U: 'a, 175 | F: Fn(&T) -> K, 176 | G: Fn(&U) -> K, 177 | K: Ord, 178 | { 179 | type Item = &'a T; 180 | 181 | fn next(&mut self) -> Option { 182 | loop { 183 | if self.a.is_empty() { 184 | return None; 185 | } 186 | let first_a = (self.f)(&self.a[0]); 187 | self.b = exponential_offset_ge_by_key(self.b, &first_a, &self.g); 188 | if self.b.is_empty() { 189 | let result = &self.a[0]; 190 | self.a = &self.a[1..]; 191 | return Some(result); 192 | } 193 | if first_a == (self.g)(&self.b[0]) { 194 | self.a = &self.a[1..]; 195 | // cannot advance b since we support duplicate relations 196 | continue; 197 | } else { // b > a 198 | let result = &self.a[0]; 199 | self.a = &self.a[1..]; 200 | return Some(result); 201 | } 202 | } 203 | } 204 | } 205 | 206 | // This version of IntoIterator moves the contents of self into the iterator. 207 | // Therefore the iterator owns the functions (f/g). 208 | // The separate structs are required to not break the public API which takes the functions 209 | // by value instead of by reference, and doesn't require them to implement Copy/Clone. 210 | impl<'a, T, U, F, G, K> IntoIterator for DifferenceByKey<'a, T, U, F, G, K> 211 | where F: Fn(&T) -> K + 'a, 212 | G: Fn(&U) -> K + 'a, 213 | K: Ord + 'a, 214 | { 215 | type Item = &'a T; 216 | type IntoIter = DifferenceByKeyIterOwning<'a, T, U, F, G, K>; 217 | fn into_iter(self) -> Self::IntoIter { 218 | Self::IntoIter { 219 | a: self.a, 220 | b: self.b, 221 | f: self.f, 222 | g: self.g 223 | } 224 | } 225 | } 226 | 227 | pub struct DifferenceByKeyIterOwning<'a, T, U, F, G, K> 228 | where 229 | T: 'a, 230 | U: 'a, 231 | F: Fn(&T) -> K, 232 | G: Fn(&U) -> K, 233 | K: Ord, 234 | { 235 | a: &'a [T], 236 | b: &'a [U], 237 | f: F, 238 | g: G, 239 | } 240 | 241 | impl<'a, T, U, F, G, K> Iterator for DifferenceByKeyIterOwning<'a, T, U, F, G, K> 242 | where 243 | T: 'a, 244 | U: 'a, 245 | F: Fn(&T) -> K, 246 | G: Fn(&U) -> K, 247 | K: Ord, 248 | { 249 | type Item = &'a T; 250 | 251 | fn next(&mut self) -> Option { 252 | loop { 253 | if self.a.is_empty() { 254 | return None; 255 | } 256 | let first_a = (self.f)(&self.a[0]); 257 | self.b = exponential_offset_ge_by_key(self.b, &first_a, &self.g); 258 | if self.b.is_empty() { 259 | let result = &self.a[0]; 260 | self.a = &self.a[1..]; 261 | return Some(result); 262 | } 263 | if first_a == (self.g)(&self.b[0]) { 264 | self.a = &self.a[1..]; 265 | // cannot advance b since we support duplicate relations 266 | continue; 267 | } else { // b > a 268 | let result = &self.a[0]; 269 | self.a = &self.a[1..]; 270 | return Some(result); 271 | } 272 | } 273 | } 274 | } 275 | 276 | #[cfg(test)] 277 | mod tests { 278 | mod set_to_set { 279 | use super::super::*; 280 | use crate::set::{sort_dedup_vec, SetBuf}; 281 | 282 | #[derive(Debug, Clone, PartialEq, Eq)] 283 | struct Foo { 284 | a: i32, 285 | b: i8, 286 | } 287 | 288 | #[test] 289 | fn difference_empty_no_duplicates() { 290 | let a = Set::new_unchecked(&[ 291 | Foo{ a: 1, b: 8 }, 292 | Foo{ a: 2, b: 9 }, 293 | Foo{ a: 3, b: 10 }, 294 | Foo{ a: 4, b: 11 }, 295 | Foo{ a: 5, b: 12 }, 296 | ]); 297 | let b = Set::new(&[1, 2, 3, 4, 5]).unwrap(); 298 | 299 | let difference: SetBuf = DifferenceByKey::new(a, b, |x| x.a, |&x| x).into_set_buf(); 300 | 301 | assert!(difference.is_empty()); 302 | } 303 | 304 | #[test] 305 | fn difference_empty_duplicate_relations() { 306 | let a = Set::new_unchecked(&[ 307 | Foo{ a: 1, b: 6 }, 308 | Foo{ a: 1, b: 7 }, 309 | Foo{ a: 1, b: 8 }, 310 | Foo{ a: 2, b: 9 }, 311 | Foo{ a: 2, b: 10 }, 312 | ]); 313 | let b = Set::new(&[1, 2, 3, 4, 5]).unwrap(); 314 | 315 | let difference: SetBuf = DifferenceByKey::new(a, b, |x| x.a, |&x| x).into_set_buf(); 316 | 317 | assert!(difference.is_empty()); 318 | } 319 | 320 | #[test] 321 | fn difference_non_empty_duplicate_relations() { 322 | let a = Set::new_unchecked(&[ 323 | Foo{ a: 1, b: 6 }, 324 | Foo{ a: 1, b: 7 }, 325 | Foo{ a: 1, b: 8 }, 326 | Foo{ a: 2, b: 9 }, 327 | Foo{ a: 2, b: 10 }, 328 | ]); 329 | let b = Set::new(&[1, 3, 4, 5]).unwrap(); 330 | 331 | let difference: SetBuf = DifferenceByKey::new(a, b, |x| x.a, |&x| x).into_set_buf(); 332 | 333 | assert_eq!(difference.as_slice(), &[ 334 | Foo{ a: 2, b: 9 }, 335 | Foo{ a: 2, b: 10 }, 336 | ][..]); 337 | } 338 | 339 | quickcheck! { 340 | fn qc_difference(a: Vec, b: Vec) -> bool { 341 | use std::collections::BTreeSet; 342 | use std::iter::FromIterator; 343 | 344 | let mut a = a; 345 | let mut b = b; 346 | 347 | sort_dedup_vec(&mut a); 348 | sort_dedup_vec(&mut b); 349 | 350 | let x: SetBuf = { 351 | let difference = DifferenceByKey { a: &a, b: &b, f: |&x| x, g: |&x| x as i32 }; 352 | difference.into_set_buf() 353 | }; 354 | 355 | let a = BTreeSet::from_iter(a); 356 | let b = BTreeSet::from_iter(b.into_iter().map(|x| x as i32)); 357 | let y = a.difference(&b); 358 | let y: Vec<_> = y.cloned().collect(); 359 | 360 | x.as_slice() == y.as_slice() 361 | } 362 | } 363 | } 364 | 365 | mod set_to_iter { 366 | use super::super::*; 367 | use crate::set::sort_dedup_vec; 368 | 369 | #[derive(Debug, Clone, PartialEq, Eq)] 370 | struct Foo { 371 | a: i32, 372 | b: i8, 373 | } 374 | 375 | #[test] 376 | fn difference_empty_no_duplicates() { 377 | let a = Set::new_unchecked(&[ 378 | Foo{ a: 1, b: 8 }, 379 | Foo{ a: 2, b: 9 }, 380 | Foo{ a: 3, b: 10 }, 381 | Foo{ a: 4, b: 11 }, 382 | Foo{ a: 5, b: 12 }, 383 | ]); 384 | let b = Set::new(&[1, 2, 3, 4, 5]).unwrap(); 385 | let difference = DifferenceByKey::new(a, b, |x| x.a, |&x| x); 386 | 387 | let diff_ref: Vec = difference.iter().cloned().collect(); 388 | assert!(diff_ref.is_empty()); 389 | 390 | let diff_own: Vec = difference.into_iter().cloned().collect(); 391 | assert!(diff_own.is_empty()); 392 | } 393 | 394 | #[test] 395 | fn difference_empty_duplicate_relations() { 396 | let a = Set::new_unchecked(&[ 397 | Foo{ a: 1, b: 6 }, 398 | Foo{ a: 1, b: 7 }, 399 | Foo{ a: 1, b: 8 }, 400 | Foo{ a: 2, b: 9 }, 401 | Foo{ a: 2, b: 10 }, 402 | ]); 403 | let b = Set::new(&[1, 2, 3, 4, 5]).unwrap(); 404 | 405 | let difference = DifferenceByKey::new(a, b, |x| x.a, |&x| x); 406 | 407 | let diff_ref: Vec = difference.iter().cloned().collect(); 408 | assert!(diff_ref.is_empty()); 409 | 410 | let diff_own: Vec = difference.into_iter().cloned().collect(); 411 | assert!(diff_own.is_empty()); 412 | } 413 | 414 | #[test] 415 | fn difference_non_empty_duplicate_relations() { 416 | let a = Set::new_unchecked(&[ 417 | Foo{ a: 1, b: 6 }, 418 | Foo{ a: 1, b: 7 }, 419 | Foo{ a: 1, b: 8 }, 420 | Foo{ a: 2, b: 9 }, 421 | Foo{ a: 2, b: 10 }, 422 | ]); 423 | let b = Set::new(&[1, 3, 4, 5]).unwrap(); 424 | 425 | let difference = DifferenceByKey::new(a, b, |x| x.a, |&x| x); 426 | 427 | let diff_ref: Vec = difference.iter().cloned().collect(); 428 | assert_eq!(diff_ref.as_slice(), &[ 429 | Foo{ a: 2, b: 9 }, 430 | Foo{ a: 2, b: 10 }, 431 | ][..]); 432 | 433 | let diff_own: Vec = difference.into_iter().cloned().collect(); 434 | assert_eq!(diff_own.as_slice(), &[ 435 | Foo{ a: 2, b: 9 }, 436 | Foo{ a: 2, b: 10 }, 437 | ][..]); 438 | } 439 | 440 | quickcheck! { 441 | fn qc_difference(a: Vec, b: Vec) -> bool { 442 | use std::collections::BTreeSet; 443 | use std::iter::FromIterator; 444 | 445 | let mut a = a; 446 | let mut b = b; 447 | 448 | sort_dedup_vec(&mut a); 449 | sort_dedup_vec(&mut b); 450 | 451 | let x: Vec = { 452 | let difference = DifferenceByKey { a: &a, b: &b, f: |&x| x, g: |&x| x as i32 }; 453 | difference.into_iter().cloned().collect() 454 | }; 455 | 456 | let a = BTreeSet::from_iter(a); 457 | let b = BTreeSet::from_iter(b.into_iter().map(|x| x as i32)); 458 | let y = a.difference(&b); 459 | let y: Vec<_> = y.cloned().collect(); 460 | 461 | x.as_slice() == y.as_slice() 462 | } 463 | } 464 | } 465 | } 466 | 467 | 468 | #[cfg(all(feature = "unstable", test))] 469 | mod bench { 470 | extern crate test; 471 | use super::*; 472 | use self::test::Bencher; 473 | use crate::set::SetBuf; 474 | 475 | #[derive(Debug, Clone)] 476 | pub struct Foo { 477 | a: i32, 478 | b: u8 479 | } 480 | 481 | impl Foo { 482 | fn new(a: i32) -> Foo { 483 | Foo { a, b: 0 } 484 | } 485 | } 486 | 487 | #[bench] 488 | fn two_slices_big(bench: &mut Bencher) { 489 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 490 | let b: Vec<_> = (1..101).collect(); 491 | let f = |x: &Foo| x.a; 492 | let g = |x: &i32| *x; 493 | 494 | bench.iter(|| { 495 | let op = DifferenceByKey { a: &a, b: &b, f, g }; 496 | let res: SetBuf = op.into_set_buf(); 497 | test::black_box(|| res); 498 | }); 499 | } 500 | 501 | #[bench] 502 | fn two_slices_big2(bench: &mut Bencher) { 503 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 504 | let b: Vec<_> = (51..151).collect(); 505 | let f = |x: &Foo| x.a; 506 | let g = |x: &i32| *x; 507 | 508 | bench.iter(|| { 509 | let op = DifferenceByKey { a: &a, b: &b, f, g }; 510 | let res: SetBuf = op.into_set_buf(); 511 | test::black_box(|| res); 512 | }); 513 | } 514 | 515 | #[bench] 516 | fn two_slices_big3(bench: &mut Bencher) { 517 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 518 | let b: Vec<_> = (100..200).collect(); 519 | let f = |x: &Foo| x.a; 520 | let g = |x: &i32| *x; 521 | 522 | bench.iter(|| { 523 | let op = DifferenceByKey { a: &a, b: &b, f, g }; 524 | let res: SetBuf = op.into_set_buf(); 525 | test::black_box(|| res); 526 | }); 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /src/duo/intersection.rs: -------------------------------------------------------------------------------- 1 | use crate::set::Set; 2 | use crate::{exponential_offset_ge, SetOperation, Collection}; 3 | 4 | /// Represent the _intersection_ set operation that will be applied to two slices. 5 | /// 6 | /// # Examples 7 | /// ``` 8 | /// # use sdset::Error; 9 | /// # fn try_main() -> Result<(), Error> { 10 | /// use sdset::duo::OpBuilder; 11 | /// use sdset::{SetOperation, Set, SetBuf}; 12 | /// 13 | /// let a = Set::new(&[1, 2, 4, 6, 7])?; 14 | /// let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 15 | /// 16 | /// let op = OpBuilder::new(a, b).intersection(); 17 | /// 18 | /// let res: SetBuf = op.into_set_buf(); 19 | /// assert_eq!(&res[..], &[2, 4, 6, 7]); 20 | /// # Ok(()) } 21 | /// # try_main().unwrap(); 22 | /// ``` 23 | #[derive(Copy, Clone)] 24 | pub struct Intersection<'a, T: 'a> { 25 | a: &'a [T], 26 | b: &'a [T], 27 | } 28 | 29 | impl<'a, T> Intersection<'a, T> { 30 | /// Construct one with slices checked to be sorted and deduplicated. 31 | pub fn new(a: &'a Set, b: &'a Set) -> Self { 32 | Self { 33 | a: a.as_slice(), 34 | b: b.as_slice(), 35 | } 36 | } 37 | } 38 | 39 | impl<'a, T: Ord> Intersection<'a, T> { 40 | #[inline] 41 | fn extend_collection(mut self, output: &mut C, extend: F) -> Result<(), C::Error> 42 | where C: Collection, 43 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 44 | { 45 | while !self.a.is_empty() && !self.b.is_empty() { 46 | let first_a = &self.a[0]; 47 | let first_b = &self.b[0]; 48 | 49 | if first_a == first_b { 50 | let off = self.a.iter().zip(self.b.iter()).take_while(|(a, b)| a == b).count(); 51 | extend(output, &self.a[..off])?; 52 | 53 | self.a = &self.a[off..]; 54 | self.b = &self.b[off..]; 55 | } 56 | else if first_a < first_b { 57 | self.a = exponential_offset_ge(self.a, first_b); 58 | } 59 | else { 60 | self.b = exponential_offset_ge(self.b, first_a); 61 | } 62 | } 63 | Ok(()) 64 | } 65 | 66 | fn iter(&self) -> IntersectionIter<'a, T> 67 | { 68 | IntersectionIter { 69 | a: self.a, 70 | b: self.b 71 | } 72 | } 73 | } 74 | 75 | impl<'a, T: Ord + Clone> SetOperation for Intersection<'a, T> { 76 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 77 | where C: Collection, 78 | { 79 | self.extend_collection(output, Collection::extend_from_slice) 80 | } 81 | } 82 | 83 | impl<'a, T: Ord> SetOperation<&'a T> for Intersection<'a, T> { 84 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 85 | where C: Collection<&'a T>, 86 | { 87 | self.extend_collection(output, Collection::extend) 88 | } 89 | } 90 | 91 | impl<'a, T: Ord> IntoIterator for Intersection<'a, T> { 92 | type Item = &'a T; 93 | type IntoIter = IntersectionIter<'a, T>; 94 | fn into_iter(self) -> Self::IntoIter { 95 | self.iter() 96 | } 97 | } 98 | 99 | impl<'a, T: Ord> IntoIterator for &'a Intersection<'a, T> { 100 | type Item = &'a T; 101 | type IntoIter = IntersectionIter<'a, T>; 102 | fn into_iter(self) -> Self::IntoIter { 103 | self.iter() 104 | } 105 | } 106 | 107 | pub struct IntersectionIter<'a, T> { 108 | a: &'a [T], 109 | b: &'a [T], 110 | } 111 | 112 | impl<'a, T: Ord> Iterator for IntersectionIter<'a, T> { 113 | type Item = &'a T; 114 | 115 | fn next(&mut self) -> Option { 116 | loop { 117 | if self.a.is_empty() || self.b.is_empty() { 118 | return None; 119 | } 120 | let first_a = &self.a[0]; 121 | let first_b = &self.b[0]; 122 | if first_a == first_b { 123 | self.a = &self.a[1..]; 124 | self.b = &self.b[1..]; 125 | return Some(first_a); 126 | } else if first_a < first_b { 127 | self.a = exponential_offset_ge(self.a, first_b); 128 | } else { 129 | self.b = exponential_offset_ge(self.b, first_a); 130 | } 131 | } 132 | } 133 | } 134 | 135 | #[cfg(test)] 136 | mod tests { 137 | mod set_to_set { 138 | use super::super::*; 139 | use crate::set::{sort_dedup_vec, SetBuf}; 140 | 141 | #[test] 142 | fn two_slices() { 143 | let a = &[1, 2, 3]; 144 | let b = &[2, 3, 4]; 145 | 146 | let intersection_: SetBuf = Intersection { a: a, b: b }.into_set_buf(); 147 | assert_eq!(&intersection_[..], &[2, 3]); 148 | } 149 | 150 | quickcheck! { 151 | fn qc_intersection(a: Vec, b: Vec) -> bool { 152 | use std::collections::BTreeSet; 153 | use std::iter::FromIterator; 154 | 155 | let mut a = a; 156 | let mut b = b; 157 | 158 | sort_dedup_vec(&mut a); 159 | sort_dedup_vec(&mut b); 160 | 161 | let x: SetBuf = Intersection { a: &a, b: &b }.into_set_buf(); 162 | 163 | let a = BTreeSet::from_iter(a); 164 | let b = BTreeSet::from_iter(b); 165 | let y = a.intersection(&b); 166 | let y: Vec<_> = y.cloned().collect(); 167 | 168 | x.as_slice() == y.as_slice() 169 | } 170 | } 171 | } 172 | 173 | mod set_to_iter { 174 | use super::super::*; 175 | use crate::set::sort_dedup_vec; 176 | 177 | #[test] 178 | fn two_slices() { 179 | let a = &[1, 2, 3]; 180 | let b = &[2, 3, 4]; 181 | 182 | let intersection_: Vec = Intersection { a: a, b: b }.into_iter().cloned().collect(); 183 | assert_eq!(&intersection_[..], &[2, 3]); 184 | } 185 | 186 | quickcheck! { 187 | fn qc_intersection(a: Vec, b: Vec) -> bool { 188 | use std::collections::BTreeSet; 189 | use std::iter::FromIterator; 190 | 191 | let mut a = a; 192 | let mut b = b; 193 | 194 | sort_dedup_vec(&mut a); 195 | sort_dedup_vec(&mut b); 196 | 197 | let x: Vec = Intersection { a: &a, b: &b }.into_iter().cloned().collect(); 198 | 199 | let a = BTreeSet::from_iter(a); 200 | let b = BTreeSet::from_iter(b); 201 | let y = a.intersection(&b); 202 | let y: Vec<_> = y.cloned().collect(); 203 | 204 | x.as_slice() == y.as_slice() 205 | } 206 | } 207 | } 208 | } 209 | 210 | #[cfg(all(feature = "unstable", test))] 211 | mod bench { 212 | extern crate test; 213 | use super::*; 214 | use self::test::Bencher; 215 | use crate::set::SetBuf; 216 | 217 | #[bench] 218 | fn two_slices_big(bench: &mut Bencher) { 219 | let a: Vec<_> = (0..100).collect(); 220 | let b: Vec<_> = (1..101).collect(); 221 | 222 | bench.iter(|| { 223 | let intersection_: SetBuf = Intersection { a: &a, b: &b }.into_set_buf(); 224 | test::black_box(|| intersection_); 225 | }); 226 | } 227 | 228 | #[bench] 229 | fn two_slices_big2(bench: &mut Bencher) { 230 | let a: Vec<_> = (0..100).collect(); 231 | let b: Vec<_> = (51..151).collect(); 232 | 233 | bench.iter(|| { 234 | let intersection_: SetBuf = Intersection { a: &a, b: &b }.into_set_buf(); 235 | test::black_box(|| intersection_); 236 | }); 237 | } 238 | 239 | #[bench] 240 | fn two_slices_big3(bench: &mut Bencher) { 241 | let a: Vec<_> = (0..100).collect(); 242 | let b: Vec<_> = (100..200).collect(); 243 | 244 | bench.iter(|| { 245 | let intersection_: SetBuf = Intersection { a: &a, b: &b }.into_set_buf(); 246 | test::black_box(|| intersection_); 247 | }); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/duo/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains the types to make set operations on two slices and only two. 2 | //! 3 | //! # Examples 4 | //! ``` 5 | //! # use sdset::Error; 6 | //! # fn try_main() -> Result<(), Error> { 7 | //! use sdset::duo::OpBuilder; 8 | //! use sdset::{SetOperation, Set, SetBuf}; 9 | //! 10 | //! let a = Set::new(&[1, 2, 4, 6, 7])?; 11 | //! let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 12 | //! 13 | //! let op = OpBuilder::new(a, b).union(); 14 | //! 15 | //! let res: SetBuf = op.into_set_buf(); 16 | //! assert_eq!(&res[..], &[1, 2, 3, 4, 5, 6, 7]); 17 | //! # Ok(()) } 18 | //! # try_main().unwrap(); 19 | //! ``` 20 | 21 | use crate::set::Set; 22 | 23 | mod union; 24 | mod difference; 25 | mod difference_by_key; 26 | mod intersection; 27 | mod symmetric_difference; 28 | 29 | pub use self::union::Union; 30 | pub use self::difference::Difference; 31 | pub use self::difference_by_key::DifferenceByKey; 32 | pub use self::intersection::Intersection; 33 | pub use self::symmetric_difference::SymmetricDifference; 34 | 35 | /// Type used to make a set operation on two slices only. 36 | #[derive(Copy, Clone)] 37 | pub struct OpBuilder<'a, T: 'a> { 38 | a: &'a Set, 39 | b: &'a Set, 40 | } 41 | 42 | impl<'a, T> OpBuilder<'a, T> { 43 | /// Construct a type with two slices. 44 | pub fn new(a: &'a Set, b: &'a Set) -> Self { 45 | Self { a, b } 46 | } 47 | 48 | /// Prepare the two slices for the _union_ set operation. 49 | pub fn union(self) -> Union<'a, T> { 50 | Union::new(self.a, self.b) 51 | } 52 | 53 | /// Prepare the two slices for the _intersection_ set operation. 54 | pub fn intersection(self) -> Intersection<'a, T> { 55 | Intersection::new(self.a, self.b) 56 | } 57 | 58 | /// Prepare the two slices for the _difference_ set operation. 59 | pub fn difference(self) -> Difference<'a, T> { 60 | Difference::new(self.a, self.b) 61 | } 62 | 63 | /// Prepare the two slices for the _difference_ set operation. 64 | pub fn symmetric_difference(self) -> SymmetricDifference<'a, T> { 65 | SymmetricDifference::new(self.a, self.b) 66 | } 67 | } 68 | 69 | /// Type used to make a set operation on two slices of different types. 70 | /// 71 | /// The two functions are used to generate a key that will be used to 72 | /// make the set operation and correlate the two slices values. 73 | #[derive(Copy, Clone)] 74 | pub struct OpBuilderByKey<'a, T: 'a, U: 'a, F, G, K> 75 | where F: Fn(&T) -> K, 76 | G: Fn(&U) -> K, 77 | K: Ord, 78 | { 79 | a: &'a Set, 80 | b: &'a Set, 81 | f: F, 82 | g: G, 83 | } 84 | 85 | impl<'a, T, U, F, G, K> OpBuilderByKey<'a, T, U, F, G, K> 86 | where F: Fn(&T) -> K, 87 | G: Fn(&U) -> K, 88 | K: Ord, 89 | { 90 | /// Construct a type with two slices. 91 | pub fn new(a: &'a Set, b: &'a Set, f: F, g: G) -> Self { 92 | Self { a, b, f, g } 93 | } 94 | 95 | /// Prepare the two slices for the _difference_ set operation. 96 | pub fn difference(self) -> DifferenceByKey<'a, T, U, F, G, K> { 97 | DifferenceByKey::new(self.a, self.b, self.f, self.g) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/duo/symmetric_difference.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | use crate::set::Set; 3 | use crate::{SetOperation, Collection}; 4 | 5 | /// Represent the _symmetric difference_ set operation that will be applied to two slices. 6 | /// 7 | /// # Examples 8 | /// ``` 9 | /// # use sdset::Error; 10 | /// # fn try_main() -> Result<(), Error> { 11 | /// use sdset::duo::OpBuilder; 12 | /// use sdset::{SetOperation, Set, SetBuf}; 13 | /// 14 | /// let a = Set::new(&[1, 2, 4, 6, 7])?; 15 | /// let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 16 | /// 17 | /// let op = OpBuilder::new(a, b).symmetric_difference(); 18 | /// 19 | /// let res: SetBuf = op.into_set_buf(); 20 | /// assert_eq!(&res[..], &[1, 3, 5]); 21 | /// # Ok(()) } 22 | /// # try_main().unwrap(); 23 | /// ``` 24 | #[derive(Copy, Clone)] 25 | pub struct SymmetricDifference<'a, T: 'a> { 26 | a: &'a [T], 27 | b: &'a [T], 28 | } 29 | 30 | impl<'a, T> SymmetricDifference<'a, T> { 31 | /// Construct one with slices checked to be sorted and deduplicated. 32 | pub fn new(a: &'a Set, b: &'a Set) -> Self { 33 | Self { 34 | a: a.as_slice(), 35 | b: b.as_slice(), 36 | } 37 | } 38 | } 39 | 40 | impl<'a, T: Ord> SymmetricDifference<'a, T> { 41 | #[inline] 42 | fn extend_collection(mut self, output: &mut C, extend: F) -> Result<(), C::Error> 43 | where C: Collection, 44 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 45 | { 46 | loop { 47 | match (self.a.first(), self.b.first()) { 48 | (Some(a), Some(b)) => { 49 | match a.cmp(b) { 50 | Ordering::Less => { 51 | let off = self.a.iter().take_while(|&e| e < b).count(); 52 | extend(output, &self.a[..off])?; 53 | self.a = &self.a[off..]; 54 | }, 55 | Ordering::Equal => { 56 | let off = self.a.iter().zip(self.b.iter()).take_while(|(a, b)| a == b).count(); 57 | self.a = &self.a[off..]; 58 | self.b = &self.b[off..]; 59 | }, 60 | Ordering::Greater => { 61 | let off = self.b.iter().take_while(|&e| e < a).count(); 62 | extend(output, &self.b[..off])?; 63 | self.b = &self.b[off..]; 64 | }, 65 | } 66 | }, 67 | (Some(_), None) => { 68 | extend(output, self.a)?; 69 | break; 70 | }, 71 | (None, Some(_)) => { 72 | extend(output, self.b)?; 73 | break; 74 | }, 75 | (None, None) => break, 76 | } 77 | } 78 | Ok(()) 79 | } 80 | 81 | fn iter(&self) -> SymmetricDifferenceIter<'a, T> 82 | { 83 | SymmetricDifferenceIter { 84 | a: self.a, 85 | b: self.b 86 | } 87 | } 88 | } 89 | 90 | impl<'a, T: Ord + Clone> SetOperation for SymmetricDifference<'a, T> { 91 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 92 | where C: Collection, 93 | { 94 | self.extend_collection(output, Collection::extend_from_slice) 95 | } 96 | } 97 | 98 | impl<'a, T: Ord> SetOperation<&'a T> for SymmetricDifference<'a, T> { 99 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 100 | where C: Collection<&'a T>, 101 | { 102 | self.extend_collection(output, Collection::extend) 103 | } 104 | } 105 | 106 | impl<'a, T: Ord> IntoIterator for SymmetricDifference<'a, T> { 107 | type Item = &'a T; 108 | type IntoIter = SymmetricDifferenceIter<'a, T>; 109 | fn into_iter(self) -> Self::IntoIter { 110 | self.iter() 111 | } 112 | } 113 | 114 | impl<'a, T: Ord> IntoIterator for &'a SymmetricDifference<'a, T> { 115 | type Item = &'a T; 116 | type IntoIter = SymmetricDifferenceIter<'a, T>; 117 | fn into_iter(self) -> Self::IntoIter { 118 | self.iter() 119 | } 120 | } 121 | 122 | pub struct SymmetricDifferenceIter<'a, T> { 123 | a: &'a [T], 124 | b: &'a [T], 125 | } 126 | 127 | impl<'a, T: Ord> Iterator for SymmetricDifferenceIter<'a, T> { 128 | type Item = &'a T; 129 | 130 | fn next(&mut self) -> Option { 131 | loop { 132 | match (self.a.first(), self.b.first()) { 133 | (Some(first_a), Some(first_b)) => { 134 | match first_a.cmp(first_b) { 135 | Ordering::Less => { 136 | self.a = &self.a[1..]; 137 | return Some(first_a); 138 | }, 139 | Ordering::Equal => { 140 | let off = self.a.iter().zip(self.b.iter()).take_while(|(a, b)| a == b).count(); 141 | self.a = &self.a[off..]; 142 | self.b = &self.b[off..]; 143 | }, 144 | Ordering::Greater => { 145 | self.b = &self.b[1..]; 146 | return Some(first_b); 147 | }, 148 | } 149 | }, 150 | (Some(first_a), None) => { 151 | self.a = &self.a[1..]; 152 | return Some(first_a); 153 | }, 154 | (None, Some(first_b)) => { 155 | self.b = &self.b[1..]; 156 | return Some(first_b); 157 | }, 158 | (None, None) => return None, 159 | } 160 | } 161 | } 162 | } 163 | 164 | #[cfg(test)] 165 | mod tests { 166 | mod set_to_set { 167 | use super::super::*; 168 | use crate::set::{sort_dedup_vec, SetBuf}; 169 | 170 | quickcheck! { 171 | fn qc_symmetric_difference(a: Vec, b: Vec) -> bool { 172 | use std::collections::BTreeSet; 173 | use std::iter::FromIterator; 174 | 175 | let mut a = a; 176 | let mut b = b; 177 | 178 | sort_dedup_vec(&mut a); 179 | sort_dedup_vec(&mut b); 180 | 181 | let x: SetBuf = SymmetricDifference { a: &a, b: &b }.into_set_buf(); 182 | 183 | let a = BTreeSet::from_iter(a); 184 | let b = BTreeSet::from_iter(b); 185 | let y = a.symmetric_difference(&b); 186 | let y: Vec<_> = y.cloned().collect(); 187 | 188 | x.as_slice() == y.as_slice() 189 | } 190 | } 191 | } 192 | mod set_to_iter { 193 | use super::super::*; 194 | use crate::set::sort_dedup_vec; 195 | 196 | quickcheck! { 197 | fn qc_symmetric_difference(a: Vec, b: Vec) -> bool { 198 | use std::collections::BTreeSet; 199 | use std::iter::FromIterator; 200 | 201 | let mut a = a; 202 | let mut b = b; 203 | 204 | sort_dedup_vec(&mut a); 205 | sort_dedup_vec(&mut b); 206 | 207 | let x: Vec = SymmetricDifference { a: &a, b: &b }.into_iter().cloned().collect(); 208 | 209 | let a = BTreeSet::from_iter(a); 210 | let b = BTreeSet::from_iter(b); 211 | let y = a.symmetric_difference(&b); 212 | let y: Vec<_> = y.cloned().collect(); 213 | 214 | x.as_slice() == y.as_slice() 215 | } 216 | } 217 | } 218 | } 219 | 220 | #[cfg(all(feature = "unstable", test))] 221 | mod bench { 222 | extern crate test; 223 | use super::*; 224 | use self::test::Bencher; 225 | use crate::set::SetBuf; 226 | 227 | #[bench] 228 | fn two_slices_big(bench: &mut Bencher) { 229 | let a: Vec<_> = (0..100).collect(); 230 | let b: Vec<_> = (1..101).collect(); 231 | 232 | bench.iter(|| { 233 | let symmetric_difference_: SetBuf = SymmetricDifference { a: &a, b: &b }.into_set_buf(); 234 | test::black_box(|| symmetric_difference_); 235 | }); 236 | } 237 | 238 | #[bench] 239 | fn two_slices_big2(bench: &mut Bencher) { 240 | let a: Vec<_> = (0..100).collect(); 241 | let b: Vec<_> = (51..151).collect(); 242 | 243 | bench.iter(|| { 244 | let symmetric_difference_: SetBuf = SymmetricDifference { a: &a, b: &b }.into_set_buf(); 245 | test::black_box(|| symmetric_difference_); 246 | }); 247 | } 248 | 249 | #[bench] 250 | fn two_slices_big3(bench: &mut Bencher) { 251 | let a: Vec<_> = (0..100).collect(); 252 | let b: Vec<_> = (100..200).collect(); 253 | 254 | bench.iter(|| { 255 | let symmetric_difference_: SetBuf = SymmetricDifference { a: &a, b: &b }.into_set_buf(); 256 | test::black_box(|| symmetric_difference_); 257 | }); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/duo/union.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::{self, Ordering}; 2 | use crate::set::Set; 3 | use crate::{SetOperation, Collection}; 4 | 5 | /// Represent the _union_ set operation that will be applied to two slices. 6 | /// 7 | /// # Examples 8 | /// ``` 9 | /// # use sdset::Error; 10 | /// # fn try_main() -> Result<(), Error> { 11 | /// use sdset::duo::OpBuilder; 12 | /// use sdset::{SetOperation, Set, SetBuf}; 13 | /// 14 | /// let a = Set::new(&[1, 2, 4, 6, 7])?; 15 | /// let b = Set::new(&[2, 3, 4, 5, 6, 7])?; 16 | /// 17 | /// let op = OpBuilder::new(a, b).union(); 18 | /// 19 | /// let res: SetBuf = op.into_set_buf(); 20 | /// assert_eq!(&res[..], &[1, 2, 3, 4, 5, 6, 7]); 21 | /// # Ok(()) } 22 | /// # try_main().unwrap(); 23 | /// ``` 24 | #[derive(Copy, Clone)] 25 | pub struct Union<'a, T: 'a> { 26 | a: &'a [T], 27 | b: &'a [T], 28 | } 29 | 30 | impl<'a, T> Union<'a, T> { 31 | /// Construct one with slices checked to be sorted and deduplicated. 32 | pub fn new(a: &'a Set, b: &'a Set) -> Self { 33 | Self { 34 | a: a.as_slice(), 35 | b: b.as_slice(), 36 | } 37 | } 38 | } 39 | 40 | impl<'a, T: Ord> Union<'a, T> { 41 | #[inline] 42 | fn extend_collection(mut self, output: &mut C, extend: F) -> Result<(), C::Error> 43 | where C: Collection, 44 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 45 | { 46 | let min_len = cmp::max(self.a.len(), self.b.len()); 47 | output.reserve(min_len)?; 48 | 49 | while !self.a.is_empty() && !self.b.is_empty() { 50 | let first_a = &self.a[0]; 51 | let first_b = &self.b[0]; 52 | 53 | match first_a.cmp(&first_b) { 54 | Ordering::Less => { 55 | let off = self.a.iter().take_while(|&x| x < first_b).count(); 56 | extend(output, &self.a[..off])?; 57 | 58 | self.a = &self.a[off..]; 59 | }, 60 | Ordering::Equal => { 61 | let off = self.a.iter().zip(self.b.iter()).take_while(|(a, b)| a == b).count(); 62 | extend(output, &self.a[..off])?; 63 | 64 | self.a = &self.a[off..]; 65 | self.b = &self.b[off..]; 66 | }, 67 | Ordering::Greater => { 68 | let off = self.b.iter().take_while(|&x| x < first_a).count(); 69 | extend(output, &self.b[..off])?; 70 | 71 | self.b = &self.b[off..]; 72 | }, 73 | } 74 | } 75 | 76 | extend(output, self.a)?; 77 | extend(output, self.b)?; 78 | Ok(()) 79 | } 80 | 81 | fn iter(&self) -> UnionIter<'a, T> 82 | { 83 | UnionIter { 84 | a: self.a, 85 | b: self.b 86 | } 87 | } 88 | } 89 | 90 | impl<'a, T: Ord + Clone> SetOperation for Union<'a, T> { 91 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 92 | where C: Collection, 93 | { 94 | self.extend_collection(output, Collection::extend_from_slice) 95 | } 96 | } 97 | 98 | impl<'a, T: Ord> SetOperation<&'a T> for Union<'a, T> { 99 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 100 | where C: Collection<&'a T>, 101 | { 102 | self.extend_collection(output, Collection::extend) 103 | } 104 | } 105 | 106 | impl<'a, T: Ord> IntoIterator for Union<'a, T> { 107 | type Item = &'a T; 108 | type IntoIter = UnionIter<'a, T>; 109 | fn into_iter(self) -> Self::IntoIter { 110 | self.iter() 111 | } 112 | } 113 | 114 | impl<'a, T: Ord> IntoIterator for &'a Union<'a, T> { 115 | type Item = &'a T; 116 | type IntoIter = UnionIter<'a, T>; 117 | fn into_iter(self) -> Self::IntoIter { 118 | self.iter() 119 | } 120 | } 121 | 122 | pub struct UnionIter<'a, T> { 123 | a: &'a [T], 124 | b: &'a [T], 125 | } 126 | 127 | impl<'a, T: Ord> Iterator for UnionIter<'a, T> { 128 | type Item = &'a T; 129 | 130 | fn next(&mut self) -> Option { 131 | if self.a.is_empty() { 132 | let result = self.b.first(); 133 | if result.is_some() { 134 | self.b = &self.b[1..]; 135 | } 136 | return result; 137 | } 138 | if self.b.is_empty() { 139 | let result = self.a.first(); 140 | if result.is_some() { 141 | self.a = &self.a[1..]; 142 | } 143 | return result; 144 | } 145 | let first_a = &self.a[0]; 146 | let first_b = &self.b[0]; 147 | 148 | match first_a.cmp(&first_b) { 149 | Ordering::Less => { 150 | self.a = &self.a[1..]; 151 | return Some(first_a); 152 | }, 153 | Ordering::Equal => { 154 | self.a = &self.a[1..]; 155 | self.b = &self.b[1..]; 156 | return Some(first_a); 157 | }, 158 | Ordering::Greater => { 159 | self.b = &self.b[1..]; 160 | return Some(first_b); 161 | }, 162 | } 163 | } 164 | } 165 | 166 | #[cfg(test)] 167 | mod tests { 168 | mod set_to_set { 169 | use super::super::*; 170 | use crate::set::{sort_dedup_vec, SetBuf}; 171 | 172 | #[test] 173 | fn union_two_slices_easy() { 174 | let a = &[1, 2, 3]; 175 | let b = &[2, 3, 4]; 176 | 177 | let union_: SetBuf = Union { a: a, b: b }.into_set_buf(); 178 | 179 | assert_eq!(&union_[..], &[1, 2, 3, 4]); 180 | } 181 | 182 | #[test] 183 | fn union_two_slices_second_empty() { 184 | let a = &[1, 2, 3]; 185 | let b = &[]; 186 | 187 | let union_: SetBuf = Union { a: a, b: b }.into_set_buf(); 188 | 189 | assert_eq!(&union_[..], &[1, 2, 3]); 190 | } 191 | 192 | #[test] 193 | fn union_two_slices_first_empty() { 194 | let a = &[]; 195 | let b = &[2, 3, 4]; 196 | 197 | let union_: SetBuf = Union { a: a, b: b }.into_set_buf(); 198 | 199 | assert_eq!(&union_[..], &[2, 3, 4]); 200 | } 201 | 202 | #[test] 203 | fn union_two_slices_same_elem() { 204 | let a = &[1]; 205 | let b = &[1]; 206 | 207 | let union_: SetBuf = Union { a: a, b: b }.into_set_buf(); 208 | 209 | assert_eq!(&union_[..], &[1]); 210 | } 211 | 212 | quickcheck! { 213 | fn qc_union(a: Vec, b: Vec) -> bool { 214 | use std::collections::BTreeSet; 215 | use std::iter::FromIterator; 216 | 217 | let mut a = a; 218 | let mut b = b; 219 | 220 | sort_dedup_vec(&mut a); 221 | sort_dedup_vec(&mut b); 222 | 223 | let x: SetBuf = Union { a: &a, b: &b }.into_set_buf(); 224 | 225 | let a = BTreeSet::from_iter(a); 226 | let b = BTreeSet::from_iter(b); 227 | let y = a.union(&b); 228 | let y: Vec<_> = y.cloned().collect(); 229 | 230 | x.as_slice() == y.as_slice() 231 | } 232 | } 233 | } 234 | 235 | mod set_to_iter { 236 | use super::super::*; 237 | use crate::set::sort_dedup_vec; 238 | 239 | #[test] 240 | fn union_two_slices_easy() { 241 | let a = &[1, 2, 3]; 242 | let b = &[2, 3, 4]; 243 | 244 | let union_: Vec = Union { a: a, b: b }.into_iter().cloned().collect(); 245 | 246 | assert_eq!(&union_[..], &[1, 2, 3, 4]); 247 | } 248 | 249 | #[test] 250 | fn union_two_slices_second_empty() { 251 | let a = &[1, 2, 3]; 252 | let b = &[]; 253 | 254 | let union_: Vec = Union { a: a, b: b }.into_iter().cloned().collect(); 255 | 256 | assert_eq!(&union_[..], &[1, 2, 3]); 257 | } 258 | 259 | #[test] 260 | fn union_two_slices_first_empty() { 261 | let a = &[]; 262 | let b = &[2, 3, 4]; 263 | 264 | let union_: Vec = Union { a: a, b: b }.into_iter().cloned().collect(); 265 | 266 | assert_eq!(&union_[..], &[2, 3, 4]); 267 | } 268 | 269 | #[test] 270 | fn union_two_slices_same_elem() { 271 | let a = &[1]; 272 | let b = &[1]; 273 | 274 | let union_: Vec = Union { a: a, b: b }.into_iter().cloned().collect(); 275 | 276 | assert_eq!(&union_[..], &[1]); 277 | } 278 | 279 | quickcheck! { 280 | fn qc_union(a: Vec, b: Vec) -> bool { 281 | use std::collections::BTreeSet; 282 | use std::iter::FromIterator; 283 | 284 | let mut a = a; 285 | let mut b = b; 286 | 287 | sort_dedup_vec(&mut a); 288 | sort_dedup_vec(&mut b); 289 | 290 | let x: Vec = Union { a: &a, b: &b }.into_iter().cloned().collect(); 291 | 292 | let a = BTreeSet::from_iter(a); 293 | let b = BTreeSet::from_iter(b); 294 | let y = a.union(&b); 295 | let y: Vec<_> = y.cloned().collect(); 296 | 297 | x.as_slice() == y.as_slice() 298 | } 299 | } 300 | } 301 | } 302 | 303 | #[cfg(all(feature = "unstable", test))] 304 | mod bench { 305 | extern crate test; 306 | use super::*; 307 | use self::test::Bencher; 308 | use crate::set::SetBuf; 309 | 310 | #[bench] 311 | fn two_slices_big(bench: &mut Bencher) { 312 | let a: Vec<_> = (0..100).collect(); 313 | let b: Vec<_> = (1..101).collect(); 314 | 315 | bench.iter(|| { 316 | let union_: SetBuf = Union { a: &a, b: &b }.into_set_buf(); 317 | test::black_box(|| union_); 318 | }); 319 | } 320 | 321 | #[bench] 322 | fn two_slices_big2(bench: &mut Bencher) { 323 | let a: Vec<_> = (0..100).collect(); 324 | let b: Vec<_> = (51..151).collect(); 325 | 326 | bench.iter(|| { 327 | let union_: SetBuf = Union { a: &a, b: &b }.into_set_buf(); 328 | test::black_box(|| union_); 329 | }); 330 | } 331 | 332 | #[bench] 333 | fn two_slices_big3(bench: &mut Bencher) { 334 | let a: Vec<_> = (0..100).collect(); 335 | let b: Vec<_> = (100..200).collect(); 336 | 337 | bench.iter(|| { 338 | let union_: SetBuf = Union { a: &a, b: &b }.into_set_buf(); 339 | test::black_box(|| union_); 340 | }); 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /src/multi/difference.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | use crate::set::{Set, vec_sets_into_slices}; 3 | use crate::{SetOperation, Collection, exponential_offset_ge}; 4 | 5 | /// Represent the _difference_ set operation that will be applied to the slices. 6 | /// 7 | /// Note that the difference is all the elements 8 | /// that are in the first slice but not in all the others. 9 | /// 10 | /// # Examples 11 | /// ``` 12 | /// # use sdset::Error; 13 | /// # fn try_main() -> Result<(), Error> { 14 | /// use sdset::multi::OpBuilder; 15 | /// use sdset::{SetOperation, Set, SetBuf}; 16 | /// 17 | /// let a = Set::new(&[1, 2, 4])?; 18 | /// let b = Set::new(&[2, 3, 5, 7])?; 19 | /// let c = Set::new(&[4, 6, 7])?; 20 | /// 21 | /// let op = OpBuilder::from_vec(vec![a, b, c]).difference(); 22 | /// 23 | /// let res: SetBuf = op.into_set_buf(); 24 | /// assert_eq!(&res[..], &[1]); 25 | /// # Ok(()) } 26 | /// # try_main().unwrap(); 27 | /// ``` 28 | #[derive(Clone)] 29 | pub struct Difference<'a, T: 'a> { 30 | slices: Vec<&'a [T]>, 31 | } 32 | 33 | impl<'a, T> Difference<'a, T> { 34 | /// Construct one with slices checked to be sorted and deduplicated. 35 | pub fn new(slices: Vec<&'a Set>) -> Self { 36 | Self { 37 | slices: vec_sets_into_slices(slices), 38 | } 39 | } 40 | } 41 | 42 | impl<'a, T: Ord> Difference<'a, T> { 43 | #[inline] 44 | fn extend_collection(mut self, output: &mut C, extend: F) -> Result<(), C::Error> 45 | where C: Collection, 46 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 47 | { 48 | let (base, others) = match self.slices.split_first_mut() { 49 | Some(split) => split, 50 | None => return Ok(()), 51 | }; 52 | 53 | while let Some(first) = base.first() { 54 | let mut minimum = None; 55 | for slice in others.iter_mut() { 56 | *slice = exponential_offset_ge(slice, first); 57 | minimum = match (minimum, slice.first()) { 58 | (Some(min), Some(first)) => Some(cmp::min(min, first)), 59 | (None, Some(first)) => Some(first), 60 | (min, _) => min, 61 | }; 62 | } 63 | 64 | match minimum { 65 | Some(min) if min == first => { 66 | *base = &base[1..]; 67 | }, 68 | Some(min) => { 69 | let off = base.iter().take_while(|&x| x < min).count(); 70 | extend(output, &base[..off])?; 71 | 72 | *base = &base[off..]; 73 | }, 74 | None => { 75 | extend(output, base)?; 76 | break; 77 | }, 78 | } 79 | } 80 | Ok(()) 81 | } 82 | 83 | fn iter(&self) -> DifferenceIter<'a, T> 84 | { 85 | DifferenceIter { 86 | slices: self.slices.clone(), 87 | } 88 | } 89 | } 90 | 91 | impl<'a, T: Ord + Clone> SetOperation for Difference<'a, T> { 92 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 93 | where C: Collection, 94 | { 95 | self.extend_collection(output, Collection::extend_from_slice) 96 | } 97 | } 98 | 99 | impl<'a, T: Ord> SetOperation<&'a T> for Difference<'a, T> { 100 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 101 | where C: Collection<&'a T>, 102 | { 103 | self.extend_collection(output, Collection::extend) 104 | } 105 | } 106 | 107 | impl<'a, T: Ord> IntoIterator for Difference<'a, T> { 108 | type Item = &'a T; 109 | type IntoIter = DifferenceIter<'a, T>; 110 | fn into_iter(self) -> Self::IntoIter { 111 | DifferenceIter { 112 | slices: self.slices, 113 | } 114 | } 115 | } 116 | 117 | impl<'a, T: Ord> IntoIterator for &'a Difference<'a, T> { 118 | type Item = &'a T; 119 | type IntoIter = DifferenceIter<'a, T>; 120 | fn into_iter(self) -> Self::IntoIter { 121 | self.iter() 122 | } 123 | } 124 | 125 | pub struct DifferenceIter<'a, T> { 126 | slices: Vec<&'a [T]>, 127 | } 128 | 129 | impl<'a, T: Ord> Iterator for DifferenceIter<'a, T> { 130 | type Item = &'a T; 131 | 132 | fn next(&mut self) -> Option { 133 | let (base, others) = match self.slices.split_first_mut() { 134 | Some(split) => split, 135 | None => return None, 136 | }; 137 | 138 | loop { 139 | if base.is_empty() { 140 | return None; 141 | } 142 | while let Some(first) = base.first() { 143 | let mut minimum = None; 144 | for slice in others.iter_mut() { 145 | *slice = exponential_offset_ge(slice, first); 146 | minimum = match (minimum, slice.first()) { 147 | (Some(min), Some(first)) => Some(cmp::min(min, first)), 148 | (None, Some(first)) => Some(first), 149 | (min, _) => min, 150 | }; 151 | } 152 | 153 | match minimum { 154 | Some(min) if min == first => { 155 | *base = &base[1..]; 156 | }, 157 | _ => { 158 | *base = &base[1..]; 159 | return Some(first); 160 | }, 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | #[cfg(test)] 168 | mod tests { 169 | mod set_to_set { 170 | use super::super::*; 171 | use crate::set::{sort_dedup_vec, SetBuf}; 172 | 173 | #[test] 174 | fn no_slice() { 175 | let difference_: SetBuf = Difference { slices: vec![] }.into_set_buf(); 176 | assert_eq!(&difference_[..], &[]); 177 | } 178 | 179 | #[test] 180 | fn one_empty_slice() { 181 | let a: &[i32] = &[]; 182 | 183 | let difference_: SetBuf = Difference { slices: vec![a] }.into_set_buf(); 184 | assert_eq!(&difference_[..], &[]); 185 | } 186 | 187 | #[test] 188 | fn one_slice() { 189 | let a = &[1, 2, 3]; 190 | 191 | let difference_: SetBuf = Difference { slices: vec![a] }.into_set_buf(); 192 | assert_eq!(&difference_[..], &[1, 2, 3]); 193 | } 194 | 195 | #[test] 196 | fn two_slices() { 197 | let a = &[1, 2, 3]; 198 | let b = &[2, 4]; 199 | 200 | let difference_: SetBuf = Difference { slices: vec![a, b] }.into_set_buf(); 201 | assert_eq!(&difference_[..], &[1, 3]); 202 | } 203 | 204 | #[test] 205 | fn two_slices_special_case() { 206 | let a = &[1, 2, 3]; 207 | let b = &[3]; 208 | 209 | let difference_: SetBuf = Difference { slices: vec![a, b] }.into_set_buf(); 210 | assert_eq!(&difference_[..], &[1, 2]); 211 | } 212 | 213 | #[test] 214 | fn three_slices() { 215 | let a = &[1, 2, 3, 6, 7]; 216 | let b = &[2, 3, 4]; 217 | let c = &[3, 4, 5, 7]; 218 | 219 | let difference_: SetBuf = Difference { slices: vec![a, b, c] }.into_set_buf(); 220 | assert_eq!(&difference_[..], &[1, 6]); 221 | } 222 | 223 | quickcheck! { 224 | fn qc_difference(xss: Vec>) -> bool { 225 | use std::collections::BTreeSet; 226 | use std::iter::FromIterator; 227 | 228 | // FIXME temporary hack (can have mutable parameters!) 229 | let mut xss = xss; 230 | 231 | for xs in &mut xss { 232 | sort_dedup_vec(xs); 233 | } 234 | 235 | let x: SetBuf = { 236 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 237 | Difference { slices: xss }.into_set_buf() 238 | }; 239 | 240 | let mut xss = xss.into_iter(); 241 | let mut y = match xss.next() { 242 | Some(xs) => BTreeSet::from_iter(xs), 243 | None => BTreeSet::new(), 244 | }; 245 | 246 | for v in xss { 247 | let x = BTreeSet::from_iter(v.iter().cloned()); 248 | y = y.difference(&x).cloned().collect(); 249 | } 250 | let y: Vec<_> = y.into_iter().collect(); 251 | 252 | x.as_slice() == y.as_slice() 253 | } 254 | } 255 | } 256 | 257 | mod set_to_iter { 258 | use super::super::*; 259 | use crate::set::sort_dedup_vec; 260 | 261 | #[test] 262 | fn no_slice() { 263 | let difference = Difference { slices: vec![] }; 264 | let diff_ref: Vec = difference.iter().cloned().collect(); 265 | assert_eq!(&diff_ref[..], &[]); 266 | let diff_own: Vec = difference.into_iter().cloned().collect(); 267 | assert_eq!(&diff_own[..], &[]); 268 | } 269 | 270 | #[test] 271 | fn one_empty_slice() { 272 | let a: &[i32] = &[]; 273 | 274 | let difference = Difference { slices: vec![a] }; 275 | let diff_ref: Vec = difference.iter().cloned().collect(); 276 | assert_eq!(&diff_ref[..], &[]); 277 | let diff_own: Vec = difference.into_iter().cloned().collect(); 278 | assert_eq!(&diff_own[..], &[]); 279 | } 280 | 281 | #[test] 282 | fn one_slice() { 283 | let a = &[1, 2, 3]; 284 | 285 | let difference = Difference { slices: vec![a] }; 286 | let diff_ref: Vec = difference.iter().cloned().collect(); 287 | assert_eq!(&diff_ref[..], &[1, 2, 3]); 288 | let diff_own: Vec = difference.into_iter().cloned().collect(); 289 | assert_eq!(&diff_own[..], &[1, 2, 3]); 290 | } 291 | 292 | #[test] 293 | fn two_slices() { 294 | let a = &[1, 2, 3]; 295 | let b = &[2, 4]; 296 | 297 | let difference = Difference { slices: vec![a, b] }; 298 | let diff_ref: Vec = difference.iter().cloned().collect(); 299 | assert_eq!(&diff_ref[..], &[1, 3]); 300 | let diff_own: Vec = difference.into_iter().cloned().collect(); 301 | assert_eq!(&diff_own[..], &[1, 3]); 302 | } 303 | 304 | #[test] 305 | fn two_slices_special_case() { 306 | let a = &[1, 2, 3]; 307 | let b = &[3]; 308 | 309 | let difference = Difference { slices: vec![a, b] }; 310 | let diff_ref: Vec = difference.iter().cloned().collect(); 311 | assert_eq!(&diff_ref[..], &[1, 2]); 312 | let diff_own: Vec = difference.into_iter().cloned().collect(); 313 | assert_eq!(&diff_own[..], &[1, 2]); 314 | } 315 | 316 | #[test] 317 | fn three_slices() { 318 | let a = &[1, 2, 3, 6, 7]; 319 | let b = &[2, 3, 4]; 320 | let c = &[3, 4, 5, 7]; 321 | 322 | let difference = Difference { slices: vec![a, b, c] }; 323 | let diff_ref: Vec = difference.iter().cloned().collect(); 324 | assert_eq!(&diff_ref[..], &[1, 6]); 325 | let diff_own: Vec = difference.into_iter().cloned().collect(); 326 | assert_eq!(&diff_own[..], &[1, 6]); 327 | } 328 | 329 | quickcheck! { 330 | fn qc_difference(xss: Vec>) -> bool { 331 | use std::collections::BTreeSet; 332 | use std::iter::FromIterator; 333 | 334 | // FIXME temporary hack (can have mutable parameters!) 335 | let mut xss = xss; 336 | 337 | for xs in &mut xss { 338 | sort_dedup_vec(xs); 339 | } 340 | 341 | let x: Vec = { 342 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 343 | Difference { slices: xss }.into_iter().cloned().collect() 344 | }; 345 | 346 | let mut xss = xss.into_iter(); 347 | let mut y = match xss.next() { 348 | Some(xs) => BTreeSet::from_iter(xs), 349 | None => BTreeSet::new(), 350 | }; 351 | 352 | for v in xss { 353 | let x = BTreeSet::from_iter(v.iter().cloned()); 354 | y = y.difference(&x).cloned().collect(); 355 | } 356 | let y: Vec<_> = y.into_iter().collect(); 357 | 358 | x.as_slice() == y.as_slice() 359 | } 360 | } 361 | } 362 | } 363 | 364 | #[cfg(all(feature = "unstable", test))] 365 | mod bench { 366 | extern crate test; 367 | use super::*; 368 | use self::test::Bencher; 369 | use crate::set::SetBuf; 370 | 371 | #[bench] 372 | fn two_slices_big(bench: &mut Bencher) { 373 | let a: Vec<_> = (0..100).collect(); 374 | let b: Vec<_> = (1..101).collect(); 375 | 376 | bench.iter(|| { 377 | let difference_: SetBuf = Difference { slices: vec![&a, &b] }.into_set_buf(); 378 | test::black_box(|| difference_); 379 | }); 380 | } 381 | 382 | #[bench] 383 | fn two_slices_big2(bench: &mut Bencher) { 384 | let a: Vec<_> = (0..100).collect(); 385 | let b: Vec<_> = (51..151).collect(); 386 | 387 | bench.iter(|| { 388 | let difference_: SetBuf = Difference { slices: vec![&a, &b] }.into_set_buf(); 389 | test::black_box(|| difference_); 390 | }); 391 | } 392 | 393 | #[bench] 394 | fn two_slices_big3(bench: &mut Bencher) { 395 | let a: Vec<_> = (0..100).collect(); 396 | let b: Vec<_> = (100..200).collect(); 397 | 398 | bench.iter(|| { 399 | let difference_: SetBuf = Difference { slices: vec![&a, &b] }.into_set_buf(); 400 | test::black_box(|| difference_); 401 | }); 402 | } 403 | 404 | #[bench] 405 | fn three_slices_big(bench: &mut Bencher) { 406 | let a: Vec<_> = (0..100).collect(); 407 | let b: Vec<_> = (1..101).collect(); 408 | let c: Vec<_> = (2..102).collect(); 409 | 410 | bench.iter(|| { 411 | let difference_: SetBuf = Difference { slices: vec![&a, &b, &c] }.into_set_buf(); 412 | test::black_box(|| difference_); 413 | }); 414 | } 415 | 416 | #[bench] 417 | fn three_slices_big2(bench: &mut Bencher) { 418 | let a: Vec<_> = (0..100).collect(); 419 | let b: Vec<_> = (34..134).collect(); 420 | let c: Vec<_> = (66..167).collect(); 421 | 422 | bench.iter(|| { 423 | let difference_: SetBuf = Difference { slices: vec![&a, &b, &c] }.into_set_buf(); 424 | test::black_box(|| difference_); 425 | }); 426 | } 427 | 428 | #[bench] 429 | fn three_slices_big3(bench: &mut Bencher) { 430 | let a: Vec<_> = (0..100).collect(); 431 | let b: Vec<_> = (100..200).collect(); 432 | let c: Vec<_> = (200..300).collect(); 433 | 434 | bench.iter(|| { 435 | let difference_: SetBuf = Difference { slices: vec![&a, &b, &c] }.into_set_buf(); 436 | test::black_box(|| difference_); 437 | }); 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /src/multi/difference_by_key.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | use crate::set::{Set, vec_sets_into_slices}; 3 | use crate::{SetOperation, Collection, exponential_offset_ge_by_key}; 4 | 5 | /// Represent the _difference_ set operation that will be applied to multiple slices 6 | /// of two different types. 7 | /// 8 | /// # Examples 9 | /// ``` 10 | /// # use sdset::Error; 11 | /// # fn try_main() -> Result<(), Error> { 12 | /// use sdset::multi::OpBuilderByKey; 13 | /// use sdset::{SetOperation, Set, SetBuf}; 14 | /// 15 | /// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 16 | /// struct Foo { a: i32, b: u8 } 17 | /// 18 | /// let a = Set::new(&[ 19 | /// Foo{ a: 1, b: 6 }, 20 | /// Foo{ a: 1, b: 7 }, 21 | /// Foo{ a: 1, b: 8 }, 22 | /// Foo{ a: 2, b: 9 }, 23 | /// Foo{ a: 2, b: 10 }, 24 | /// Foo{ a: 4, b: 10 }, 25 | /// ])?; 26 | /// let b = Set::new(&[2, 3, 5, 7])?; 27 | /// let c = Set::new(&[4, 6, 7])?; 28 | /// 29 | /// // Return the field of Foo that will be used for comparison 30 | /// let f = |x: &Foo| x.a; 31 | /// 32 | /// // directly use the i32 for comparison 33 | /// let g = |x: &i32| *x; 34 | /// 35 | /// let op = OpBuilderByKey::from_vec(a, vec![b, c], f, g).difference(); 36 | /// let res: SetBuf = op.into_set_buf(); 37 | /// 38 | /// assert_eq!(&res[..], &[Foo{ a: 1, b: 6 }, Foo{ a: 1, b: 7 }, Foo{ a: 1, b: 8 }]); 39 | /// # Ok(()) } 40 | /// # try_main().unwrap(); 41 | /// ``` 42 | #[derive(Clone)] 43 | pub struct DifferenceByKey<'a, T: 'a, U: 'a, F, G, K> 44 | where F: Fn(&T) -> K, 45 | G: Fn(&U) -> K, 46 | K: Ord, 47 | { 48 | base: &'a [T], 49 | others: Vec<&'a [U]>, 50 | f: F, 51 | g: G, 52 | } 53 | 54 | impl<'a, T, U, F, G, K> DifferenceByKey<'a, T, U, F, G, K> 55 | where F: Fn(&T) -> K, 56 | G: Fn(&U) -> K, 57 | K: Ord, 58 | { 59 | /// Construct one with slices checked to be sorted and deduplicated. 60 | pub fn new(base: &'a Set, others: Vec<&'a Set>, f: F, g: G) -> Self { 61 | Self { 62 | base: base.as_slice(), 63 | others: vec_sets_into_slices(others), 64 | f: f, 65 | g: g, 66 | } 67 | } 68 | } 69 | 70 | impl<'a, T, U, F, G, K> DifferenceByKey<'a, T, U, F, G, K> 71 | where F: Fn(&T) -> K, 72 | G: Fn(&U) -> K, 73 | K: Ord, 74 | { 75 | fn extend_collection(mut self, output: &mut C, extend: E) -> Result<(), C::Error> 76 | where C: Collection, 77 | E: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 78 | { 79 | while let Some(first) = self.base.first().map(|x| (self.f)(x)) { 80 | let mut minimum = None; 81 | for slice in self.others.iter_mut() { 82 | *slice = exponential_offset_ge_by_key(slice, &first, &self.g); 83 | 84 | let first = match slice.first() { 85 | Some(first) => Some((self.g)(first)), 86 | None => None, 87 | }; 88 | 89 | minimum = match (minimum, first) { 90 | (Some(min), Some(first)) => Some(cmp::min(min, first)), 91 | (None, Some(first)) => Some(first), 92 | (min, _) => min, 93 | }; 94 | } 95 | 96 | match minimum { 97 | Some(min) => { 98 | if min == first { 99 | self.base = &self.base[1..]; 100 | } else { 101 | let off = self.base.iter().take_while(|&x| (self.f)(x) < min).count(); 102 | extend(output, &self.base[..off])?; 103 | 104 | self.base = &self.base[off..]; 105 | } 106 | }, 107 | None => { 108 | extend(output, self.base)?; 109 | break; 110 | }, 111 | } 112 | } 113 | Ok(()) 114 | } 115 | 116 | fn iter(&'a self) -> DifferenceByKeyIter<'a, T, U, F, G, K> 117 | { 118 | DifferenceByKeyIter { 119 | base: self.base, 120 | others: self.others.clone(), 121 | f: &self.f, 122 | g: &self.g, 123 | } 124 | } 125 | } 126 | 127 | impl<'a, T, U, F, G, K> SetOperation for DifferenceByKey<'a, T, U, F, G, K> 128 | where T: Clone, 129 | F: Fn(&T) -> K, 130 | G: Fn(&U) -> K, 131 | K: Ord, 132 | { 133 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 134 | where C: Collection, 135 | { 136 | self.extend_collection(output, Collection::extend_from_slice) 137 | } 138 | } 139 | 140 | impl<'a, T, U, F, G, K> SetOperation<&'a T> for DifferenceByKey<'a, T, U, F, G, K> 141 | where F: Fn(&T) -> K, 142 | G: Fn(&U) -> K, 143 | K: Ord, 144 | { 145 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 146 | where C: Collection<&'a T>, 147 | { 148 | self.extend_collection(output, Collection::extend) 149 | } 150 | } 151 | 152 | // This version of IntoIterator takes references to the functions (f/g). 153 | // The separate structs are required to not break the public API which takes the functions 154 | // by value instead of by reference, and doesn't require them to implement Copy/Clone. 155 | impl<'a, T, U, F, G, K> IntoIterator for &'a DifferenceByKey<'a, T, U, F, G, K> 156 | where F: Fn(&T) -> K, 157 | G: Fn(&U) -> K, 158 | K: Ord, 159 | { 160 | type Item = &'a T; 161 | type IntoIter = DifferenceByKeyIter<'a, T, U, F, G, K>; 162 | fn into_iter(self) -> Self::IntoIter { 163 | self.iter() 164 | } 165 | } 166 | 167 | pub struct DifferenceByKeyIter<'a, T, U, F, G, K> 168 | where 169 | T: 'a, 170 | U: 'a, 171 | F: Fn(&T) -> K, 172 | G: Fn(&U) -> K, 173 | K: Ord, 174 | { 175 | //slices: Vec<&'a [T]>, 176 | base: &'a [T], 177 | others: Vec<&'a [U]>, 178 | f: &'a F, 179 | g: &'a G, 180 | } 181 | 182 | impl<'a, T, U, F, G, K> Iterator for DifferenceByKeyIter<'a, T, U, F, G, K> 183 | where 184 | T: 'a, 185 | U: 'a, 186 | F: Fn(&T) -> K, 187 | G: Fn(&U) -> K, 188 | K: Ord, 189 | { 190 | type Item = &'a T; 191 | 192 | fn next(&mut self) -> Option { 193 | loop { 194 | if self.base.is_empty() { 195 | return None; 196 | } 197 | let first_base = (self.f)(&self.base[0]); 198 | let mut minimum = None; 199 | for slice in self.others.iter_mut() { 200 | *slice = exponential_offset_ge_by_key(slice, &first_base, &self.g); 201 | if !slice.is_empty() { 202 | let first_other = (self.g)(&slice[0]); 203 | match minimum { 204 | Some(min) => { 205 | minimum = Some(cmp::min(min, first_other)) 206 | }, 207 | None => { 208 | minimum = Some(first_other) 209 | } 210 | } 211 | } 212 | } 213 | 214 | match minimum { 215 | Some(min) if min == first_base => { 216 | self.base = &self.base[1..]; 217 | }, 218 | _ => { 219 | let result = &self.base[0]; 220 | self.base = &self.base[1..]; 221 | return Some(result); 222 | }, 223 | } 224 | } 225 | } 226 | } 227 | 228 | // This version of IntoIterator moves the contents of self into the iterator. 229 | // Therefore the iterator owns the functions (f/g). 230 | // The separate structs are required to not break the public API which takes the functions 231 | // by value instead of by reference, and doesn't require them to implement Copy/Clone. 232 | impl<'a, T, U, F, G, K> IntoIterator for DifferenceByKey<'a, T, U, F, G, K> 233 | where F: Fn(&T) -> K, 234 | G: Fn(&U) -> K, 235 | K: Ord, 236 | { 237 | type Item = &'a T; 238 | type IntoIter = DifferenceByKeyIterOwning<'a, T, U, F, G, K>; 239 | fn into_iter(self) -> Self::IntoIter { 240 | Self::IntoIter { 241 | base: self.base, 242 | others: self.others, 243 | f: self.f, 244 | g: self.g, 245 | } 246 | } 247 | } 248 | 249 | pub struct DifferenceByKeyIterOwning<'a, T, U, F, G, K> 250 | where 251 | T: 'a, 252 | U: 'a, 253 | F: Fn(&T) -> K, 254 | G: Fn(&U) -> K, 255 | K: Ord, 256 | { 257 | base: &'a [T], 258 | others: Vec<&'a [U]>, 259 | f: F, 260 | g: G, 261 | } 262 | 263 | impl<'a, T, U, F, G, K> Iterator for DifferenceByKeyIterOwning<'a, T, U, F, G, K> 264 | where 265 | T: 'a, 266 | U: 'a, 267 | F: Fn(&T) -> K, 268 | G: Fn(&U) -> K, 269 | K: Ord, 270 | { 271 | type Item = &'a T; 272 | 273 | fn next(&mut self) -> Option { 274 | loop { 275 | if self.base.is_empty() { 276 | return None; 277 | } 278 | let first_base = (self.f)(&self.base[0]); 279 | let mut minimum = None; 280 | for slice in self.others.iter_mut() { 281 | *slice = exponential_offset_ge_by_key(slice, &first_base, &self.g); 282 | if !slice.is_empty() { 283 | let first_other = (self.g)(&slice[0]); 284 | match minimum { 285 | Some(min) => { 286 | minimum = Some(cmp::min(min, first_other)) 287 | }, 288 | None => { 289 | minimum = Some(first_other) 290 | } 291 | } 292 | } 293 | } 294 | 295 | match minimum { 296 | Some(min) if min == first_base => { 297 | self.base = &self.base[1..]; 298 | }, 299 | _ => { 300 | let result = &self.base[0]; 301 | self.base = &self.base[1..]; 302 | return Some(result); 303 | }, 304 | } 305 | } 306 | } 307 | } 308 | 309 | #[cfg(test)] 310 | mod tests { 311 | mod set_to_set { 312 | use super::super::*; 313 | use crate::set::{sort_dedup_vec, SetBuf}; 314 | 315 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 316 | struct Foo { 317 | a: i32, 318 | b: i8, 319 | } 320 | 321 | impl Foo { 322 | fn new(a: i32) -> Foo { 323 | Foo { a, b: 0 } 324 | } 325 | } 326 | 327 | #[test] 328 | fn one_empty_slice() { 329 | let a: &[Foo] = &[]; 330 | 331 | let op = DifferenceByKey { base: a, others: vec![], f: |x| x.a, g: |&x| x }; 332 | let res: SetBuf = op.into_set_buf(); 333 | assert_eq!(&res[..], &[]); 334 | } 335 | 336 | #[test] 337 | fn one_slice() { 338 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 339 | 340 | let op = DifferenceByKey { base: a, others: vec![], f: |x| x.a, g: |&x| x }; 341 | let res: SetBuf = op.into_set_buf(); 342 | assert_eq!(&res[..], &[Foo::new(1), Foo::new(2), Foo::new(3)]); 343 | } 344 | 345 | #[test] 346 | fn two_slices() { 347 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 348 | let b = &[2, 4]; 349 | 350 | let op = DifferenceByKey { base: a, others: vec![b], f: |x| x.a, g: |&x| x }; 351 | let res: SetBuf = op.into_set_buf(); 352 | assert_eq!(&res[..], &[Foo::new(1), Foo::new(3)]); 353 | } 354 | 355 | #[test] 356 | fn two_slices_special_case() { 357 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 358 | let b = &[3]; 359 | 360 | let op = DifferenceByKey { base: a, others: vec![b], f: |x| x.a, g: |&x| x }; 361 | let res: SetBuf = op.into_set_buf(); 362 | assert_eq!(&res[..], &[Foo::new(1), Foo::new(2)]); 363 | } 364 | 365 | #[test] 366 | fn three_slices() { 367 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3), Foo::new(6), Foo::new(7)]; 368 | let b = &[2, 3, 4]; 369 | let c = &[3, 4, 5, 7]; 370 | 371 | let op = DifferenceByKey { base: a, others: vec![b, c], f: |x| x.a, g: |&x| x }; 372 | let res: SetBuf = op.into_set_buf(); 373 | assert_eq!(&res[..], &[Foo::new(1), Foo::new(6)]); 374 | } 375 | 376 | quickcheck! { 377 | fn qc_difference(base: Vec, xss: Vec>) -> bool { 378 | use std::collections::BTreeSet; 379 | use std::iter::FromIterator; 380 | 381 | let mut base = base; 382 | let mut xss = xss; 383 | 384 | sort_dedup_vec(&mut base); 385 | 386 | for xs in &mut xss { 387 | sort_dedup_vec(xs); 388 | } 389 | 390 | let x: SetBuf = { 391 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 392 | DifferenceByKey { base: &base, others: xss, f: |&x| x, g: |&x| x as i32 }.into_set_buf() 393 | }; 394 | 395 | let mut y = BTreeSet::from_iter(base); 396 | 397 | for v in xss { 398 | let x = BTreeSet::from_iter(v.into_iter().map(|x| x as i32)); 399 | y = y.difference(&x).cloned().collect(); 400 | } 401 | let y: Vec<_> = y.into_iter().collect(); 402 | 403 | x.as_slice() == y.as_slice() 404 | } 405 | } 406 | } 407 | 408 | mod set_to_iter { 409 | use super::super::*; 410 | use crate::set::sort_dedup_vec; 411 | 412 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 413 | struct Foo { 414 | a: i32, 415 | b: i8, 416 | } 417 | 418 | impl Foo { 419 | fn new(a: i32) -> Foo { 420 | Foo { a, b: 0 } 421 | } 422 | } 423 | 424 | #[test] 425 | fn one_empty_slice() { 426 | let a: &[Foo] = &[]; 427 | 428 | let difference = DifferenceByKey { base: a, others: vec![], f: |x| x.a, g: |&x| x }; 429 | let diff_ref: Vec = difference.iter().cloned().collect(); 430 | assert_eq!(&diff_ref[..], &[]); 431 | let diff_own: Vec = difference.into_iter().cloned().collect(); 432 | assert_eq!(&diff_own[..], &[]); 433 | } 434 | 435 | #[test] 436 | fn one_slice() { 437 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 438 | 439 | let difference = DifferenceByKey { base: a, others: vec![], f: |x| x.a, g: |&x| x }; 440 | let diff_ref: Vec = difference.iter().cloned().collect(); 441 | assert_eq!(&diff_ref[..], &[Foo::new(1), Foo::new(2), Foo::new(3)]); 442 | let diff_own: Vec = difference.into_iter().cloned().collect(); 443 | assert_eq!(&diff_own[..], &[Foo::new(1), Foo::new(2), Foo::new(3)]); 444 | } 445 | 446 | #[test] 447 | fn two_slices() { 448 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 449 | let b = &[2, 4]; 450 | 451 | let difference = DifferenceByKey { base: a, others: vec![b], f: |x| x.a, g: |&x| x }; 452 | let diff_ref: Vec = difference.iter().cloned().collect(); 453 | assert_eq!(&diff_ref[..], &[Foo::new(1), Foo::new(3)]); 454 | let diff_own: Vec = difference.into_iter().cloned().collect(); 455 | assert_eq!(&diff_own[..], &[Foo::new(1), Foo::new(3)]); 456 | } 457 | 458 | #[test] 459 | fn two_slices_special_case() { 460 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3)]; 461 | let b = &[3]; 462 | 463 | let difference = DifferenceByKey { base: a, others: vec![b], f: |x| x.a, g: |&x| x }; 464 | let diff_ref: Vec = difference.iter().cloned().collect(); 465 | assert_eq!(&diff_ref[..], &[Foo::new(1), Foo::new(2)]); 466 | let diff_own: Vec = difference.into_iter().cloned().collect(); 467 | assert_eq!(&diff_own[..], &[Foo::new(1), Foo::new(2)]); 468 | } 469 | 470 | #[test] 471 | fn three_slices() { 472 | let a = &[Foo::new(1), Foo::new(2), Foo::new(3), Foo::new(6), Foo::new(7)]; 473 | let b = &[2, 3, 4]; 474 | let c = &[3, 4, 5, 7]; 475 | 476 | let difference = DifferenceByKey { base: a, others: vec![b, c], f: |x| x.a, g: |&x| x }; 477 | let diff_ref: Vec = difference.iter().cloned().collect(); 478 | assert_eq!(&diff_ref[..], &[Foo::new(1), Foo::new(6)]); 479 | let diff_own: Vec = difference.into_iter().cloned().collect(); 480 | assert_eq!(&diff_own[..], &[Foo::new(1), Foo::new(6)]); 481 | } 482 | 483 | quickcheck! { 484 | fn qc_difference(base: Vec, xss: Vec>) -> bool { 485 | use std::collections::BTreeSet; 486 | use std::iter::FromIterator; 487 | 488 | let mut base = base; 489 | let mut xss = xss; 490 | 491 | sort_dedup_vec(&mut base); 492 | 493 | for xs in &mut xss { 494 | sort_dedup_vec(xs); 495 | } 496 | 497 | let x: Vec = { 498 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 499 | DifferenceByKey { base: &base, others: xss, f: |&x| x, g: |&x| x as i32 }.into_iter().cloned().collect() 500 | }; 501 | 502 | let mut y = BTreeSet::from_iter(base); 503 | 504 | for v in xss { 505 | let x = BTreeSet::from_iter(v.into_iter().map(|x| x as i32)); 506 | y = y.difference(&x).cloned().collect(); 507 | } 508 | let y: Vec<_> = y.into_iter().collect(); 509 | 510 | x.as_slice() == y.as_slice() 511 | } 512 | } 513 | } 514 | } 515 | 516 | #[cfg(all(feature = "unstable", test))] 517 | mod bench { 518 | extern crate test; 519 | use super::*; 520 | use self::test::Bencher; 521 | use crate::set::SetBuf; 522 | 523 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 524 | struct Foo { 525 | a: i32, 526 | b: i8, 527 | } 528 | 529 | impl Foo { 530 | fn new(a: i32) -> Foo { 531 | Foo { a, b: 0 } 532 | } 533 | } 534 | 535 | #[bench] 536 | fn two_slices_big(bench: &mut Bencher) { 537 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 538 | let b: Vec<_> = (1..101).collect(); 539 | 540 | bench.iter(|| { 541 | let op = DifferenceByKey { base: &a, others: vec![&b], f: |x| x.a, g: |&x| x }; 542 | let res: SetBuf = op.into_set_buf(); 543 | test::black_box(|| res); 544 | }); 545 | } 546 | 547 | #[bench] 548 | fn two_slices_big2(bench: &mut Bencher) { 549 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 550 | let b: Vec<_> = (51..151).collect(); 551 | 552 | bench.iter(|| { 553 | let op = DifferenceByKey { base: &a, others: vec![&b], f: |x| x.a, g: |&x| x }; 554 | let res: SetBuf = op.into_set_buf(); 555 | test::black_box(|| res); 556 | }); 557 | } 558 | 559 | #[bench] 560 | fn two_slices_big3(bench: &mut Bencher) { 561 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 562 | let b: Vec<_> = (100..200).collect(); 563 | 564 | bench.iter(|| { 565 | let op = DifferenceByKey { base: &a, others: vec![&b], f: |x| x.a, g: |&x| x }; 566 | let res: SetBuf = op.into_set_buf(); 567 | test::black_box(|| res); 568 | }); 569 | } 570 | 571 | #[bench] 572 | fn three_slices_big(bench: &mut Bencher) { 573 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 574 | let b: Vec<_> = (1..101).collect(); 575 | let c: Vec<_> = (2..102).collect(); 576 | 577 | bench.iter(|| { 578 | let op = DifferenceByKey { base: &a, others: vec![&b, &c], f: |x| x.a, g: |&x| x }; 579 | let res: SetBuf = op.into_set_buf(); 580 | test::black_box(|| res); 581 | }); 582 | } 583 | 584 | #[bench] 585 | fn three_slices_big2(bench: &mut Bencher) { 586 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 587 | let b: Vec<_> = (34..134).collect(); 588 | let c: Vec<_> = (66..167).collect(); 589 | 590 | bench.iter(|| { 591 | let op = DifferenceByKey { base: &a, others: vec![&b, &c], f: |x| x.a, g: |&x| x }; 592 | let res: SetBuf = op.into_set_buf(); 593 | test::black_box(|| res); 594 | }); 595 | } 596 | 597 | #[bench] 598 | fn three_slices_big3(bench: &mut Bencher) { 599 | let a: Vec<_> = (0..100).map(Foo::new).collect(); 600 | let b: Vec<_> = (100..200).collect(); 601 | let c: Vec<_> = (200..300).collect(); 602 | 603 | bench.iter(|| { 604 | let op = DifferenceByKey { base: &a, others: vec![&b, &c], f: |x| x.a, g: |&x| x }; 605 | let res: SetBuf = op.into_set_buf(); 606 | test::black_box(|| res); 607 | }); 608 | } 609 | } 610 | -------------------------------------------------------------------------------- /src/multi/intersection.rs: -------------------------------------------------------------------------------- 1 | use crate::set::{Set, vec_sets_into_slices}; 2 | use crate::{SetOperation, Collection, exponential_offset_ge}; 3 | 4 | use self::Equality::*; 5 | 6 | /// Represent the _intersection_ set operation that will be applied to the slices. 7 | /// 8 | /// Note that the intersection is all the elements that are in all the slices at the same time. 9 | /// 10 | /// # Examples 11 | /// ``` 12 | /// # use sdset::Error; 13 | /// # fn try_main() -> Result<(), Error> { 14 | /// use sdset::multi::OpBuilder; 15 | /// use sdset::{SetOperation, Set, SetBuf}; 16 | /// 17 | /// let a = Set::new(&[1, 2, 4])?; 18 | /// let b = Set::new(&[2, 3, 4, 5, 7])?; 19 | /// let c = Set::new(&[2, 4, 6, 7])?; 20 | /// 21 | /// let op = OpBuilder::from_vec(vec![a, b, c]).intersection(); 22 | /// 23 | /// let res: SetBuf = op.into_set_buf(); 24 | /// assert_eq!(&res[..], &[2, 4]); 25 | /// # Ok(()) } 26 | /// # try_main().unwrap(); 27 | /// ``` 28 | #[derive(Clone)] 29 | pub struct Intersection<'a, T: 'a> { 30 | slices: Vec<&'a [T]>, 31 | } 32 | 33 | impl<'a, T> Intersection<'a, T> { 34 | /// Construct one with slices checked to be sorted and deduplicated. 35 | pub fn new(slices: Vec<&'a Set>) -> Self { 36 | Self { 37 | slices: vec_sets_into_slices(slices), 38 | } 39 | } 40 | } 41 | 42 | enum Equality<'a, T: 'a> { 43 | NotEqual(&'a T), 44 | Equal(&'a T), 45 | } 46 | 47 | /// precondition: slices may not be empty && slices[i] may not be empty 48 | #[inline] 49 | fn test_equality<'a, T: Ord>(slices: &[&'a [T]]) -> Equality<'a, T> { 50 | let mut is_equal: usize = 1; // LLVM produced wasted instruction when this was bool 51 | let mut max = &slices[0][0]; 52 | for s in slices { 53 | let x = &s[0]; 54 | if x != max { 55 | is_equal = 0; 56 | } 57 | if x > max { 58 | max = x; 59 | } 60 | } 61 | if is_equal != 0 { Equal(max) } else { NotEqual(max) } 62 | } 63 | 64 | impl<'a, T: Ord> Intersection<'a, T> { 65 | #[inline] 66 | fn extend_collection(mut self, output: &mut C, push: F) -> Result<(), C::Error> 67 | where C: Collection, 68 | F: Fn(&mut C, &'a T) -> Result<(), C::Error>, 69 | { 70 | if self.slices.is_empty() { return Ok(()) } 71 | if self.slices.iter().any(|s| s.is_empty()) { return Ok(()) } 72 | 73 | loop { 74 | match test_equality(&self.slices) { 75 | Equal(x) => { 76 | push(output, x)?; 77 | for slice in &mut self.slices { 78 | *slice = &slice[1..]; 79 | if slice.is_empty() { return Ok(()) } 80 | } 81 | }, 82 | NotEqual(max) => { 83 | for slice in &mut self.slices { 84 | *slice = exponential_offset_ge(slice, max); 85 | if slice.is_empty() { return Ok(()) } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | fn iter(&self) -> IntersectionIter<'a, T> 93 | { 94 | IntersectionIter { 95 | slices: self.slices.clone(), 96 | } 97 | } 98 | } 99 | 100 | impl<'a, T: Ord + Clone> SetOperation for Intersection<'a, T> { 101 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 102 | where C: Collection, 103 | { 104 | self.extend_collection(output, |v, x| v.push(x.clone())) 105 | } 106 | } 107 | 108 | impl<'a, T: Ord> SetOperation<&'a T> for Intersection<'a, T> { 109 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 110 | where C: Collection<&'a T>, 111 | { 112 | self.extend_collection(output, Collection::push) 113 | } 114 | } 115 | 116 | impl<'a, T: Ord> IntoIterator for Intersection<'a, T> { 117 | type Item = &'a T; 118 | type IntoIter = IntersectionIter<'a, T>; 119 | fn into_iter(self) -> Self::IntoIter { 120 | IntersectionIter { 121 | slices: self.slices, 122 | } 123 | } 124 | } 125 | 126 | impl<'a, T: Ord> IntoIterator for &'a Intersection<'a, T> { 127 | type Item = &'a T; 128 | type IntoIter = IntersectionIter<'a, T>; 129 | fn into_iter(self) -> Self::IntoIter { 130 | self.iter() 131 | } 132 | } 133 | 134 | pub struct IntersectionIter<'a, T> { 135 | slices: Vec<&'a [T]>, 136 | } 137 | 138 | impl<'a, T: Ord> Iterator for IntersectionIter<'a, T> { 139 | type Item = &'a T; 140 | 141 | fn next(&mut self) -> Option { 142 | if self.slices.is_empty() { return None; } 143 | 144 | loop { 145 | if self.slices.iter().any(|s| s.is_empty()) { return None; } 146 | match test_equality(&self.slices) { 147 | Equal(x) => { 148 | for slice in &mut self.slices { 149 | *slice = &slice[1..]; 150 | } 151 | return Some(x); 152 | }, 153 | NotEqual(max) => { 154 | for slice in &mut self.slices { 155 | *slice = exponential_offset_ge(slice, max); 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | #[cfg(test)] 164 | mod tests { 165 | mod set_to_set { 166 | use super::super::*; 167 | use crate::set::{sort_dedup_vec, SetBuf}; 168 | 169 | #[test] 170 | fn no_slice() { 171 | let intersection_: SetBuf = Intersection { slices: vec![] }.into_set_buf(); 172 | assert_eq!(&intersection_[..], &[]); 173 | } 174 | 175 | #[test] 176 | fn one_empty_slice() { 177 | let a: &[i32] = &[]; 178 | 179 | let intersection_: SetBuf = Intersection { slices: vec![a] }.into_set_buf(); 180 | assert_eq!(&intersection_[..], &[]); 181 | } 182 | 183 | #[test] 184 | fn one_slice() { 185 | let a = &[1, 2, 3]; 186 | 187 | let intersection_: SetBuf = Intersection { slices: vec![a] }.into_set_buf(); 188 | assert_eq!(&intersection_[..], &[1, 2, 3]); 189 | } 190 | 191 | #[test] 192 | fn two_slices() { 193 | let a = &[1, 2, 3]; 194 | let b = &[2, 3, 4]; 195 | 196 | let intersection_: SetBuf = Intersection { slices: vec![a, b] }.into_set_buf(); 197 | assert_eq!(&intersection_[..], &[2, 3]); 198 | } 199 | 200 | #[test] 201 | fn three_slices() { 202 | let a = &[1, 2, 3]; 203 | let b = &[2, 3, 4]; 204 | let c = &[3, 4, 5]; 205 | 206 | let intersection_: SetBuf = Intersection { slices: vec![a, b, c] }.into_set_buf(); 207 | assert_eq!(&intersection_[..], &[3]); 208 | } 209 | 210 | quickcheck! { 211 | fn qc_intersection(xss: Vec>) -> bool { 212 | use std::collections::BTreeSet; 213 | use std::iter::FromIterator; 214 | 215 | // FIXME temporary hack (can have mutable parameters!) 216 | let mut xss = xss; 217 | 218 | for xs in &mut xss { 219 | sort_dedup_vec(xs); 220 | } 221 | 222 | let x: SetBuf = { 223 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 224 | Intersection { slices: xss }.into_set_buf() 225 | }; 226 | 227 | let mut xss = xss.into_iter(); 228 | let mut y = match xss.next() { 229 | Some(xs) => BTreeSet::from_iter(xs), 230 | None => BTreeSet::new(), 231 | }; 232 | 233 | for v in xss { 234 | let x = BTreeSet::from_iter(v.iter().cloned()); 235 | y = y.intersection(&x).cloned().collect(); 236 | } 237 | let y: Vec<_> = y.into_iter().collect(); 238 | 239 | x.as_slice() == y.as_slice() 240 | } 241 | } 242 | } 243 | 244 | mod set_to_iter { 245 | use super::super::*; 246 | use crate::set::sort_dedup_vec; 247 | 248 | #[test] 249 | fn no_slice() { 250 | let intersection = Intersection { slices: vec![] }; 251 | let inter_ref: Vec = intersection.iter().cloned().collect(); 252 | assert_eq!(&inter_ref[..], &[]); 253 | let inter_own: Vec = intersection.into_iter().cloned().collect(); 254 | assert_eq!(&inter_own[..], &[]); 255 | } 256 | 257 | #[test] 258 | fn one_empty_slice() { 259 | let a: &[i32] = &[]; 260 | 261 | let intersection = Intersection { slices: vec![a] }; 262 | let inter_ref: Vec = intersection.iter().cloned().collect(); 263 | assert_eq!(&inter_ref[..], &[]); 264 | let inter_own: Vec = intersection.into_iter().cloned().collect(); 265 | assert_eq!(&inter_own[..], &[]); 266 | } 267 | 268 | #[test] 269 | fn one_slice() { 270 | let a = &[1, 2, 3]; 271 | 272 | let intersection = Intersection { slices: vec![a] }; 273 | let inter_ref: Vec = intersection.iter().cloned().collect(); 274 | assert_eq!(&inter_ref[..], &[1, 2, 3]); 275 | let inter_own: Vec = intersection.into_iter().cloned().collect(); 276 | assert_eq!(&inter_own[..], &[1, 2, 3]); 277 | } 278 | 279 | #[test] 280 | fn two_slices() { 281 | let a = &[1, 2, 3]; 282 | let b = &[2, 3, 4]; 283 | 284 | let intersection = Intersection { slices: vec![a, b] }; 285 | let inter_ref: Vec = intersection.iter().cloned().collect(); 286 | assert_eq!(&inter_ref[..], &[2, 3]); 287 | let inter_own: Vec = intersection.into_iter().cloned().collect(); 288 | assert_eq!(&inter_own[..], &[2, 3]); 289 | } 290 | 291 | #[test] 292 | fn three_slices() { 293 | let a = &[1, 2, 3]; 294 | let b = &[2, 3, 4]; 295 | let c = &[3, 4, 5]; 296 | 297 | let intersection = Intersection { slices: vec![a, b, c] }; 298 | let inter_ref: Vec = intersection.iter().cloned().collect(); 299 | assert_eq!(&inter_ref[..], &[3]); 300 | let inter_own: Vec = intersection.into_iter().cloned().collect(); 301 | assert_eq!(&inter_own[..], &[3]); 302 | } 303 | 304 | quickcheck! { 305 | fn qc_intersection(xss: Vec>) -> bool { 306 | use std::collections::BTreeSet; 307 | use std::iter::FromIterator; 308 | 309 | // FIXME temporary hack (can have mutable parameters!) 310 | let mut xss = xss; 311 | 312 | for xs in &mut xss { 313 | sort_dedup_vec(xs); 314 | } 315 | 316 | let x: Vec = { 317 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 318 | Intersection { slices: xss }.into_iter().cloned().collect() 319 | }; 320 | 321 | let mut xss = xss.into_iter(); 322 | let mut y = match xss.next() { 323 | Some(xs) => BTreeSet::from_iter(xs), 324 | None => BTreeSet::new(), 325 | }; 326 | 327 | for v in xss { 328 | let x = BTreeSet::from_iter(v.iter().cloned()); 329 | y = y.intersection(&x).cloned().collect(); 330 | } 331 | let y: Vec<_> = y.into_iter().collect(); 332 | 333 | x.as_slice() == y.as_slice() 334 | } 335 | } 336 | } 337 | } 338 | 339 | #[cfg(all(feature = "unstable", test))] 340 | mod bench { 341 | extern crate test; 342 | use super::*; 343 | use self::test::Bencher; 344 | use crate::set::SetBuf; 345 | 346 | #[bench] 347 | fn two_slices_big(bench: &mut Bencher) { 348 | let a: Vec<_> = (0..100).collect(); 349 | let b: Vec<_> = (1..101).collect(); 350 | 351 | bench.iter(|| { 352 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b] }.into_set_buf(); 353 | test::black_box(|| intersection_); 354 | }); 355 | } 356 | 357 | #[bench] 358 | fn two_slices_big2(bench: &mut Bencher) { 359 | let a: Vec<_> = (0..100).collect(); 360 | let b: Vec<_> = (51..151).collect(); 361 | 362 | bench.iter(|| { 363 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b] }.into_set_buf(); 364 | test::black_box(|| intersection_); 365 | }); 366 | } 367 | 368 | #[bench] 369 | fn two_slices_big3(bench: &mut Bencher) { 370 | let a: Vec<_> = (0..100).collect(); 371 | let b: Vec<_> = (100..200).collect(); 372 | 373 | bench.iter(|| { 374 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b] }.into_set_buf(); 375 | test::black_box(|| intersection_); 376 | }); 377 | } 378 | 379 | #[bench] 380 | fn three_slices_big(bench: &mut Bencher) { 381 | let a: Vec<_> = (0..100).collect(); 382 | let b: Vec<_> = (1..101).collect(); 383 | let c: Vec<_> = (2..102).collect(); 384 | 385 | bench.iter(|| { 386 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b, &c] }.into_set_buf(); 387 | test::black_box(|| intersection_); 388 | }); 389 | } 390 | 391 | #[bench] 392 | fn three_slices_big2(bench: &mut Bencher) { 393 | let a: Vec<_> = (0..100).collect(); 394 | let b: Vec<_> = (34..134).collect(); 395 | let c: Vec<_> = (66..167).collect(); 396 | 397 | bench.iter(|| { 398 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b, &c] }.into_set_buf(); 399 | test::black_box(|| intersection_); 400 | }); 401 | } 402 | 403 | #[bench] 404 | fn three_slices_big3(bench: &mut Bencher) { 405 | let a: Vec<_> = (0..100).collect(); 406 | let b: Vec<_> = (100..200).collect(); 407 | let c: Vec<_> = (200..300).collect(); 408 | 409 | bench.iter(|| { 410 | let intersection_: SetBuf = Intersection { slices: vec![&a, &b, &c] }.into_set_buf(); 411 | test::black_box(|| intersection_); 412 | }); 413 | } 414 | } 415 | -------------------------------------------------------------------------------- /src/multi/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains the types to make set operations on any given number of slices. 2 | //! 3 | //! # Examples 4 | //! ``` 5 | //! # use sdset::Error; 6 | //! # fn try_main() -> Result<(), Error> { 7 | //! use sdset::multi::OpBuilder; 8 | //! use sdset::{SetOperation, Set, SetBuf}; 9 | //! 10 | //! let a = Set::new(&[1, 2, 4])?; 11 | //! let b = Set::new(&[2, 3, 5, 7])?; 12 | //! let c = Set::new(&[4, 6, 7])?; 13 | //! 14 | //! let op = OpBuilder::from_vec(vec![a, b, c]).union(); 15 | //! 16 | //! let res: SetBuf = op.into_set_buf(); 17 | //! assert_eq!(&res[..], &[1, 2, 3, 4, 5, 6, 7]); 18 | //! # Ok(()) } 19 | //! # try_main().unwrap(); 20 | //! ``` 21 | 22 | use crate::set::Set; 23 | 24 | mod union; 25 | mod intersection; 26 | mod difference; 27 | mod difference_by_key; 28 | mod symmetric_difference; 29 | 30 | pub use self::union::Union; 31 | pub use self::intersection::Intersection; 32 | pub use self::difference::Difference; 33 | pub use self::difference_by_key::DifferenceByKey; 34 | pub use self::symmetric_difference::SymmetricDifference; 35 | 36 | /// Type used to acquire any number of slices 37 | /// and make a set operation on these slices. 38 | #[derive(Clone)] 39 | pub struct OpBuilder<'a, T: 'a> { 40 | slices: Vec<&'a Set>, 41 | } 42 | 43 | impl<'a, T> OpBuilder<'a, T> { 44 | /// Construct an empty one. 45 | pub fn new() -> Self { 46 | Self { slices: Vec::new() } 47 | } 48 | 49 | /// Construct an empty one with enough space for `capacity` elements or more. 50 | pub fn with_capacity(capacity: usize) -> Self { 51 | Self { slices: Vec::with_capacity(capacity) } 52 | } 53 | 54 | /// Construct it with the content of the given slice. 55 | /// 56 | /// Note that no other allocation than the one of the vec given 57 | /// in parameter is needed for the construction. 58 | pub fn from_vec(slices: Vec<&'a Set>) -> Self { 59 | Self { slices } 60 | } 61 | 62 | /// Reserve additional space for the underlying vec. 63 | pub fn reserve(&mut self, additional: usize) { 64 | self.slices.reserve(additional); 65 | } 66 | 67 | /// Add a new set that will be used for the future set operation 68 | /// and consume and return the type. 69 | pub fn add(mut self, set: &'a Set) -> Self { 70 | self.push(set); 71 | self 72 | } 73 | 74 | /// Push a new set that will be used for the future set operation. 75 | pub fn push(&mut self, set: &'a Set) { 76 | self.slices.push(set); 77 | } 78 | 79 | /// Prepare the slices for the _union_ set operation. 80 | pub fn union(self) -> Union<'a, T> { 81 | Union::new(self.slices) 82 | } 83 | 84 | /// Prepare the slices for the _intersection_ set operation. 85 | pub fn intersection(self) -> Intersection<'a, T> { 86 | Intersection::new(self.slices) 87 | } 88 | 89 | /// Prepare the slices for the _difference_ set operation. 90 | pub fn difference(self) -> Difference<'a, T> { 91 | Difference::new(self.slices) 92 | } 93 | 94 | /// Prepare the slices for the _symmetric difference_ set operation. 95 | pub fn symmetric_difference(self) -> SymmetricDifference<'a, T> { 96 | SymmetricDifference::new(self.slices) 97 | } 98 | } 99 | 100 | /// Type used to make a set operation on two slices of different types. 101 | /// 102 | /// The two functions are used to generate a key that will be used to 103 | /// make the set operation and correlate the two slices values. 104 | #[derive(Clone)] 105 | pub struct OpBuilderByKey<'a, T: 'a, U: 'a, F, G, K> 106 | where F: Fn(&T) -> K, 107 | G: Fn(&U) -> K, 108 | K: Ord, 109 | { 110 | base: &'a Set, 111 | others: Vec<&'a Set>, 112 | f: F, 113 | g: G, 114 | } 115 | 116 | impl<'a, T, U, F, G, K> OpBuilderByKey<'a, T, U, F, G, K> 117 | where F: Fn(&T) -> K, 118 | G: Fn(&U) -> K, 119 | K: Ord, 120 | { 121 | /// Construct a type with two slices. 122 | pub fn new(base: &'a Set, f: F, g: G) -> Self { 123 | Self { base, others: Vec::new(), f, g } 124 | } 125 | 126 | /// Construct it with the content of the given slice. 127 | /// 128 | /// Note that no other allocation than the one of the vec given 129 | /// in parameter is needed for the construction. 130 | pub fn from_vec(base: &'a Set, others: Vec<&'a Set>, f: F, g: G) -> Self { 131 | Self { base, others, f, g } 132 | } 133 | 134 | /// Push a new set that will be used for the future set operation. 135 | pub fn push(&mut self, set: &'a Set) { 136 | self.others.push(set); 137 | } 138 | 139 | /// Add a new set that will be used for the future set operation 140 | /// and consume and return the type. 141 | pub fn add(mut self, set: &'a Set) -> Self { 142 | self.push(set); 143 | self 144 | } 145 | 146 | /// Prepare the two slices for the _difference_ set operation. 147 | pub fn difference(self) -> DifferenceByKey<'a, T, U, F, G, K> { 148 | DifferenceByKey::new(self.base, self.others, self.f, self.g) 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/multi/symmetric_difference.rs: -------------------------------------------------------------------------------- 1 | use crate::set::{Set, vec_sets_into_slices}; 2 | use crate::two_minimums::{two_minimums, Minimums::*}; 3 | use crate::{SetOperation, Collection}; 4 | 5 | /// Represent the _symmetric difference_ set operation that will be applied to the slices. 6 | /// 7 | /// # Examples 8 | /// ``` 9 | /// # use sdset::Error; 10 | /// # fn try_main() -> Result<(), Error> { 11 | /// use sdset::multi::OpBuilder; 12 | /// use sdset::{SetOperation, Set, SetBuf}; 13 | /// 14 | /// let a = Set::new(&[1, 2, 4])?; 15 | /// let b = Set::new(&[2, 3, 5, 7])?; 16 | /// let c = Set::new(&[4, 6, 7])?; 17 | /// 18 | /// let op = OpBuilder::from_vec(vec![a, b, c]).symmetric_difference(); 19 | /// 20 | /// let res: SetBuf = op.into_set_buf(); 21 | /// assert_eq!(&res[..], &[1, 3, 5, 6]); 22 | /// # Ok(()) } 23 | /// # try_main().unwrap(); 24 | /// ``` 25 | #[derive(Clone)] 26 | pub struct SymmetricDifference<'a, T: 'a> { 27 | slices: Vec<&'a [T]>, 28 | } 29 | 30 | impl<'a, T> SymmetricDifference<'a, T> { 31 | /// Construct one with slices checked to be sorted and deduplicated. 32 | pub fn new(slices: Vec<&'a Set>) -> Self { 33 | Self { 34 | slices: vec_sets_into_slices(slices), 35 | } 36 | } 37 | } 38 | 39 | impl<'a, T: Ord> SymmetricDifference<'a, T> { 40 | #[inline] 41 | fn extend_collection(mut self, output: &mut C, extend: F, push: G) -> Result<(), C::Error> 42 | where C: Collection, 43 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 44 | G: Fn(&mut C, &'a T) -> Result<(), C::Error>, 45 | { 46 | loop { 47 | match two_minimums(&self.slices) { 48 | Two((i, f), (_, s)) => { 49 | if f != s { 50 | let off = self.slices[i].iter().take_while(|&e| e < s).count(); 51 | extend(output, &self.slices[i][..off])?; 52 | self.slices[i] = &self.slices[i][off..]; 53 | } 54 | else { 55 | let mut count = 0; 56 | for slice in self.slices.iter_mut() { 57 | if slice.first() == Some(f) { 58 | count += 1; 59 | *slice = &slice[1..]; 60 | } 61 | } 62 | // if count is odd 63 | if count % 2 != 0 { 64 | push(output, f)?; 65 | } 66 | } 67 | }, 68 | One((i, _)) => { 69 | extend(output, self.slices[i])?; 70 | break; 71 | }, 72 | Nothing => break, 73 | } 74 | } 75 | Ok(()) 76 | } 77 | 78 | fn iter(&self) -> SymmetricDifferenceIter<'a, T> 79 | { 80 | SymmetricDifferenceIter { 81 | slices: self.slices.clone(), 82 | } 83 | } 84 | } 85 | 86 | impl<'a, T: Ord + Clone> SetOperation for SymmetricDifference<'a, T> { 87 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 88 | where C: Collection, 89 | { 90 | self.extend_collection(output, Collection::extend_from_slice, |v, x| v.push(x.clone())) 91 | } 92 | } 93 | 94 | impl<'a, T: Ord> SetOperation<&'a T> for SymmetricDifference<'a, T> { 95 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 96 | where C: Collection<&'a T>, 97 | { 98 | self.extend_collection(output, Collection::extend, Collection::push) 99 | } 100 | } 101 | 102 | impl<'a, T: Ord> IntoIterator for SymmetricDifference<'a, T> { 103 | type Item = &'a T; 104 | type IntoIter = SymmetricDifferenceIter<'a, T>; 105 | fn into_iter(self) -> Self::IntoIter { 106 | SymmetricDifferenceIter { 107 | slices: self.slices, 108 | } 109 | } 110 | } 111 | 112 | impl<'a, T: Ord> IntoIterator for &'a SymmetricDifference<'a, T> { 113 | type Item = &'a T; 114 | type IntoIter = SymmetricDifferenceIter<'a, T>; 115 | fn into_iter(self) -> Self::IntoIter { 116 | self.iter() 117 | } 118 | } 119 | 120 | pub struct SymmetricDifferenceIter<'a, T> { 121 | slices: Vec<&'a [T]>, 122 | } 123 | 124 | impl<'a, T: Ord> Iterator for SymmetricDifferenceIter<'a, T> { 125 | type Item = &'a T; 126 | 127 | fn next(&mut self) -> Option { 128 | loop { 129 | match two_minimums(&self.slices) { 130 | Two((i, f), (_, s)) => { 131 | if f != s { 132 | let result = &self.slices[i][0]; 133 | self.slices[i] = &self.slices[i][1..]; 134 | return Some(result); 135 | } else { 136 | let mut count = 0; 137 | for slice in self.slices.iter_mut() { 138 | if slice.first() == Some(f) { 139 | count += 1; 140 | *slice = &slice[1..]; 141 | } 142 | } 143 | // if count is odd 144 | if count % 2 != 0 { 145 | return Some(f); 146 | } 147 | } 148 | }, 149 | One((i, _)) => { 150 | let result = &self.slices[i][0]; 151 | self.slices[i] = &self.slices[i][1..]; 152 | return Some(result); 153 | }, 154 | Nothing => { return None; }, 155 | } 156 | } 157 | } 158 | } 159 | 160 | #[cfg(test)] 161 | mod tests { 162 | mod set_to_set { 163 | use super::super::*; 164 | use crate::set::{sort_dedup_vec, SetBuf}; 165 | 166 | quickcheck! { 167 | fn qc_symmetric_difference(xss: Vec>) -> bool { 168 | use std::collections::BTreeSet; 169 | use std::iter::FromIterator; 170 | 171 | // FIXME temporary hack (can have mutable parameters!) 172 | let mut xss = xss; 173 | 174 | for xs in &mut xss { 175 | sort_dedup_vec(xs); 176 | } 177 | 178 | let x: SetBuf = { 179 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 180 | SymmetricDifference { slices: xss }.into_set_buf() 181 | }; 182 | 183 | let mut y = BTreeSet::new(); 184 | for v in xss { 185 | let x = BTreeSet::from_iter(v.iter().cloned()); 186 | y = y.symmetric_difference(&x).cloned().collect(); 187 | } 188 | let y: Vec<_> = y.into_iter().collect(); 189 | 190 | x.as_slice() == y.as_slice() 191 | } 192 | } 193 | } 194 | 195 | mod set_to_iter { 196 | use super::super::*; 197 | use crate::set::sort_dedup_vec; 198 | 199 | quickcheck! { 200 | fn qc_symmetric_difference(xss: Vec>) -> bool { 201 | use std::collections::BTreeSet; 202 | use std::iter::FromIterator; 203 | 204 | // FIXME temporary hack (can have mutable parameters!) 205 | let mut xss = xss; 206 | 207 | for xs in &mut xss { 208 | sort_dedup_vec(xs); 209 | } 210 | 211 | let x: Vec = { 212 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 213 | SymmetricDifference { slices: xss }.into_iter().cloned().collect() 214 | }; 215 | 216 | let mut y = BTreeSet::new(); 217 | for v in xss { 218 | let x = BTreeSet::from_iter(v.iter().cloned()); 219 | y = y.symmetric_difference(&x).cloned().collect(); 220 | } 221 | let y: Vec<_> = y.into_iter().collect(); 222 | 223 | x.as_slice() == y.as_slice() 224 | } 225 | } 226 | } 227 | } 228 | 229 | #[cfg(all(feature = "unstable", test))] 230 | mod bench { 231 | extern crate test; 232 | use super::*; 233 | use self::test::Bencher; 234 | use crate::set::SetBuf; 235 | 236 | #[bench] 237 | fn two_slices_big(bench: &mut Bencher) { 238 | let a: Vec<_> = (0..100).collect(); 239 | let b: Vec<_> = (1..101).collect(); 240 | 241 | bench.iter(|| { 242 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b] }.into_set_buf(); 243 | test::black_box(|| symdiff_); 244 | }); 245 | } 246 | 247 | #[bench] 248 | fn two_slices_big2(bench: &mut Bencher) { 249 | let a: Vec<_> = (0..100).collect(); 250 | let b: Vec<_> = (51..151).collect(); 251 | 252 | bench.iter(|| { 253 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b] }.into_set_buf(); 254 | test::black_box(|| symdiff_); 255 | }); 256 | } 257 | 258 | #[bench] 259 | fn two_slices_big3(bench: &mut Bencher) { 260 | let a: Vec<_> = (0..100).collect(); 261 | let b: Vec<_> = (100..200).collect(); 262 | 263 | bench.iter(|| { 264 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b] }.into_set_buf(); 265 | test::black_box(|| symdiff_); 266 | }); 267 | } 268 | 269 | #[bench] 270 | fn three_slices_big(bench: &mut Bencher) { 271 | let a: Vec<_> = (0..100).collect(); 272 | let b: Vec<_> = (1..101).collect(); 273 | let c: Vec<_> = (2..102).collect(); 274 | 275 | bench.iter(|| { 276 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b, &c] }.into_set_buf(); 277 | test::black_box(|| symdiff_); 278 | }); 279 | } 280 | 281 | #[bench] 282 | fn three_slices_big2(bench: &mut Bencher) { 283 | let a: Vec<_> = (0..100).collect(); 284 | let b: Vec<_> = (34..134).collect(); 285 | let c: Vec<_> = (66..167).collect(); 286 | 287 | bench.iter(|| { 288 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b, &c] }.into_set_buf(); 289 | test::black_box(|| symdiff_); 290 | }); 291 | } 292 | 293 | #[bench] 294 | fn three_slices_big3(bench: &mut Bencher) { 295 | let a: Vec<_> = (0..100).collect(); 296 | let b: Vec<_> = (100..200).collect(); 297 | let c: Vec<_> = (200..300).collect(); 298 | 299 | bench.iter(|| { 300 | let symdiff_: SetBuf = SymmetricDifference { slices: vec![&a, &b, &c] }.into_set_buf(); 301 | test::black_box(|| symdiff_); 302 | }); 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /src/multi/union.rs: -------------------------------------------------------------------------------- 1 | use crate::set::{Set, vec_sets_into_slices}; 2 | use crate::two_minimums::{two_minimums, Minimums::*}; 3 | use crate::{SetOperation, Collection}; 4 | 5 | /// Represent the _union_ set operation that will be applied to the slices. 6 | /// 7 | /// # Examples 8 | /// ``` 9 | /// # use sdset::Error; 10 | /// # fn try_main() -> Result<(), Error> { 11 | /// use sdset::multi::OpBuilder; 12 | /// use sdset::{SetOperation, Set, SetBuf}; 13 | /// 14 | /// let a = Set::new(&[1, 2, 4])?; 15 | /// let b = Set::new(&[2, 3, 5, 7])?; 16 | /// let c = Set::new(&[4, 6, 7])?; 17 | /// 18 | /// let op = OpBuilder::from_vec(vec![a, b, c]).union(); 19 | /// 20 | /// let res: SetBuf = op.into_set_buf(); 21 | /// assert_eq!(&res[..], &[1, 2, 3, 4, 5, 6, 7]); 22 | /// # Ok(()) } 23 | /// # try_main().unwrap(); 24 | /// ``` 25 | #[derive(Clone)] 26 | pub struct Union<'a, T: 'a> { 27 | slices: Vec<&'a [T]>, 28 | } 29 | 30 | impl<'a, T> Union<'a, T> { 31 | /// Construct one with slices checked to be sorted and deduplicated. 32 | pub fn new(slices: Vec<&'a Set>) -> Self { 33 | Self { 34 | slices: vec_sets_into_slices(slices), 35 | } 36 | } 37 | } 38 | 39 | impl<'a, T: Ord> Union<'a, T> { 40 | #[inline] 41 | fn extend_collection(mut self, output: &mut C, extend: F, push: G) -> Result<(), C::Error> 42 | where C: Collection, 43 | F: Fn(&mut C, &'a [T]) -> Result<(), C::Error>, 44 | G: Fn(&mut C, &'a T) -> Result<(), C::Error>, 45 | { 46 | if let Some(slice) = self.slices.first() { 47 | output.reserve(slice.len())?; 48 | } 49 | 50 | loop { 51 | match two_minimums(&self.slices) { 52 | Two((i, f), (_, s)) => { 53 | if f != s { 54 | let off = self.slices[i].iter().take_while(|&e| e < s).count(); 55 | extend(output, &self.slices[i][..off])?; 56 | self.slices[i] = &self.slices[i][off..]; 57 | } 58 | push(output, s)?; 59 | for slice in &mut self.slices { 60 | if slice.first() == Some(s) { 61 | *slice = &slice[1..]; 62 | } 63 | } 64 | }, 65 | One((i, _)) => { 66 | extend(output, self.slices[i])?; 67 | break; 68 | }, 69 | Nothing => break, 70 | } 71 | } 72 | Ok(()) 73 | } 74 | 75 | fn iter(&self) -> UnionIter<'a, T> 76 | { 77 | UnionIter { 78 | slices: self.slices.clone(), 79 | } 80 | } 81 | } 82 | 83 | impl<'a, T: Ord + Clone> SetOperation for Union<'a, T> { 84 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 85 | where C: Collection, 86 | { 87 | self.extend_collection(output, Collection::extend_from_slice, |v, x| v.push(x.clone())) 88 | } 89 | } 90 | 91 | impl<'a, T: Ord> SetOperation<&'a T> for Union<'a, T> { 92 | fn extend_collection(self, output: &mut C) -> Result<(), C::Error> 93 | where C: Collection<&'a T>, 94 | { 95 | self.extend_collection(output, Collection::extend, Collection::push) 96 | } 97 | } 98 | 99 | impl<'a, T: Ord> IntoIterator for Union<'a, T> { 100 | type Item = &'a T; 101 | type IntoIter = UnionIter<'a, T>; 102 | fn into_iter(self) -> Self::IntoIter { 103 | UnionIter { 104 | slices: self.slices, 105 | } 106 | } 107 | } 108 | 109 | impl<'a, T: Ord> IntoIterator for &'a Union<'a, T> { 110 | type Item = &'a T; 111 | type IntoIter = UnionIter<'a, T>; 112 | fn into_iter(self) -> Self::IntoIter { 113 | self.iter() 114 | } 115 | } 116 | 117 | pub struct UnionIter<'a, T> { 118 | slices: Vec<&'a [T]>, 119 | } 120 | 121 | impl<'a, T: Ord> Iterator for UnionIter<'a, T> { 122 | type Item = &'a T; 123 | 124 | fn next(&mut self) -> Option { 125 | loop { 126 | match two_minimums(&self.slices) { 127 | Two((i, f), (_, s)) => { 128 | if f != s { 129 | let result = &self.slices[i][0]; 130 | self.slices[i] = &self.slices[i][1..]; 131 | return Some(result); 132 | } else { 133 | for slice in &mut self.slices { 134 | if slice.first() == Some(s) { 135 | *slice = &slice[1..]; 136 | } 137 | } 138 | return Some(s); 139 | } 140 | 141 | }, 142 | One((i, _)) => { 143 | let result = &self.slices[i][0]; 144 | self.slices[i] = &self.slices[i][1..]; 145 | return Some(result); 146 | }, 147 | Nothing => { return None; }, 148 | } 149 | } 150 | } 151 | } 152 | 153 | #[cfg(test)] 154 | mod tests { 155 | mod set_to_set { 156 | use super::super::*; 157 | use crate::set::{sort_dedup_vec, SetBuf}; 158 | 159 | #[test] 160 | fn no_slice() { 161 | let union_: SetBuf = Union { slices: vec![] }.into_set_buf(); 162 | assert_eq!(&union_[..], &[]); 163 | } 164 | 165 | #[test] 166 | fn one_empty_slice() { 167 | let a: &[i32] = &[]; 168 | 169 | let union_: SetBuf = Union { slices: vec![a] }.into_set_buf(); 170 | assert_eq!(&union_[..], &[]); 171 | } 172 | 173 | #[test] 174 | fn one_slice() { 175 | let a = &[1, 2, 3]; 176 | 177 | let union_: SetBuf = Union { slices: vec![a] }.into_set_buf(); 178 | assert_eq!(&union_[..], &[1, 2, 3]); 179 | } 180 | 181 | #[test] 182 | fn two_slices_equal() { 183 | let a = &[1, 2, 3]; 184 | let b = &[1, 2, 3]; 185 | 186 | let union_: SetBuf = Union { slices: vec![a, b] }.into_set_buf(); 187 | assert_eq!(&union_[..], &[1, 2, 3]); 188 | } 189 | 190 | #[test] 191 | fn two_slices_little() { 192 | let a = &[1]; 193 | let b = &[2]; 194 | 195 | let union_: SetBuf = Union { slices: vec![a, b] }.into_set_buf(); 196 | assert_eq!(&union_[..], &[1, 2]); 197 | } 198 | 199 | #[test] 200 | fn two_slices() { 201 | let a = &[1, 2, 3]; 202 | let b = &[2, 3, 4]; 203 | 204 | let union_: SetBuf = Union { slices: vec![a, b] }.into_set_buf(); 205 | assert_eq!(&union_[..], &[1, 2, 3, 4]); 206 | } 207 | 208 | #[test] 209 | fn three_slices() { 210 | let a = &[1, 2, 3]; 211 | let b = &[2, 3, 4]; 212 | let c = &[3, 4, 5]; 213 | 214 | let union_: SetBuf = Union { slices: vec![a, b, c] }.into_set_buf(); 215 | assert_eq!(&union_[..], &[1, 2, 3, 4, 5]); 216 | } 217 | 218 | quickcheck! { 219 | fn qc_union(xss: Vec>) -> bool { 220 | use std::collections::BTreeSet; 221 | use std::iter::FromIterator; 222 | 223 | // FIXME temporary hack (can have mutable parameters!) 224 | let mut xss = xss; 225 | 226 | for xs in &mut xss { 227 | sort_dedup_vec(xs); 228 | } 229 | 230 | let x: SetBuf = { 231 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 232 | Union { slices: xss }.into_set_buf() 233 | }; 234 | 235 | let mut y = BTreeSet::new(); 236 | for v in xss { 237 | let x = BTreeSet::from_iter(v.iter().cloned()); 238 | y = y.union(&x).cloned().collect(); 239 | } 240 | let y: Vec<_> = y.into_iter().collect(); 241 | 242 | x.as_slice() == y.as_slice() 243 | } 244 | } 245 | } 246 | 247 | mod set_to_iter { 248 | use super::super::*; 249 | use crate::set::sort_dedup_vec; 250 | 251 | #[test] 252 | fn no_slice() { 253 | let union = Union { slices: vec![] }; 254 | let union_ref: Vec = union.iter().cloned().collect(); 255 | assert_eq!(&union_ref[..], &[]); 256 | let union_own: Vec = union.into_iter().cloned().collect(); 257 | assert_eq!(&union_own[..], &[]); 258 | } 259 | 260 | #[test] 261 | fn one_empty_slice() { 262 | let a: &[i32] = &[]; 263 | 264 | let union = Union { slices: vec![a] }; 265 | let union_ref: Vec = union.iter().cloned().collect(); 266 | assert_eq!(&union_ref[..], &[]); 267 | let union_own: Vec = union.into_iter().cloned().collect(); 268 | assert_eq!(&union_own[..], &[]); 269 | } 270 | 271 | #[test] 272 | fn one_slice() { 273 | let a = &[1, 2, 3]; 274 | 275 | let union = Union { slices: vec![a] }; 276 | let union_ref: Vec = union.iter().cloned().collect(); 277 | assert_eq!(&union_ref[..], &[1, 2, 3]); 278 | let union_own: Vec = union.into_iter().cloned().collect(); 279 | assert_eq!(&union_own[..], &[1, 2, 3]); 280 | } 281 | 282 | #[test] 283 | fn two_slices_equal() { 284 | let a = &[1, 2, 3]; 285 | let b = &[1, 2, 3]; 286 | 287 | let union = Union { slices: vec![a, b] }; 288 | let union_ref: Vec = union.iter().cloned().collect(); 289 | assert_eq!(&union_ref[..], &[1, 2, 3]); 290 | let union_own: Vec = union.into_iter().cloned().collect(); 291 | assert_eq!(&union_own[..], &[1, 2, 3]); 292 | } 293 | 294 | #[test] 295 | fn two_slices_little() { 296 | let a = &[1]; 297 | let b = &[2]; 298 | 299 | let union = Union { slices: vec![a, b] }; 300 | let union_ref: Vec = union.iter().cloned().collect(); 301 | assert_eq!(&union_ref[..], &[1, 2]); 302 | let union_own: Vec = union.into_iter().cloned().collect(); 303 | assert_eq!(&union_own[..], &[1, 2]); 304 | } 305 | 306 | #[test] 307 | fn two_slices() { 308 | let a = &[1, 2, 3]; 309 | let b = &[2, 3, 4]; 310 | 311 | let union = Union { slices: vec![a, b] }; 312 | let union_ref: Vec = union.iter().cloned().collect(); 313 | assert_eq!(&union_ref[..], &[1, 2, 3, 4]); 314 | let union_own: Vec = union.into_iter().cloned().collect(); 315 | assert_eq!(&union_own[..], &[1, 2, 3, 4]); 316 | } 317 | 318 | #[test] 319 | fn three_slices() { 320 | let a = &[1, 2, 3]; 321 | let b = &[2, 3, 4]; 322 | let c = &[3, 4, 5]; 323 | 324 | let union = Union { slices: vec![a, b, c] }; 325 | let union_ref: Vec = union.iter().cloned().collect(); 326 | assert_eq!(&union_ref[..], &[1, 2, 3, 4, 5]); 327 | let union_own: Vec = union.into_iter().cloned().collect(); 328 | assert_eq!(&union_own[..], &[1, 2, 3, 4, 5]); 329 | } 330 | 331 | quickcheck! { 332 | fn qc_union(xss: Vec>) -> bool { 333 | use std::collections::BTreeSet; 334 | use std::iter::FromIterator; 335 | 336 | // FIXME temporary hack (can have mutable parameters!) 337 | let mut xss = xss; 338 | 339 | for xs in &mut xss { 340 | sort_dedup_vec(xs); 341 | } 342 | 343 | let x: Vec = { 344 | let xss = xss.iter().map(|xs| xs.as_slice()).collect(); 345 | Union { slices: xss }.into_iter().cloned().collect() 346 | }; 347 | 348 | let mut y = BTreeSet::new(); 349 | for v in xss { 350 | let x = BTreeSet::from_iter(v.iter().cloned()); 351 | y = y.union(&x).cloned().collect(); 352 | } 353 | let y: Vec<_> = y.into_iter().collect(); 354 | 355 | x.as_slice() == y.as_slice() 356 | } 357 | } 358 | } 359 | } 360 | 361 | #[cfg(all(feature = "unstable", test))] 362 | mod bench { 363 | extern crate test; 364 | use super::*; 365 | use self::test::Bencher; 366 | use crate::set::SetBuf; 367 | 368 | #[bench] 369 | fn two_slices_big(bench: &mut Bencher) { 370 | let a: Vec<_> = (0..100).collect(); 371 | let b: Vec<_> = (1..101).collect(); 372 | 373 | bench.iter(|| { 374 | let union_: SetBuf = Union { slices: vec![&a, &b] }.into_set_buf(); 375 | test::black_box(|| union_); 376 | }); 377 | } 378 | 379 | #[bench] 380 | fn two_slices_big2(bench: &mut Bencher) { 381 | let a: Vec<_> = (0..100).collect(); 382 | let b: Vec<_> = (51..151).collect(); 383 | 384 | bench.iter(|| { 385 | let union_: SetBuf = Union { slices: vec![&a, &b] }.into_set_buf(); 386 | test::black_box(|| union_); 387 | }); 388 | } 389 | 390 | #[bench] 391 | fn two_slices_big3(bench: &mut Bencher) { 392 | let a: Vec<_> = (0..100).collect(); 393 | let b: Vec<_> = (100..200).collect(); 394 | 395 | bench.iter(|| { 396 | let union_: SetBuf = Union { slices: vec![&a, &b] }.into_set_buf(); 397 | test::black_box(|| union_); 398 | }); 399 | } 400 | 401 | #[bench] 402 | fn three_slices_big(bench: &mut Bencher) { 403 | let a: Vec<_> = (0..100).collect(); 404 | let b: Vec<_> = (1..101).collect(); 405 | let c: Vec<_> = (2..102).collect(); 406 | 407 | bench.iter(|| { 408 | let union_: SetBuf = Union { slices: vec![&a, &b, &c] }.into_set_buf(); 409 | test::black_box(|| union_); 410 | }); 411 | } 412 | 413 | #[bench] 414 | fn three_slices_big2(bench: &mut Bencher) { 415 | let a: Vec<_> = (0..100).collect(); 416 | let b: Vec<_> = (34..134).collect(); 417 | let c: Vec<_> = (66..167).collect(); 418 | 419 | bench.iter(|| { 420 | let union_: SetBuf = Union { slices: vec![&a, &b, &c] }.into_set_buf(); 421 | test::black_box(|| union_); 422 | }); 423 | } 424 | 425 | #[bench] 426 | fn three_slices_big3(bench: &mut Bencher) { 427 | let a: Vec<_> = (0..100).collect(); 428 | let b: Vec<_> = (100..200).collect(); 429 | let c: Vec<_> = (200..300).collect(); 430 | 431 | bench.iter(|| { 432 | let union_: SetBuf = Union { slices: vec![&a, &b, &c] }.into_set_buf(); 433 | test::black_box(|| union_); 434 | }); 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /src/set.rs: -------------------------------------------------------------------------------- 1 | //! All the methods and types associated to [`Set`]s. 2 | 3 | use std::cmp::Ordering; 4 | use std::borrow::Borrow; 5 | use std::ops::{Deref, RangeBounds, Bound}; 6 | use std::{error, fmt, mem}; 7 | 8 | #[cfg(feature="serde")] 9 | use serde::{Serialize, Deserialize}; 10 | 11 | use crate::{exponential_search, exponential_search_by, exponential_search_by_key}; 12 | 13 | /// Represent a slice which contains types that are sorted and deduplicated (akin to [`str`]). 14 | /// 15 | /// This is an *unsized* type, meaning that it must always be used behind a 16 | /// pointer like `&` or [`Box`]. For an owned version of this type, 17 | /// see [`SetBuf`]. 18 | #[cfg_attr(feature="serde", derive(Serialize))] 19 | #[repr(transparent)] 20 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 21 | pub struct Set([T]); 22 | 23 | impl Set { 24 | /// Construct a [`Set`] only if it is sorted and deduplicated. 25 | /// 26 | /// ``` 27 | /// use sdset::{Set, Error}; 28 | /// # fn try_main() -> Result<(), Error> { 29 | /// 30 | /// let slice = &[1, 2, 4, 6, 7]; 31 | /// let set = Set::new(slice)?; 32 | /// 33 | /// // this slice is not sorted! 34 | /// let slice = &[1, 2, 4, 7, 6]; 35 | /// let set = Set::new(slice); 36 | /// 37 | /// assert_eq!(set, Err(Error::NotSort)); 38 | /// # Ok(()) } 39 | /// # try_main().unwrap(); 40 | /// ``` 41 | #[inline] 42 | pub fn new(slice: &[T]) -> Result<&Self, Error> 43 | where T: Ord 44 | { 45 | is_sort_dedup(slice).map(|_| Self::new_unchecked(slice)) 46 | } 47 | 48 | /// Construct a [`Set`] without checking it. 49 | /// 50 | /// ``` 51 | /// use sdset::{Set, Error}; 52 | /// # fn try_main() -> Result<(), Error> { 53 | /// 54 | /// // this slice is not sorted 55 | /// let slice = &[1, 2, 4, 7, 6]; 56 | /// 57 | /// // but we can still create a Set, so be careful! 58 | /// let set = Set::new_unchecked(slice); 59 | /// # Ok(()) } 60 | /// # try_main().unwrap(); 61 | /// ``` 62 | #[inline] 63 | pub fn new_unchecked(slice: &[T]) -> &Self { 64 | unsafe { mem::transmute(slice) } 65 | } 66 | 67 | /// Returns a [`Set`] containing all the values in the given range. 68 | /// 69 | /// This function uses exponential searching internally 70 | /// because it is verified that the elements are ordered. 71 | /// 72 | /// ``` 73 | /// use std::ops::Bound::{Excluded, Included}; 74 | /// use sdset::{Set, Error}; 75 | /// # fn try_main() -> Result<(), Error> { 76 | /// 77 | /// let set = Set::new(&[1, 2, 4, 6, 7])?; 78 | /// 79 | /// let subset = set.range(2..=6); 80 | /// assert_eq!(subset.as_slice(), &[2, 4, 6]); 81 | /// 82 | /// let subset = set.range(3..5); 83 | /// assert_eq!(subset.as_slice(), &[4]); 84 | /// 85 | /// let subset = set.range((Excluded(&2), Included(&7))); 86 | /// assert_eq!(subset.as_slice(), &[4, 6, 7]); 87 | /// # Ok(()) } 88 | /// # try_main().unwrap(); 89 | /// ``` 90 | #[inline] 91 | pub fn range(&self, range: R) -> &Self 92 | where K: Ord + ?Sized, 93 | R: RangeBounds, 94 | T: Borrow, 95 | { 96 | let left = match range.start_bound() { 97 | Bound::Included(x) => match self.exponential_search_by(|e| e.borrow().cmp(x)) { 98 | Ok(index) => index, 99 | Err(index) => index, 100 | }, 101 | Bound::Excluded(x) => match self.exponential_search_by(|e| e.borrow().cmp(x)) { 102 | Ok(index) => index + 1, 103 | Err(index) => index, 104 | }, 105 | Bound::Unbounded => 0, 106 | }; 107 | 108 | let right = match range.end_bound() { 109 | Bound::Included(x) => match self.exponential_search_by(|e| e.borrow().cmp(x)) { 110 | Ok(index) => index + 1, 111 | Err(index) => index, 112 | }, 113 | Bound::Excluded(x) => match self.exponential_search_by(|e| e.borrow().cmp(x)) { 114 | Ok(index) => index, 115 | Err(index) => index, 116 | }, 117 | Bound::Unbounded => self.len(), 118 | }; 119 | 120 | Self::new_unchecked(&self[left..right]) 121 | } 122 | 123 | /// Exponential searches this sorted slice for a given element. 124 | /// 125 | /// If the value is found then `Ok` is returned, containing the index of the matching element; 126 | /// if the value is not found then `Err` is returned, containing the index where a 127 | /// matching element could be inserted while maintaining sorted order. 128 | /// 129 | /// See the [`exponential_search`] documentation for more details. 130 | #[inline] 131 | pub fn exponential_search(&self, elem: &T) -> Result 132 | where T: Ord, 133 | { 134 | exponential_search(self, elem) 135 | } 136 | 137 | /// Binary searches this sorted slice with a comparator function. 138 | /// 139 | /// The comparator function should implement an order consistent with the sort order of 140 | /// the underlying slice, returning an order code that indicates whether its argument 141 | /// is `Less`, `Equal` or `Greater` the desired target. 142 | /// 143 | /// If the value is found then `Ok` is returned, containing the index of the matching element; 144 | /// if the value is not found then `Err` is returned, containing the index where a 145 | /// matching element could be inserted while maintaining sorted order. 146 | /// 147 | /// See the [`exponential_search_by`] documentation for more details. 148 | #[inline] 149 | pub fn exponential_search_by(&self, f: F) -> Result 150 | where F: FnMut(&T) -> Ordering, 151 | { 152 | exponential_search_by(self, f) 153 | } 154 | 155 | /// Binary searches this sorted slice with a key extraction function. 156 | /// 157 | /// Assumes that the slice is sorted by the key. 158 | /// 159 | /// If the value is found then `Ok` is returned, containing the index of the matching element; 160 | /// if the value is not found then `Err` is returned, containing the index where a 161 | /// matching element could be inserted while maintaining sorted order. 162 | /// 163 | /// See the [`exponential_search_by`] documentation for more details. 164 | #[inline] 165 | pub fn exponential_search_by_key(&self, b: &B, f: F) -> Result 166 | where F: FnMut(&T) -> B, 167 | B: Ord, 168 | { 169 | exponential_search_by_key(self, b, f) 170 | } 171 | 172 | /// Returns `true` if the set contains an element with the given value. 173 | /// 174 | /// This function uses exponential searching internally 175 | /// because it is verified that the elements are ordered. 176 | /// 177 | /// ``` 178 | /// use sdset::{Set, Error}; 179 | /// # fn try_main() -> Result<(), Error> { 180 | /// 181 | /// let slice = &[1, 2, 4, 6, 7]; 182 | /// let set = Set::new(slice)?; 183 | /// 184 | /// assert!(set.contains(&4)); 185 | /// # Ok(()) } 186 | /// # try_main().unwrap(); 187 | /// ``` 188 | #[inline] 189 | pub fn contains(&self, x: &T) -> bool 190 | where T: Ord, 191 | { 192 | self.exponential_search(x).is_ok() 193 | } 194 | 195 | /// Construct the owning version of the [`Set`]. 196 | /// 197 | /// ``` 198 | /// use sdset::{Set, SetBuf, Error}; 199 | /// # fn try_main() -> Result<(), Error> { 200 | /// 201 | /// let set = Set::new(&[1, 2, 4, 6, 7])?; 202 | /// let setbuf: SetBuf<_> = set.to_set_buf(); 203 | /// # Ok(()) } 204 | /// # try_main().unwrap(); 205 | /// ``` 206 | #[inline] 207 | pub fn to_set_buf(&self) -> SetBuf 208 | where T: Clone 209 | { 210 | SetBuf(self.0.to_vec()) 211 | } 212 | 213 | /// Return the slice "inside" of this [`Set`]. 214 | /// 215 | /// ``` 216 | /// use sdset::{Set, Error}; 217 | /// # fn try_main() -> Result<(), Error> { 218 | /// 219 | /// let slice = &[1, 2, 4, 6, 7]; 220 | /// let set = Set::new(slice)?; 221 | /// 222 | /// assert_eq!(set.as_slice(), slice); 223 | /// # Ok(()) } 224 | /// # try_main().unwrap(); 225 | /// ``` 226 | #[inline] 227 | pub fn as_slice(&self) -> &[T] { 228 | &self.0 229 | } 230 | 231 | /// Returns an iterator over this ordered set. 232 | /// 233 | /// ``` 234 | /// use sdset::Set; 235 | /// 236 | /// let x = Set::new_unchecked(&[1, 2, 4]); 237 | /// let mut iterator = x.iter(); 238 | /// 239 | /// assert_eq!(iterator.next(), Some(&1)); 240 | /// assert_eq!(iterator.next(), Some(&2)); 241 | /// assert_eq!(iterator.next(), Some(&4)); 242 | /// assert_eq!(iterator.next(), None); 243 | /// ``` 244 | #[inline] 245 | pub fn iter(&self) -> std::slice::Iter { 246 | self.0.iter() 247 | } 248 | } 249 | 250 | impl ToOwned for Set { 251 | type Owned = SetBuf; 252 | 253 | fn to_owned(&self) -> Self::Owned { 254 | SetBuf(self.0.to_owned()) 255 | } 256 | } 257 | 258 | impl Default for &Set { 259 | fn default() -> Self { 260 | Set::new_unchecked(&[]) 261 | } 262 | } 263 | 264 | impl Deref for Set { 265 | type Target = [T]; 266 | 267 | fn deref(&self) -> &Self::Target { 268 | self.as_slice() 269 | } 270 | } 271 | 272 | impl AsRef<[T]> for Set { 273 | fn as_ref(&self) -> &[T] { 274 | &self.0 275 | } 276 | } 277 | 278 | impl AsRef> for Set { 279 | fn as_ref(&self) -> &Set { 280 | self 281 | } 282 | } 283 | 284 | impl<'a, T> IntoIterator for &'a Set { 285 | type Item = &'a T; 286 | type IntoIter = std::slice::Iter<'a, T>; 287 | 288 | fn into_iter(self) -> Self::IntoIter { 289 | self.iter() 290 | } 291 | } 292 | 293 | /// An owned, set (akin to [`String`]). 294 | #[cfg_attr(feature="serde", derive(Serialize))] 295 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 296 | pub struct SetBuf(Vec); 297 | 298 | impl SetBuf { 299 | /// Construct a [`SetBuf`] only if it is sorted and deduplicated. 300 | /// 301 | /// ``` 302 | /// use sdset::{SetBuf, Error}; 303 | /// # fn try_main() -> Result<(), Error> { 304 | /// 305 | /// let vec = vec![1, 2, 4, 6, 7]; 306 | /// let setbuf = SetBuf::new(vec)?; 307 | /// 308 | /// // this vec is not sorted! 309 | /// let vec = vec![1, 2, 4, 7, 6]; 310 | /// let setbuf = SetBuf::new(vec); 311 | /// 312 | /// assert_eq!(setbuf, Err(Error::NotSort)); 313 | /// # Ok(()) } 314 | /// # try_main().unwrap(); 315 | /// ``` 316 | #[inline] 317 | pub fn new(vec: Vec) -> Result 318 | where T: Ord 319 | { 320 | is_sort_dedup(&vec).map(|_| SetBuf::new_unchecked(vec)) 321 | } 322 | 323 | /// Construct a [`SetBuf`] from an unsorted and/or 324 | /// non-deduplicated `Vec`. 325 | /// 326 | /// ``` 327 | /// use sdset::SetBuf; 328 | /// 329 | /// let set = SetBuf::from_dirty(vec![1, 4, 2, 6, 4]); 330 | /// let mut iterator = set.into_iter(); 331 | /// 332 | /// assert_eq!(iterator.next(), Some(1)); 333 | /// assert_eq!(iterator.next(), Some(2)); 334 | /// assert_eq!(iterator.next(), Some(4)); 335 | /// assert_eq!(iterator.next(), Some(6)); 336 | /// assert_eq!(iterator.next(), None); 337 | /// ``` 338 | pub fn from_dirty(mut vec: Vec) -> Self 339 | where T: Ord, 340 | { 341 | sort_dedup_vec(&mut vec); 342 | SetBuf(vec) 343 | } 344 | 345 | /// Construct a [`SetBuf`] without checking it. 346 | /// 347 | /// ``` 348 | /// use sdset::{SetBuf, Error}; 349 | /// # fn try_main() -> Result<(), Error> { 350 | /// 351 | /// // this vec is not sorted 352 | /// let vec = vec![1, 2, 4, 7, 6]; 353 | /// 354 | /// // but we can still create a SetBuf, so be careful! 355 | /// let setbuf = SetBuf::new_unchecked(vec); 356 | /// # Ok(()) } 357 | /// # try_main().unwrap(); 358 | /// ``` 359 | #[inline] 360 | pub fn new_unchecked(vec: Vec) -> Self { 361 | SetBuf(vec) 362 | } 363 | 364 | /// Return the [`Set`] owned by this [`SetBuf`]. 365 | /// 366 | /// ``` 367 | /// use sdset::{Set, SetBuf, Error}; 368 | /// # fn try_main() -> Result<(), Error> { 369 | /// 370 | /// let vec = vec![1, 2, 4, 6, 7]; 371 | /// let setbuf = SetBuf::new(vec.clone())?; 372 | /// 373 | /// let set = Set::new(&vec)?; 374 | /// assert_eq!(setbuf.as_set(), set); 375 | /// # Ok(()) } 376 | /// # try_main().unwrap(); 377 | /// ``` 378 | #[inline] 379 | pub fn as_set(&self) -> &Set { 380 | Set::new_unchecked(self.0.as_slice()) 381 | } 382 | 383 | /// Return the [`Vec`] inside by this [`SetBuf`]. 384 | /// 385 | /// ``` 386 | /// use sdset::{SetBuf, Error}; 387 | /// # fn try_main() -> Result<(), Error> { 388 | /// 389 | /// let vec = vec![1, 2, 4, 6, 7]; 390 | /// let setbuf = SetBuf::new(vec)?; 391 | /// 392 | /// let vec = setbuf.into_vec(); 393 | /// # Ok(()) } 394 | /// # try_main().unwrap(); 395 | /// ``` 396 | #[inline] 397 | pub fn into_vec(self) -> Vec { 398 | self.0 399 | } 400 | 401 | /// Returns an iterator over this ordered set. 402 | /// 403 | /// ``` 404 | /// use sdset::SetBuf; 405 | /// 406 | /// let x = SetBuf::new_unchecked(vec![1, 2, 4]); 407 | /// let mut iterator = x.iter(); 408 | /// 409 | /// assert_eq!(iterator.next(), Some(&1)); 410 | /// assert_eq!(iterator.next(), Some(&2)); 411 | /// assert_eq!(iterator.next(), Some(&4)); 412 | /// assert_eq!(iterator.next(), None); 413 | /// ``` 414 | #[inline] 415 | pub fn iter(&self) -> std::slice::Iter { 416 | self.0.iter() 417 | } 418 | } 419 | 420 | impl Borrow> for SetBuf { 421 | fn borrow(&self) -> &Set { 422 | self.as_set() 423 | } 424 | } 425 | 426 | impl Default for SetBuf { 427 | fn default() -> Self { 428 | SetBuf::new_unchecked(Vec::new()) 429 | } 430 | } 431 | 432 | impl Deref for SetBuf { 433 | type Target = Set; 434 | 435 | fn deref(&self) -> &Self::Target { 436 | self.as_set() 437 | } 438 | } 439 | 440 | impl AsRef> for SetBuf { 441 | fn as_ref(&self) -> &Set { 442 | self.as_set() 443 | } 444 | } 445 | 446 | impl AsRef<[T]> for SetBuf { 447 | fn as_ref(&self) -> &[T] { 448 | self.0.as_slice() 449 | } 450 | } 451 | 452 | impl IntoIterator for SetBuf { 453 | type Item = T; 454 | type IntoIter = std::vec::IntoIter; 455 | 456 | fn into_iter(self) -> Self::IntoIter { 457 | self.0.into_iter() 458 | } 459 | } 460 | 461 | #[cfg(feature="serde")] 462 | use serde::de::{Deserializer, Error as SerdeError}; 463 | 464 | #[cfg(feature="serde")] 465 | impl<'de, T> Deserialize<'de> for SetBuf 466 | where 467 | T: Deserialize<'de> + Ord, 468 | { 469 | fn deserialize(deserializer: D) -> Result 470 | where 471 | D: Deserializer<'de>, 472 | { 473 | let vec = Vec::deserialize(deserializer)?; 474 | 475 | match SetBuf::new(vec) { 476 | Ok(set) => Ok(set), 477 | Err(e) => Err(D::Error::custom(e)), 478 | } 479 | } 480 | 481 | fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> 482 | where 483 | D: Deserializer<'de>, 484 | { 485 | Vec::deserialize_in_place(deserializer, &mut place.0)?; 486 | 487 | is_sort_dedup(&place.0).map_err(D::Error::custom) 488 | } 489 | } 490 | 491 | /// Represent the possible errors when creating a [`Set`]. 492 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 493 | pub enum Error { 494 | /// Define that a slice is not sorted. 495 | NotSort, 496 | /// Define that a slice is not deduplicated. 497 | NotDedup, 498 | } 499 | 500 | impl fmt::Display for Error { 501 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 502 | let desc = match self { 503 | Error::NotSort => "elements are not sorted.", 504 | Error::NotDedup => "elements contain duplicates.", 505 | }; 506 | f.write_str(desc) 507 | } 508 | } 509 | 510 | impl error::Error for Error {} 511 | 512 | /// The list of all [`Error`]s that can occur 513 | /// while trying to convert a [`slice`](std::slice) to a [`Set`]. 514 | pub type Errors = Vec>; 515 | 516 | /// Construct a [`Vec`] of [`Set`]s only if all slices are sorted and deduplicated. 517 | /// 518 | /// Otherwise returns the [`Vec`] given in parameter along with a [`Vec`] containing 519 | /// the possible conversion errors of each slice. 520 | /// 521 | /// # Examples 522 | /// ``` 523 | /// use sdset::set::vec_slices_into_sets; 524 | /// 525 | /// let a = &[1, 2, 3, 4][..]; 526 | /// let b = &[1, 4, 6, 7]; 527 | /// let slices = vec![a, b]; 528 | /// 529 | /// let sets = vec_slices_into_sets(slices).unwrap(); 530 | /// ``` 531 | pub fn vec_slices_into_sets(vec: Vec<&[T]>) -> Result>, (Vec<&[T]>, Errors)> { 532 | let mut has_error = false; 533 | let mut errors = Errors::with_capacity(vec.len()); 534 | for slice in &vec { 535 | let res = is_sort_dedup(slice).err(); 536 | has_error = res.is_some(); 537 | errors.push(res); 538 | } 539 | 540 | if has_error { 541 | return Err((vec, errors)) 542 | } 543 | 544 | Ok(vec_slices_into_sets_unchecked(vec)) 545 | } 546 | 547 | /// Transmutes slices without checking them. 548 | /// 549 | /// This is useful when you don't want to introduce another allocation to 550 | /// your program and you are sure all these slices are valid [`Set`]s. 551 | /// 552 | /// # Examples 553 | /// ``` 554 | /// use sdset::set::vec_slices_into_sets_unchecked; 555 | /// 556 | /// // these slices are not sorted! 557 | /// let a = &[1, 6, 4][..]; 558 | /// let b = &[1, 6, 1]; 559 | /// let slices = vec![a, b]; 560 | /// 561 | /// // but we can still create a Vec of Sets, so be careful! 562 | /// let sets = vec_slices_into_sets_unchecked(slices); 563 | /// ``` 564 | pub fn vec_slices_into_sets_unchecked(vec: Vec<&[T]>) -> Vec<&Set> { 565 | unsafe { mem::transmute(vec) } 566 | } 567 | 568 | /// Safely transmute a [`Vec`] of [`Set`]s into a [`Vec`] of [`slice`](std::slice). 569 | /// 570 | /// This is useful when you don't want to introduce another allocation to your program. 571 | /// 572 | /// Note that the values that are parts of the returned 573 | /// slices will be ordered and deduplicated. 574 | pub fn vec_sets_into_slices(vec: Vec<&Set>) -> Vec<&[T]> { 575 | unsafe { mem::transmute(vec) } 576 | } 577 | 578 | /// Safely transmute a [`slice`](std::slice) of [`Set`]s into 579 | /// a [`slice`](std::slice) of [`slice`](std::slice). 580 | /// 581 | /// This is useful when you don't want to introduce another allocation to your program. 582 | /// 583 | /// Note that the values that are parts of the returned 584 | /// slices will be ordered and deduplicated. 585 | pub fn slice_sets_into_slices<'a, T: 'a>(slice: &'a [&'a Set]) -> &'a [&'a [T]] { 586 | unsafe { mem::transmute(slice) } 587 | } 588 | 589 | /// Sort and dedup the vec given in parameter. 590 | pub fn sort_dedup_vec(vec: &mut Vec) { 591 | vec.sort_unstable(); 592 | vec.dedup(); 593 | } 594 | 595 | /// Returns an error if the slice is not sorted nor deduplicated, returns `()` if it is. 596 | pub fn is_sort_dedup(slice: &[T]) -> Result<(), Error> { 597 | for pair in slice.windows(2) { 598 | match pair[0].cmp(&pair[1]) { 599 | Ordering::Less => (), 600 | Ordering::Equal => return Err(Error::NotDedup), 601 | Ordering::Greater => return Err(Error::NotSort), 602 | } 603 | } 604 | Ok(()) 605 | } 606 | 607 | #[cfg(test)] 608 | mod tests { 609 | use super::*; 610 | use std::ops::Bound::*; 611 | 612 | #[test] 613 | fn range_set() { 614 | let set = Set::new(&[1, 2, 4, 6, 7]).unwrap(); 615 | 616 | let subset = set.range((Excluded(1), Unbounded)); 617 | assert_eq!(subset.as_slice(), &[2, 4, 6, 7]); 618 | 619 | let subset = set.range((Excluded(1), Included(4))); 620 | assert_eq!(subset.as_slice(), &[2, 4]); 621 | 622 | let subset = set.range((Excluded(0), Included(4))); 623 | assert_eq!(subset.as_slice(), &[1, 2, 4]); 624 | 625 | let subset = set.range((Unbounded, Excluded(10))); 626 | assert_eq!(subset.as_slice(), &[1, 2, 4, 6, 7]); 627 | } 628 | 629 | #[test] 630 | fn cow_set_setbuf() { 631 | use std::borrow::Cow; 632 | 633 | let set = Set::new(&[1, 2, 4, 6, 7]).unwrap(); 634 | 635 | let borrowed_cow = Cow::Borrowed(set); 636 | let owned_cow = borrowed_cow.to_owned(); 637 | 638 | assert_eq!(&*owned_cow, set); 639 | } 640 | } 641 | -------------------------------------------------------------------------------- /src/two_minimums.rs: -------------------------------------------------------------------------------- 1 | use self::Minimums::*; 2 | 3 | pub enum Minimums { 4 | Nothing, 5 | One(T), 6 | Two(T, T), 7 | } 8 | 9 | /// Returns the first values of two slices along with the indexes 10 | /// which are the minimums (could be equal). 11 | #[inline] 12 | pub fn two_minimums<'a, T: 'a + Ord>(slices: &[&'a [T]]) -> Minimums<(usize, &'a T)> 13 | { 14 | let mut minimums: Minimums<(_, &T)> = Nothing; 15 | 16 | for (index, slice) in slices.iter().enumerate().filter(|(_, s)| !s.is_empty()) { 17 | let current = (index, &slice[0]); 18 | let (_, min) = current; 19 | 20 | minimums = match minimums { 21 | One(f) | Two(f, _) if min < f.1 => Two(current, f), 22 | One(f) if min >= f.1 => Two(f, current), 23 | Two(f, s) if min < s.1 => Two(f, current), 24 | Nothing => One(current), 25 | other => other, 26 | }; 27 | } 28 | 29 | minimums 30 | } 31 | --------------------------------------------------------------------------------