Skip to main content

SplittableTreap

Struct SplittableTreap 

Source
pub struct SplittableTreap<K, V> { /* private fields */ }

Implementations§

Source§

impl<K: Ord, V> SplittableTreap<K, V>

Source

pub fn new(seed: u64) -> Self

Examples found in repository?
examples/sample_app.rs (line 250)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
More examples
Hide additional examples
examples/perf_features.rs (line 165)
95fn main() -> io::Result<()> {
96    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
97        .join("..")
98        .join(".subms")
99        .join("features")
100        .join("rust.json");
101    let existing = std::fs::read_to_string(&path).unwrap_or_default();
102    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
103    // Stamp the box these numbers came from. The bench runs wherever it is
104    // invoked, so an unstamped manifest is indistinguishable from a fleet
105    // capture; the renderer will not publish one it cannot attribute.
106    let (source, instance) = SubMsP99Source::from_env();
107    manifest.set_p99_source(source, instance.as_deref());
108
109    // The baseline: a base-treap lookup at the canonical size. A feature landing
110    // at or under this costs nothing on the read path.
111    let base = build(CANON);
112    let base_p50 = keyed(CANON, |i| _ = base.get(&key_at(i)), true);
113    eprintln!("base get p50: {base_p50}ns");
114
115    // ---------- persistent: path-copying insert, old version stays valid ----------
116    #[cfg(feature = "persistent")]
117    {
118        use subms_treap::PersistentTreap;
119        // `insert` returns a NEW treap sharing everything off the copied path,
120        // so the cost is the path length - O(log n), which should read flat.
121        let sw = sweep("persistent/insert", |n| {
122            let mut p = PersistentTreap::new(SEED);
123            for i in 0..n {
124                p = p.insert(key_at(i), i as u64);
125            }
126            keyed(n, |i| _ = p.insert(key_at(i), i as u64), true)
127        });
128        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
129
130        let mut p = PersistentTreap::new(SEED);
131        for i in 0..CANON {
132            p = p.insert(key_at(i), i as u64);
133        }
134        let mut p99 = BTreeMap::new();
135        p99.insert(
136            "insert".to_string(),
137            keyed(CANON, |i| _ = p.insert(key_at(i), i as u64), false),
138        );
139        p99.insert(
140            "get".to_string(),
141            keyed(CANON, |i| _ = p.get(&key_at(i)), false),
142        );
143        p99.insert(
144            "remove".to_string(),
145            keyed(CANON, |i| _ = p.remove(&key_at(i)), false),
146        );
147        manifest.set_feature("persistent", cat, &p99, &reason);
148    }
149
150    // ---------- merge-split: split at a pivot, merge two ordered halves ----------
151    #[cfg(feature = "merge-split")]
152    {
153        use subms_treap::SplittableTreap;
154        // Timed as a split-then-merge ROUND TRIP, because `split` consumes the
155        // treap: rebuilding one per rep would put an O(n log n) build inside the
156        // timed region and the figure would be the build. A round trip restores
157        // the original, so the input is set up once and every rep does identical
158        // work.
159        //
160        // The sweep classifies this structural, and the reason is in `split`
161        // rather than in `split_node`: the descent is O(log n), but split then
162        // calls `count()` on BOTH halves to fill in their lengths, and that is a
163        // full traversal. An O(log n) op with an O(n) bookkeeping tail.
164        let make = |n: usize| {
165            let mut t = SplittableTreap::new(SEED);
166            for i in 0..n {
167                t.insert(key_at(i), i as u64);
168            }
169            Some(t)
170        };
171        let round_trip = |slot: &mut Option<SplittableTreap<u64, u64>>| {
172            let t = slot.take().expect("round trip restores the treap");
173            let (l, r) = t.split(&(KEY_SPACE / 2));
174            *slot = Some(SplittableTreap::merge(l, r));
175        };
176        let sw = sweep("merge-split/split+merge", |n| {
177            bulk(|| make(n), round_trip, true)
178        });
179        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
180
181        let mut p99 = BTreeMap::new();
182        p99.insert(
183            "split_merge".to_string(),
184            bulk(|| make(CANON), round_trip, false),
185        );
186        manifest.set_feature("merge-split", cat, &p99, &reason);
187    }
188
189    // ---------- concurrent-reads: a flattened immutable snapshot ----------
190    #[cfg(feature = "concurrent-reads")]
191    {
192        use subms_treap::TreapSnapshot;
193        // `from_treap` flattens the tree into a sorted Vec, so it is O(n) and the
194        // sweep says so. Lookups on the result are a binary search over that Vec,
195        // which is the point: readers pay O(log n) with no tree pointers and no
196        // coordination with the writer.
197        let sw = sweep("concurrent-reads/snapshot", |n| {
198            let t = build(n);
199            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), true)
200        });
201        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
202
203        let t = build(CANON);
204        let snap = TreapSnapshot::from_treap(&t);
205        let mut p99 = BTreeMap::new();
206        p99.insert(
207            "snapshot".to_string(),
208            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), false),
209        );
210        p99.insert(
211            "lookup_on_snapshot".to_string(),
212            keyed(CANON, |i| _ = snap.get(&key_at(i)), false),
213        );
214        manifest.set_feature("concurrent-reads", cat, &p99, &reason);
215    }
216
217    std::fs::create_dir_all(path.parent().unwrap())?;
218    std::fs::write(&path, manifest.to_json())?;
219    io::stdout().write_all(manifest.to_json().as_bytes())?;
220    Ok(())
221}
Source

pub fn len(&self) -> usize

Examples found in repository?
examples/sample_app.rs (line 267)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
Source

pub fn is_empty(&self) -> bool

Source

pub fn insert(&mut self, key: K, value: V) -> Option<V>

Examples found in repository?
examples/sample_app.rs (line 259)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
More examples
Hide additional examples
examples/perf_features.rs (line 167)
95fn main() -> io::Result<()> {
96    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
97        .join("..")
98        .join(".subms")
99        .join("features")
100        .join("rust.json");
101    let existing = std::fs::read_to_string(&path).unwrap_or_default();
102    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
103    // Stamp the box these numbers came from. The bench runs wherever it is
104    // invoked, so an unstamped manifest is indistinguishable from a fleet
105    // capture; the renderer will not publish one it cannot attribute.
106    let (source, instance) = SubMsP99Source::from_env();
107    manifest.set_p99_source(source, instance.as_deref());
108
109    // The baseline: a base-treap lookup at the canonical size. A feature landing
110    // at or under this costs nothing on the read path.
111    let base = build(CANON);
112    let base_p50 = keyed(CANON, |i| _ = base.get(&key_at(i)), true);
113    eprintln!("base get p50: {base_p50}ns");
114
115    // ---------- persistent: path-copying insert, old version stays valid ----------
116    #[cfg(feature = "persistent")]
117    {
118        use subms_treap::PersistentTreap;
119        // `insert` returns a NEW treap sharing everything off the copied path,
120        // so the cost is the path length - O(log n), which should read flat.
121        let sw = sweep("persistent/insert", |n| {
122            let mut p = PersistentTreap::new(SEED);
123            for i in 0..n {
124                p = p.insert(key_at(i), i as u64);
125            }
126            keyed(n, |i| _ = p.insert(key_at(i), i as u64), true)
127        });
128        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
129
130        let mut p = PersistentTreap::new(SEED);
131        for i in 0..CANON {
132            p = p.insert(key_at(i), i as u64);
133        }
134        let mut p99 = BTreeMap::new();
135        p99.insert(
136            "insert".to_string(),
137            keyed(CANON, |i| _ = p.insert(key_at(i), i as u64), false),
138        );
139        p99.insert(
140            "get".to_string(),
141            keyed(CANON, |i| _ = p.get(&key_at(i)), false),
142        );
143        p99.insert(
144            "remove".to_string(),
145            keyed(CANON, |i| _ = p.remove(&key_at(i)), false),
146        );
147        manifest.set_feature("persistent", cat, &p99, &reason);
148    }
149
150    // ---------- merge-split: split at a pivot, merge two ordered halves ----------
151    #[cfg(feature = "merge-split")]
152    {
153        use subms_treap::SplittableTreap;
154        // Timed as a split-then-merge ROUND TRIP, because `split` consumes the
155        // treap: rebuilding one per rep would put an O(n log n) build inside the
156        // timed region and the figure would be the build. A round trip restores
157        // the original, so the input is set up once and every rep does identical
158        // work.
159        //
160        // The sweep classifies this structural, and the reason is in `split`
161        // rather than in `split_node`: the descent is O(log n), but split then
162        // calls `count()` on BOTH halves to fill in their lengths, and that is a
163        // full traversal. An O(log n) op with an O(n) bookkeeping tail.
164        let make = |n: usize| {
165            let mut t = SplittableTreap::new(SEED);
166            for i in 0..n {
167                t.insert(key_at(i), i as u64);
168            }
169            Some(t)
170        };
171        let round_trip = |slot: &mut Option<SplittableTreap<u64, u64>>| {
172            let t = slot.take().expect("round trip restores the treap");
173            let (l, r) = t.split(&(KEY_SPACE / 2));
174            *slot = Some(SplittableTreap::merge(l, r));
175        };
176        let sw = sweep("merge-split/split+merge", |n| {
177            bulk(|| make(n), round_trip, true)
178        });
179        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
180
181        let mut p99 = BTreeMap::new();
182        p99.insert(
183            "split_merge".to_string(),
184            bulk(|| make(CANON), round_trip, false),
185        );
186        manifest.set_feature("merge-split", cat, &p99, &reason);
187    }
188
189    // ---------- concurrent-reads: a flattened immutable snapshot ----------
190    #[cfg(feature = "concurrent-reads")]
191    {
192        use subms_treap::TreapSnapshot;
193        // `from_treap` flattens the tree into a sorted Vec, so it is O(n) and the
194        // sweep says so. Lookups on the result are a binary search over that Vec,
195        // which is the point: readers pay O(log n) with no tree pointers and no
196        // coordination with the writer.
197        let sw = sweep("concurrent-reads/snapshot", |n| {
198            let t = build(n);
199            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), true)
200        });
201        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
202
203        let t = build(CANON);
204        let snap = TreapSnapshot::from_treap(&t);
205        let mut p99 = BTreeMap::new();
206        p99.insert(
207            "snapshot".to_string(),
208            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), false),
209        );
210        p99.insert(
211            "lookup_on_snapshot".to_string(),
212            keyed(CANON, |i| _ = snap.get(&key_at(i)), false),
213        );
214        manifest.set_feature("concurrent-reads", cat, &p99, &reason);
215    }
216
217    std::fs::create_dir_all(path.parent().unwrap())?;
218    std::fs::write(&path, manifest.to_json())?;
219    io::stdout().write_all(manifest.to_json().as_bytes())?;
220    Ok(())
221}
Source

pub fn get(&self, key: &K) -> Option<&V>

Source

pub fn split(self, pivot: &K) -> (Self, Self)

Consume self and split into (left, right) where every key in left is strictly less than pivot and every key in right is greater-than-or-equal-to pivot.

Examples found in repository?
examples/sample_app.rs (line 264)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
More examples
Hide additional examples
examples/perf_features.rs (line 173)
95fn main() -> io::Result<()> {
96    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
97        .join("..")
98        .join(".subms")
99        .join("features")
100        .join("rust.json");
101    let existing = std::fs::read_to_string(&path).unwrap_or_default();
102    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
103    // Stamp the box these numbers came from. The bench runs wherever it is
104    // invoked, so an unstamped manifest is indistinguishable from a fleet
105    // capture; the renderer will not publish one it cannot attribute.
106    let (source, instance) = SubMsP99Source::from_env();
107    manifest.set_p99_source(source, instance.as_deref());
108
109    // The baseline: a base-treap lookup at the canonical size. A feature landing
110    // at or under this costs nothing on the read path.
111    let base = build(CANON);
112    let base_p50 = keyed(CANON, |i| _ = base.get(&key_at(i)), true);
113    eprintln!("base get p50: {base_p50}ns");
114
115    // ---------- persistent: path-copying insert, old version stays valid ----------
116    #[cfg(feature = "persistent")]
117    {
118        use subms_treap::PersistentTreap;
119        // `insert` returns a NEW treap sharing everything off the copied path,
120        // so the cost is the path length - O(log n), which should read flat.
121        let sw = sweep("persistent/insert", |n| {
122            let mut p = PersistentTreap::new(SEED);
123            for i in 0..n {
124                p = p.insert(key_at(i), i as u64);
125            }
126            keyed(n, |i| _ = p.insert(key_at(i), i as u64), true)
127        });
128        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
129
130        let mut p = PersistentTreap::new(SEED);
131        for i in 0..CANON {
132            p = p.insert(key_at(i), i as u64);
133        }
134        let mut p99 = BTreeMap::new();
135        p99.insert(
136            "insert".to_string(),
137            keyed(CANON, |i| _ = p.insert(key_at(i), i as u64), false),
138        );
139        p99.insert(
140            "get".to_string(),
141            keyed(CANON, |i| _ = p.get(&key_at(i)), false),
142        );
143        p99.insert(
144            "remove".to_string(),
145            keyed(CANON, |i| _ = p.remove(&key_at(i)), false),
146        );
147        manifest.set_feature("persistent", cat, &p99, &reason);
148    }
149
150    // ---------- merge-split: split at a pivot, merge two ordered halves ----------
151    #[cfg(feature = "merge-split")]
152    {
153        use subms_treap::SplittableTreap;
154        // Timed as a split-then-merge ROUND TRIP, because `split` consumes the
155        // treap: rebuilding one per rep would put an O(n log n) build inside the
156        // timed region and the figure would be the build. A round trip restores
157        // the original, so the input is set up once and every rep does identical
158        // work.
159        //
160        // The sweep classifies this structural, and the reason is in `split`
161        // rather than in `split_node`: the descent is O(log n), but split then
162        // calls `count()` on BOTH halves to fill in their lengths, and that is a
163        // full traversal. An O(log n) op with an O(n) bookkeeping tail.
164        let make = |n: usize| {
165            let mut t = SplittableTreap::new(SEED);
166            for i in 0..n {
167                t.insert(key_at(i), i as u64);
168            }
169            Some(t)
170        };
171        let round_trip = |slot: &mut Option<SplittableTreap<u64, u64>>| {
172            let t = slot.take().expect("round trip restores the treap");
173            let (l, r) = t.split(&(KEY_SPACE / 2));
174            *slot = Some(SplittableTreap::merge(l, r));
175        };
176        let sw = sweep("merge-split/split+merge", |n| {
177            bulk(|| make(n), round_trip, true)
178        });
179        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
180
181        let mut p99 = BTreeMap::new();
182        p99.insert(
183            "split_merge".to_string(),
184            bulk(|| make(CANON), round_trip, false),
185        );
186        manifest.set_feature("merge-split", cat, &p99, &reason);
187    }
188
189    // ---------- concurrent-reads: a flattened immutable snapshot ----------
190    #[cfg(feature = "concurrent-reads")]
191    {
192        use subms_treap::TreapSnapshot;
193        // `from_treap` flattens the tree into a sorted Vec, so it is O(n) and the
194        // sweep says so. Lookups on the result are a binary search over that Vec,
195        // which is the point: readers pay O(log n) with no tree pointers and no
196        // coordination with the writer.
197        let sw = sweep("concurrent-reads/snapshot", |n| {
198            let t = build(n);
199            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), true)
200        });
201        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
202
203        let t = build(CANON);
204        let snap = TreapSnapshot::from_treap(&t);
205        let mut p99 = BTreeMap::new();
206        p99.insert(
207            "snapshot".to_string(),
208            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), false),
209        );
210        p99.insert(
211            "lookup_on_snapshot".to_string(),
212            keyed(CANON, |i| _ = snap.get(&key_at(i)), false),
213        );
214        manifest.set_feature("concurrent-reads", cat, &p99, &reason);
215    }
216
217    std::fs::create_dir_all(path.parent().unwrap())?;
218    std::fs::write(&path, manifest.to_json())?;
219    io::stdout().write_all(manifest.to_json().as_bytes())?;
220    Ok(())
221}
Source

pub fn merge(left: Self, right: Self) -> Self

Consume left and right and produce a single treap. Every key in left must be strictly less than every key in right or the resulting BST invariant is violated.

Examples found in repository?
examples/sample_app.rs (line 276)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
More examples
Hide additional examples
examples/perf_features.rs (line 174)
95fn main() -> io::Result<()> {
96    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
97        .join("..")
98        .join(".subms")
99        .join("features")
100        .join("rust.json");
101    let existing = std::fs::read_to_string(&path).unwrap_or_default();
102    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
103    // Stamp the box these numbers came from. The bench runs wherever it is
104    // invoked, so an unstamped manifest is indistinguishable from a fleet
105    // capture; the renderer will not publish one it cannot attribute.
106    let (source, instance) = SubMsP99Source::from_env();
107    manifest.set_p99_source(source, instance.as_deref());
108
109    // The baseline: a base-treap lookup at the canonical size. A feature landing
110    // at or under this costs nothing on the read path.
111    let base = build(CANON);
112    let base_p50 = keyed(CANON, |i| _ = base.get(&key_at(i)), true);
113    eprintln!("base get p50: {base_p50}ns");
114
115    // ---------- persistent: path-copying insert, old version stays valid ----------
116    #[cfg(feature = "persistent")]
117    {
118        use subms_treap::PersistentTreap;
119        // `insert` returns a NEW treap sharing everything off the copied path,
120        // so the cost is the path length - O(log n), which should read flat.
121        let sw = sweep("persistent/insert", |n| {
122            let mut p = PersistentTreap::new(SEED);
123            for i in 0..n {
124                p = p.insert(key_at(i), i as u64);
125            }
126            keyed(n, |i| _ = p.insert(key_at(i), i as u64), true)
127        });
128        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
129
130        let mut p = PersistentTreap::new(SEED);
131        for i in 0..CANON {
132            p = p.insert(key_at(i), i as u64);
133        }
134        let mut p99 = BTreeMap::new();
135        p99.insert(
136            "insert".to_string(),
137            keyed(CANON, |i| _ = p.insert(key_at(i), i as u64), false),
138        );
139        p99.insert(
140            "get".to_string(),
141            keyed(CANON, |i| _ = p.get(&key_at(i)), false),
142        );
143        p99.insert(
144            "remove".to_string(),
145            keyed(CANON, |i| _ = p.remove(&key_at(i)), false),
146        );
147        manifest.set_feature("persistent", cat, &p99, &reason);
148    }
149
150    // ---------- merge-split: split at a pivot, merge two ordered halves ----------
151    #[cfg(feature = "merge-split")]
152    {
153        use subms_treap::SplittableTreap;
154        // Timed as a split-then-merge ROUND TRIP, because `split` consumes the
155        // treap: rebuilding one per rep would put an O(n log n) build inside the
156        // timed region and the figure would be the build. A round trip restores
157        // the original, so the input is set up once and every rep does identical
158        // work.
159        //
160        // The sweep classifies this structural, and the reason is in `split`
161        // rather than in `split_node`: the descent is O(log n), but split then
162        // calls `count()` on BOTH halves to fill in their lengths, and that is a
163        // full traversal. An O(log n) op with an O(n) bookkeeping tail.
164        let make = |n: usize| {
165            let mut t = SplittableTreap::new(SEED);
166            for i in 0..n {
167                t.insert(key_at(i), i as u64);
168            }
169            Some(t)
170        };
171        let round_trip = |slot: &mut Option<SplittableTreap<u64, u64>>| {
172            let t = slot.take().expect("round trip restores the treap");
173            let (l, r) = t.split(&(KEY_SPACE / 2));
174            *slot = Some(SplittableTreap::merge(l, r));
175        };
176        let sw = sweep("merge-split/split+merge", |n| {
177            bulk(|| make(n), round_trip, true)
178        });
179        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
180
181        let mut p99 = BTreeMap::new();
182        p99.insert(
183            "split_merge".to_string(),
184            bulk(|| make(CANON), round_trip, false),
185        );
186        manifest.set_feature("merge-split", cat, &p99, &reason);
187    }
188
189    // ---------- concurrent-reads: a flattened immutable snapshot ----------
190    #[cfg(feature = "concurrent-reads")]
191    {
192        use subms_treap::TreapSnapshot;
193        // `from_treap` flattens the tree into a sorted Vec, so it is O(n) and the
194        // sweep says so. Lookups on the result are a binary search over that Vec,
195        // which is the point: readers pay O(log n) with no tree pointers and no
196        // coordination with the writer.
197        let sw = sweep("concurrent-reads/snapshot", |n| {
198            let t = build(n);
199            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), true)
200        });
201        let (cat, reason) = classify_feature(&sw, Some(base_p50), None);
202
203        let t = build(CANON);
204        let snap = TreapSnapshot::from_treap(&t);
205        let mut p99 = BTreeMap::new();
206        p99.insert(
207            "snapshot".to_string(),
208            bulk(|| (), |()| _ = TreapSnapshot::from_treap(&t), false),
209        );
210        p99.insert(
211            "lookup_on_snapshot".to_string(),
212            keyed(CANON, |i| _ = snap.get(&key_at(i)), false),
213        );
214        manifest.set_feature("concurrent-reads", cat, &p99, &reason);
215    }
216
217    std::fs::create_dir_all(path.parent().unwrap())?;
218    std::fs::write(&path, manifest.to_json())?;
219    io::stdout().write_all(manifest.to_json().as_bytes())?;
220    Ok(())
221}
Source

pub fn collect_in_order(&self) -> Vec<(&K, &V)>

Examples found in repository?
examples/sample_app.rs (line 272)
247fn partition_ladder() {
248    use subms_treap::SplittableTreap;
249    println!("\n== merge-split: partition at the touch ==");
250    let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251    for (px, qty) in [
252        (9_996u32, 600u64),
253        (9_998, 1_000),
254        (9_999, 250),
255        (10_000, 650),
256        (10_001, 900),
257        (10_002, 400),
258    ] {
259        book.insert(px, qty);
260    }
261
262    // Everything strictly below 10000 is the resting book; 10000 and above is
263    // the band a marketable order would clear against.
264    let (resting, marketable) = book.split(&10_000);
265    println!(
266        "  below 10000: {} levels | 10000 and up: {} levels",
267        resting.len(),
268        marketable.len()
269    );
270    assert_eq!((resting.len(), marketable.len()), (3, 3));
271    assert_eq!(
272        marketable.collect_in_order().first().map(|(k, _)| **k),
273        Some(10_000)
274    );
275
276    let rejoined = SplittableTreap::merge(resting, marketable);
277    let keys: Vec<u32> = rejoined
278        .collect_in_order()
279        .into_iter()
280        .map(|(k, _)| *k)
281        .collect();
282    println!("  rejoined: {keys:?}");
283    assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}

Auto Trait Implementations§

§

impl<K, V> Freeze for SplittableTreap<K, V>

§

impl<K, V> RefUnwindSafe for SplittableTreap<K, V>

§

impl<K, V> Send for SplittableTreap<K, V>
where K: Send, V: Send,

§

impl<K, V> Sync for SplittableTreap<K, V>
where K: Sync, V: Sync,

§

impl<K, V> Unpin for SplittableTreap<K, V>

§

impl<K, V> UnsafeUnpin for SplittableTreap<K, V>

§

impl<K, V> UnwindSafe for SplittableTreap<K, V>
where K: UnwindSafe, V: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.