From a1f7f3bd282a3fb68e8451d98ceda872228dc70d Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 21 Mar 2019 18:19:29 +0100 Subject: [PATCH] copy and adapt code and benchmarks from https://github.com/rust-lang/rust/pull/59186 --- Cargo.toml | 21 ++++ src/benches/set.rs | 297 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/set.rs | 174 ++++++++++++++++++++++++++ src/tests/set.rs | 71 +++++++++++ 5 files changed, 564 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/benches/set.rs create mode 100644 src/lib.rs create mode 100644 src/set.rs create mode 100644 src/tests/set.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7893f4b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rust_bench_btreeset_intersection" +version = "0.1.0" +authors = ["Stein Somers "] +autotests = false +autobenches = false +edition = "2018" + +[dev-dependencies] +proptest = "0.9" +rand = "0.6" +rand_xorshift = "0.1" + +[[test]] +name = "collectionstests" +path = "src/tests/set.rs" + +[[bench]] +name = "collectionsbenches" +path = "src/benches/set.rs" + diff --git a/src/benches/set.rs b/src/benches/set.rs new file mode 100644 index 0000000..60015b2 --- /dev/null +++ b/src/benches/set.rs @@ -0,0 +1,297 @@ +// file comparable to rust/src/liballoc/benches/btree/set.rs +#![feature(test)] + +use std::collections::BTreeSet; + +extern crate rand; +extern crate test; +use self::rand::{thread_rng, Rng}; +use self::test::{black_box, Bencher}; + +fn random(n1: usize, n2: usize) -> [BTreeSet; 2] { + let mut rng = thread_rng(); + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..2 { + while sets[i].len() < [n1, n2][i] { + sets[i].insert(rng.gen()); + } + } + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets +} + +fn stagger(n1: usize, factor: usize) -> [BTreeSet; 2] { + let n2 = n1 * factor; + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..(n1 + n2) { + let b = i % (factor + 1) != 0; + sets[b as usize].insert(i as u32); + } + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets +} + +macro_rules! intersection_bench { + ($name: ident, $sets: expr) => { + #[bench] + pub fn $name(b: &mut Bencher) { + // setup + let sets = $sets; + + // measure + b.iter(|| { + let x = sets[0].intersection(&sets[1]).count(); + black_box(x); + }) + } + }; + ($name: ident, $sets: expr, $intersection_kind: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + use ::rust_bench_btreeset_intersection::set::$intersection_kind; + + // setup + let sets = $sets; + assert!(sets[0].len() <= sets[1].len()); + + // measure + b.iter(|| { + let x = $intersection_kind(&sets[0], &sets[1]).count(); + black_box(x); + }) + } + }; +} + +intersection_bench! {intersect_random_100_vs_100, random(100, 100)} +intersection_bench! {intersect_random_100_vs_100_future,random(100, 100), intersection_future} +intersection_bench! {intersect_random_100_vs_100_search,random(100, 100), intersection_search} +intersection_bench! {intersect_random_100_vs_100_spring,random(100, 100), intersection_spring} +intersection_bench! {intersect_random_100_vs_100_stitch,random(100, 100), intersection_stitch} +intersection_bench! {intersect_random_100_vs_1600, random(100, 1_600)} +intersection_bench! {intersect_random_100_vs_1600_future,random(100, 1_600), intersection_future} +intersection_bench! {intersect_random_100_vs_1600_search,random(100, 1_600), intersection_search} +intersection_bench! {intersect_random_100_vs_1600_spring,random(100, 1_600), intersection_spring} +intersection_bench! {intersect_random_100_vs_1600_stitch,random(100, 1_600), intersection_stitch} +intersection_bench! {intersect_random_100_vs_10k, random(100, 10_000)} +intersection_bench! {intersect_random_100_vs_10k_future,random(100, 10_000), intersection_future} +intersection_bench! {intersect_random_100_vs_10k_search,random(100, 10_000), intersection_search} +intersection_bench! {intersect_random_100_vs_10k_spring,random(100, 10_000), intersection_spring} +intersection_bench! {intersect_random_100_vs_10k_stitch,random(100, 10_000), intersection_stitch} +intersection_bench! {intersect_random_10k_vs_10k, random(10_000, 10_000)} +intersection_bench! {intersect_random_10k_vs_10k_future,random(10_000, 10_000), intersection_future} +intersection_bench! {intersect_random_10k_vs_10k_search,random(10_000, 10_000), intersection_search} +intersection_bench! {intersect_random_10k_vs_10k_spring,random(10_000, 10_000), intersection_spring} +intersection_bench! {intersect_random_10k_vs_10k_stitch,random(10_000, 10_000), intersection_stitch} +intersection_bench! {intersect_random_10k_vs_160k, random(10_000, 160_000)} +intersection_bench! {intersect_random_10k_vs_160k_future,random(10_000, 160_000), intersection_future} +intersection_bench! {intersect_random_10k_vs_160k_search,random(10_000, 160_000), intersection_search} +intersection_bench! {intersect_random_10k_vs_160k_spring,random(10_000, 160_000), intersection_spring} +intersection_bench! {intersect_random_10k_vs_160k_stitch,random(10_000, 160_000), intersection_stitch} +intersection_bench! {intersect_stagger_1_vs_1, stagger(1, 1)} +intersection_bench! {intersect_stagger_1_vs_1_future, stagger(1, 1), intersection_future} +intersection_bench! {intersect_stagger_1_vs_1_search, stagger(1, 1), intersection_search} +intersection_bench! {intersect_stagger_1_vs_1_spring, stagger(1, 1), intersection_spring} +intersection_bench! {intersect_stagger_1_vs_1_stitch, stagger(1, 1), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x2, stagger(10, 2)} +intersection_bench! {intersect_stagger_10_vs_x2_future, stagger(10, 2), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x2_search, stagger(10, 2), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x2_spring, stagger(10, 2), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x2_stitch, stagger(10, 2), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x3, stagger(10, 3)} +intersection_bench! {intersect_stagger_10_vs_x3_future, stagger(10, 3), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x3_search, stagger(10, 3), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x3_spring, stagger(10, 3), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x3_stitch, stagger(10, 3), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x4, stagger(10, 4)} +intersection_bench! {intersect_stagger_10_vs_x4_future, stagger(10, 4), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x4_search, stagger(10, 4), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x4_spring, stagger(10, 4), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x4_stitch, stagger(10, 4), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x5, stagger(10, 5)} +intersection_bench! {intersect_stagger_10_vs_x5_future, stagger(10, 5), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x5_search, stagger(10, 5), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x5_spring, stagger(10, 5), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x5_stitch, stagger(10, 5), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x15, stagger(10, 15)} +intersection_bench! {intersect_stagger_10_vs_x15_future,stagger(10, 15), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x15_search,stagger(10, 15), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x15_spring,stagger(10, 15), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x15_stitch,stagger(10, 15), intersection_stitch} +intersection_bench! {intersect_stagger_10_vs_x16, stagger(10, 16)} +intersection_bench! {intersect_stagger_10_vs_x16_future,stagger(10, 16), intersection_future} +intersection_bench! {intersect_stagger_10_vs_x16_search,stagger(10, 16), intersection_search} +intersection_bench! {intersect_stagger_10_vs_x16_spring,stagger(10, 16), intersection_spring} +intersection_bench! {intersect_stagger_10_vs_x16_stitch,stagger(10, 16), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x4, stagger(100, 4)} +intersection_bench! {intersect_stagger_100_vs_x4_future,stagger(100, 4), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x4_search,stagger(100, 4), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x4_spring,stagger(100, 4), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x4_stitch,stagger(100, 4), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x5, stagger(100, 5)} +intersection_bench! {intersect_stagger_100_vs_x5_future,stagger(100, 5), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x5_search,stagger(100, 5), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x5_spring,stagger(100, 5), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x5_stitch,stagger(100, 5), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x6, stagger(100, 6)} +intersection_bench! {intersect_stagger_100_vs_x6_future,stagger(100, 6), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x6_search,stagger(100, 6), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x6_spring,stagger(100, 6), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x6_stitch,stagger(100, 6), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x7, stagger(100, 7)} +intersection_bench! {intersect_stagger_100_vs_x7_future,stagger(100, 7), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x7_search,stagger(100, 7), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x7_spring,stagger(100, 7), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x7_stitch,stagger(100, 7), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x15, stagger(100, 15)} +intersection_bench! {intersect_stagger_100_vs_x15_future,stagger(100, 15), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x15_search,stagger(100, 15), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x15_spring,stagger(100, 15), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x15_stitch,stagger(100, 15), intersection_stitch} +intersection_bench! {intersect_stagger_100_vs_x16, stagger(100, 16)} +intersection_bench! {intersect_stagger_100_vs_x16_future,stagger(100, 16), intersection_future} +intersection_bench! {intersect_stagger_100_vs_x16_search,stagger(100, 16), intersection_search} +intersection_bench! {intersect_stagger_100_vs_x16_spring,stagger(100, 16), intersection_spring} +intersection_bench! {intersect_stagger_100_vs_x16_stitch,stagger(100, 16), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x5, stagger(200, 5)} +intersection_bench! {intersect_stagger_200_vs_x5_future,stagger(200, 5), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x5_search,stagger(200, 5), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x5_spring,stagger(200, 5), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x5_stitch,stagger(200, 5), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x6, stagger(200, 6)} +intersection_bench! {intersect_stagger_200_vs_x6_future,stagger(200, 6), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x6_search,stagger(200, 6), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x6_spring,stagger(200, 6), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x6_stitch,stagger(200, 6), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x7, stagger(200, 7)} +intersection_bench! {intersect_stagger_200_vs_x7_future,stagger(200, 7), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x7_search,stagger(200, 7), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x7_spring,stagger(200, 7), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x7_stitch,stagger(200, 7), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x8, stagger(200, 8)} +intersection_bench! {intersect_stagger_200_vs_x8_future,stagger(200, 8), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x8_search,stagger(200, 8), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x8_spring,stagger(200, 8), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x8_stitch,stagger(200, 8), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x15, stagger(200, 15)} +intersection_bench! {intersect_stagger_200_vs_x15_future,stagger(200, 15), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x15_search,stagger(200, 15), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x15_spring,stagger(200, 15), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x15_stitch,stagger(200, 15), intersection_stitch} +intersection_bench! {intersect_stagger_200_vs_x16, stagger(200, 16)} +intersection_bench! {intersect_stagger_200_vs_x16_future,stagger(200, 16), intersection_future} +intersection_bench! {intersect_stagger_200_vs_x16_search,stagger(200, 16), intersection_search} +intersection_bench! {intersect_stagger_200_vs_x16_spring,stagger(200, 16), intersection_spring} +intersection_bench! {intersect_stagger_200_vs_x16_stitch,stagger(200, 16), intersection_stitch} +intersection_bench! {intersect_stagger_500_vs_x12, stagger(500, 12)} +intersection_bench! {intersect_stagger_500_vs_x12_future,stagger(500, 12), intersection_future} +intersection_bench! {intersect_stagger_500_vs_x12_search,stagger(500, 12), intersection_search} +intersection_bench! {intersect_stagger_500_vs_x12_spring,stagger(500, 12), intersection_spring} +intersection_bench! {intersect_stagger_500_vs_x12_stitch,stagger(500, 12), intersection_stitch} +intersection_bench! {intersect_stagger_500_vs_x13, stagger(500, 13)} +intersection_bench! {intersect_stagger_500_vs_x13_future,stagger(500, 13), intersection_future} +intersection_bench! {intersect_stagger_500_vs_x13_search,stagger(500, 13), intersection_search} +intersection_bench! {intersect_stagger_500_vs_x13_spring,stagger(500, 13), intersection_spring} +intersection_bench! {intersect_stagger_500_vs_x13_stitch,stagger(500, 13), intersection_stitch} +intersection_bench! {intersect_stagger_500_vs_x14, stagger(500, 14)} +intersection_bench! {intersect_stagger_500_vs_x14_future,stagger(500, 14), intersection_future} +intersection_bench! {intersect_stagger_500_vs_x14_search,stagger(500, 14), intersection_search} +intersection_bench! {intersect_stagger_500_vs_x14_spring,stagger(500, 14), intersection_spring} +intersection_bench! {intersect_stagger_500_vs_x14_stitch,stagger(500, 14), intersection_stitch} +intersection_bench! {intersect_stagger_500_vs_x15, stagger(500, 15)} +intersection_bench! {intersect_stagger_500_vs_x15_future,stagger(500, 15), intersection_future} +intersection_bench! {intersect_stagger_500_vs_x15_search,stagger(500, 15), intersection_search} +intersection_bench! {intersect_stagger_500_vs_x15_spring,stagger(500, 15), intersection_spring} +intersection_bench! {intersect_stagger_500_vs_x15_stitch,stagger(500, 15), intersection_stitch} +intersection_bench! {intersect_stagger_500_vs_x16, stagger(500, 16)} +intersection_bench! {intersect_stagger_500_vs_x16_future,stagger(500, 16), intersection_future} +intersection_bench! {intersect_stagger_500_vs_x16_search,stagger(500, 16), intersection_search} +intersection_bench! {intersect_stagger_500_vs_x16_spring,stagger(500, 16), intersection_spring} +intersection_bench! {intersect_stagger_500_vs_x16_stitch,stagger(500, 16), intersection_stitch} +intersection_bench! {intersect_stagger_1k_vs_x15, stagger(1_000, 15)} +intersection_bench! {intersect_stagger_1k_vs_x15_future,stagger(1_000, 15), intersection_future} +intersection_bench! {intersect_stagger_1k_vs_x15_search,stagger(1_000, 15), intersection_search} +intersection_bench! {intersect_stagger_1k_vs_x15_spring,stagger(1_000, 15), intersection_spring} +intersection_bench! {intersect_stagger_1k_vs_x15_stitch,stagger(1_000, 15), intersection_stitch} +intersection_bench! {intersect_stagger_1k_vs_x16, stagger(1_000, 16)} +intersection_bench! {intersect_stagger_1k_vs_x16_future,stagger(1_000, 16), intersection_future} +intersection_bench! {intersect_stagger_1k_vs_x16_search,stagger(1_000, 16), intersection_search} +intersection_bench! {intersect_stagger_1k_vs_x16_spring,stagger(1_000, 16), intersection_spring} +intersection_bench! {intersect_stagger_1k_vs_x16_stitch,stagger(1_000, 16), intersection_stitch} +intersection_bench! {intersect_stagger_1k_vs_x17, stagger(1_000, 17)} +intersection_bench! {intersect_stagger_1k_vs_x17_future,stagger(1_000, 17), intersection_future} +intersection_bench! {intersect_stagger_1k_vs_x17_search,stagger(1_000, 17), intersection_search} +intersection_bench! {intersect_stagger_1k_vs_x17_spring,stagger(1_000, 17), intersection_spring} +intersection_bench! {intersect_stagger_1k_vs_x17_stitch,stagger(1_000, 17), intersection_stitch} +intersection_bench! {intersect_stagger_1k_vs_x18, stagger(1_000, 18)} +intersection_bench! {intersect_stagger_1k_vs_x18_future,stagger(1_000, 18), intersection_future} +intersection_bench! {intersect_stagger_1k_vs_x18_search,stagger(1_000, 18), intersection_search} +intersection_bench! {intersect_stagger_1k_vs_x18_spring,stagger(1_000, 18), intersection_spring} +intersection_bench! {intersect_stagger_1k_vs_x18_stitch,stagger(1_000, 18), intersection_stitch} +intersection_bench! {intersect_stagger_1k_vs_x19, stagger(1_000, 19)} +intersection_bench! {intersect_stagger_1k_vs_x19_future,stagger(1_000, 19), intersection_future} +intersection_bench! {intersect_stagger_1k_vs_x19_search,stagger(1_000, 19), intersection_search} +intersection_bench! {intersect_stagger_1k_vs_x19_spring,stagger(1_000, 19), intersection_spring} +intersection_bench! {intersect_stagger_1k_vs_x19_stitch,stagger(1_000, 19), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x15, stagger(10_000, 15)} +intersection_bench! {intersect_stagger_10k_vs_x15_future,stagger(10_000, 15), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x15_search,stagger(10_000, 15), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x15_spring,stagger(10_000, 15), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x15_stitch,stagger(10_000, 15), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x16, stagger(10_000, 16)} +intersection_bench! {intersect_stagger_10k_vs_x16_future,stagger(10_000, 16), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x16_search,stagger(10_000, 16), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x16_spring,stagger(10_000, 16), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x16_stitch,stagger(10_000, 16), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x17, stagger(10_000, 17)} +intersection_bench! {intersect_stagger_10k_vs_x17_future,stagger(10_000, 17), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x17_search,stagger(10_000, 17), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x17_spring,stagger(10_000, 17), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x17_stitch,stagger(10_000, 17), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x18, stagger(10_000, 18)} +intersection_bench! {intersect_stagger_10k_vs_x18_future,stagger(10_000, 18), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x18_search,stagger(10_000, 18), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x18_spring,stagger(10_000, 18), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x18_stitch,stagger(10_000, 18), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x19, stagger(10_000, 19)} +intersection_bench! {intersect_stagger_10k_vs_x19_future,stagger(10_000, 19), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x19_search,stagger(10_000, 19), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x19_spring,stagger(10_000, 19), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x19_stitch,stagger(10_000, 19), intersection_stitch} +intersection_bench! {intersect_stagger_10k_vs_x20, stagger(10_000, 20)} +intersection_bench! {intersect_stagger_10k_vs_x20_future,stagger(10_000, 20), intersection_future} +intersection_bench! {intersect_stagger_10k_vs_x20_search,stagger(10_000, 20), intersection_search} +intersection_bench! {intersect_stagger_10k_vs_x20_spring,stagger(10_000, 20), intersection_spring} +intersection_bench! {intersect_stagger_10k_vs_x20_stitch,stagger(10_000, 20), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x15, stagger(100_000, 15)} +intersection_bench! {intersect_stagger_100k_vs_x15_future,stagger(100_000, 15), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x15_search,stagger(100_000, 15), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x15_spring,stagger(100_000, 15), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x15_stitch,stagger(100_000, 15), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x16, stagger(100_000, 16)} +intersection_bench! {intersect_stagger_100k_vs_x16_future,stagger(100_000, 16), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x16_search,stagger(100_000, 16), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x16_spring,stagger(100_000, 16), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x16_stitch,stagger(100_000, 16), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x17, stagger(100_000, 17)} +intersection_bench! {intersect_stagger_100k_vs_x17_future,stagger(100_000, 17), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x17_search,stagger(100_000, 17), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x17_spring,stagger(100_000, 17), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x17_stitch,stagger(100_000, 17), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x18, stagger(100_000, 18)} +intersection_bench! {intersect_stagger_100k_vs_x18_future,stagger(100_000, 18), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x18_search,stagger(100_000, 18), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x18_spring,stagger(100_000, 18), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x18_stitch,stagger(100_000, 18), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x19, stagger(100_000, 19)} +intersection_bench! {intersect_stagger_100k_vs_x19_future,stagger(100_000, 19), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x19_search,stagger(100_000, 19), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x19_spring,stagger(100_000, 19), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x19_stitch,stagger(100_000, 19), intersection_stitch} +intersection_bench! {intersect_stagger_100k_vs_x20, stagger(100_000, 20)} +intersection_bench! {intersect_stagger_100k_vs_x20_future,stagger(100_000, 20), intersection_future} +intersection_bench! {intersect_stagger_100k_vs_x20_search,stagger(100_000, 20), intersection_search} +intersection_bench! {intersect_stagger_100k_vs_x20_spring,stagger(100_000, 20), intersection_spring} +intersection_bench! {intersect_stagger_100k_vs_x20_stitch,stagger(100_000, 20), intersection_stitch} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d7e5255 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod set; diff --git a/src/set.rs b/src/set.rs new file mode 100644 index 0000000..c8d26d0 --- /dev/null +++ b/src/set.rs @@ -0,0 +1,174 @@ +// file comparable to rust/src/liballoc/collections/btree/set.rs + +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::collections::btree_set::{Iter, Range}; +use std::collections::BTreeSet; + +pub struct Intersection<'a, T: 'a> { + inner: IntersectionInner<'a, T>, +} +#[derive(Debug)] +enum IntersectionInner<'a, T: 'a> { + Stitch { + small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets + other_iter: Iter<'a, T>, + }, + Spring { + small_range: Range<'a, T>, + small_set: &'a BTreeSet, + other_range: Range<'a, T>, + other_set: &'a BTreeSet, + }, + Search { + small_iter: Iter<'a, T>, + large_set: &'a BTreeSet, + }, +} + +impl<'a, T: Ord> Iterator for Intersection<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + match &mut self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => { + let mut small_next = small_iter.next()?; + let mut other_next = other_iter.next()?; + loop { + match Ord::cmp(small_next, other_next) { + Less => small_next = small_iter.next()?, + Greater => other_next = other_iter.next()?, + Equal => return Some(small_next), + } + } + } + IntersectionInner::Spring { + small_range, + small_set, + other_range, + other_set, + } => { + const NEXT_COUNT_MAX: usize = 1; + let mut next_count: usize = 0; + let mut small_next = small_range.next()?; + let mut other_next = other_range.next()?; + loop { + match Ord::cmp(small_next, other_next) { + Less => { + next_count += 1; + if next_count > NEXT_COUNT_MAX { + next_count = 0; + *small_range = small_set.range(other_next..); + } + small_next = small_range.next()?; + } + Greater => { + next_count += 1; + if next_count > NEXT_COUNT_MAX { + next_count = 0; + *other_range = other_set.range(small_next..); + } + other_next = other_range.next()?; + } + Equal => return Some(small_next), + } + } + } + IntersectionInner::Search { + small_iter, + large_set, + } => loop { + let small_next = small_iter.next()?; + if large_set.contains(&small_next) { + return Some(small_next); + } + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + let upper_bound = match &self.inner { + IntersectionInner::Stitch { small_iter, .. } => small_iter.len(), + IntersectionInner::Spring { small_set, .. } => small_set.len(), + IntersectionInner::Search { small_iter, .. } => small_iter.len(), + }; + (0, Some(upper_bound)) + } +} + +pub fn intersection_future<'a, T: Ord>( + selv: &'a BTreeSet, + other: &'a BTreeSet, +) -> Intersection<'a, T> { + let (small, other) = if selv.len() <= other.len() { + (selv, other) + } else { + (other, selv) + }; + Intersection { + inner: + // The following rule: + // - is based on the benchmarks in + // https://github.com/ssomers/rust_bench_btreeset_intersection; + // - divides, rather than multiplies, to rule out overflow; + // - avoids creating a second iterator if one of the sets is empty. + if small.len() > other.len() / 16 { + // Small set is not much smaller than other set, so iterate + // both sets jointly, spotting matches along the way. + IntersectionInner::Stitch { + small_iter: small.iter(), + other_iter: other.iter(), + } + } else { + // Big difference in number of elements, so iterate the small set, + // searching for matches in the large set. + IntersectionInner::Search { + small_iter: small.iter(), + large_set: other, + } + }, + } +} + +pub fn intersection_search<'a, T: Ord>( + small: &'a BTreeSet, + large: &'a BTreeSet, +) -> Intersection<'a, T> { + debug_assert!(small.len() <= large.len()); + Intersection { + inner: IntersectionInner::Search { + small_iter: small.iter(), + large_set: &large, + }, + } +} + +pub fn intersection_spring<'a, T: Ord>( + small: &'a BTreeSet, + other: &'a BTreeSet, +) -> Intersection<'a, T> { + debug_assert!(small.len() <= other.len()); + Intersection { + inner: IntersectionInner::Spring { + small_range: small.range(..), + small_set: &small, + other_range: other.range(..), + other_set: &other, + }, + } +} + +pub fn intersection_stitch<'a, T: Ord>( + small: &'a BTreeSet, + other: &'a BTreeSet, +) -> Intersection<'a, T> { + debug_assert!(small.len() <= other.len()); + Intersection { + inner: IntersectionInner::Stitch { + small_iter: small.iter(), + other_iter: other.iter(), + }, + } +} diff --git a/src/tests/set.rs b/src/tests/set.rs new file mode 100644 index 0000000..ddcc61b --- /dev/null +++ b/src/tests/set.rs @@ -0,0 +1,71 @@ +extern crate proptest; +extern crate rand; +extern crate rand_xorshift; +use self::proptest::prelude::*; +use self::rand::Rng; +use self::rand::SeedableRng; +use self::rand_xorshift::XorShiftRng; +use ::rust_bench_btreeset_intersection::set::*; +use std::collections::BTreeSet; + +fn random_set(size: usize, ovule: u8) -> BTreeSet { + let mut rng = XorShiftRng::from_seed([ovule; 16]); + let mut s = BTreeSet::::new(); + while s.len() < size { + s.insert(rng.gen()); + } + s +} +fn assert_intersection<'a, I: Iterator>( + it: I, + s1: &'a BTreeSet, + s2: &'a BTreeSet, +) -> Result<(), TestCaseError> { + let mut collected = BTreeSet::::new(); + for elt in it { + prop_assert!(s1.contains(elt)); + prop_assert!(s2.contains(elt)); + prop_assert!(collected.insert(*elt)); + } + for elt in s1 { + prop_assert_eq!(collected.contains(elt), s2.contains(elt)); + } + for elt in s2 { + prop_assert_eq!(collected.contains(elt), s1.contains(elt)); + } + Ok(()) +} + +proptest! { + #[test] + fn test_intersection_future(len1 in 0..1000usize, len2 in 0..1000usize) { + prop_assume!(len1 <= len2); + let s1 = random_set(len1, 11u8); + let s2 = random_set(len2, 22u8); + assert_intersection(intersection_future(&s1, &s2), &s1, &s2)? + } + + #[test] + fn test_intersection_search(len1 in 0..1000usize, len2 in 0..1000usize) { + prop_assume!(len1 <= len2); + let s1 = random_set(len1, 11u8); + let s2 = random_set(len2, 22u8); + assert_intersection(intersection_search(&s1, &s2), &s1, &s2)? + } + + #[test] + fn test_intersection_spring(len1 in 0..1000usize, len2 in 0..1000usize) { + prop_assume!(len1 <= len2); + let s1 = random_set(len1, 11u8); + let s2 = random_set(len2, 22u8); + assert_intersection(intersection_spring(&s1, &s2), &s1, &s2)? + } + + #[test] + fn test_intersection_stitch(len1 in 0..1000usize, len2 in 0..1000usize) { + prop_assume!(len1 <= len2); + let s1 = random_set(len1, 11u8); + let s2 = random_set(len2, 22u8); + assert_intersection(intersection_stitch(&s1, &s2), &s1, &s2)? + } +}