Skip to main content

Treap

Struct Treap 

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

Implementations§

Source§

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

Source

pub fn range<'a>( &'a self, from: RangeBound<'a, K>, to: RangeBound<'a, K>, ) -> RangeIter<'a, K, V>

Iterate every (&K, &V) with from <= key <= to (or whichever inclusion shape the bounds declare), in ascending key order.

Examples found in repository?
examples/sample_app.rs (line 192)
186fn band_depth() {
187    use subms_treap::RangeBound;
188    println!("\n== range-query: depth in a price band ==");
189    let book = build_book();
190    let (lo, hi) = (9_996u32, 10_000u32);
191    let band: Vec<(u32, u64)> = book
192        .range(RangeBound::Inclusive(&lo), RangeBound::Inclusive(&hi))
193        .map(|(k, v)| (*k, *v))
194        .collect();
195    let depth: u64 = band.iter().map(|(_, q)| *q).sum();
196    println!("  [{lo}, {hi}] -> {} levels, {depth} lots", band.len());
197    assert_eq!(
198        band.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
199        vec![9_996, 9_998, 9_999, 10_000]
200    );
201    assert_eq!(depth, 2_500);
202
203    // Exclusive upper bound drops the touch itself.
204    let inside: u64 = book
205        .range(RangeBound::Inclusive(&lo), RangeBound::Exclusive(&hi))
206        .map(|(_, q)| *q)
207        .sum();
208    println!("  same band, exclusive of {hi}: {inside} lots");
209    assert_eq!(inside, 1_850);
210}
Source§

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

Source

pub fn new(seed: u64) -> Self

Examples found in repository?
examples/perf_features.rs (line 44)
43fn build(n: usize) -> Treap<u64, u64> {
44    let mut t = Treap::new(SEED);
45    for i in 0..n {
46        t.insert(key_at(i), i as u64);
47    }
48    t
49}
More examples
Hide additional examples
examples/sample_app.rs (line 294)
290fn published_snapshot() {
291    use std::thread;
292    use subms_treap::TreapSnapshot;
293    println!("\n== concurrent-reads: published book snapshot ==");
294    let mut book: Treap<u32, u64> = Treap::new(SEED);
295    for px in 9_990..10_010u32 {
296        book.insert(px, (px as u64) * 10);
297    }
298    let snap = TreapSnapshot::from_treap(&book);
299
300    let readers: Vec<_> = (0..4)
301        .map(|_| {
302            let s = snap.clone();
303            thread::spawn(move || s.range(&9_995, &10_004).count())
304        })
305        .collect();
306
307    // Writer churn after the snapshot: readers must not observe it.
308    book.insert(12_345, 1);
309    book.remove(&9_990);
310
311    for r in readers {
312        assert_eq!(
313            r.join().unwrap(),
314            10,
315            "reader sees the frozen 10-level band"
316        );
317    }
318    println!("  4 readers each counted 10 levels in [9995, 10004]");
319    assert!(
320        snap.get(&12_345).is_none(),
321        "snapshot isolated from later writes"
322    );
323    assert_eq!(snap.len(), 20);
324}
Source

pub fn with_capacity(seed: u64, capacity: usize) -> Self

Construct with capacity pre-allocated. Use when an upper bound on the working set is known: avoids the doubling-vec growth path during the first burst of inserts.

Examples found in repository?
examples/sample_app.rs (line 79)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
Source

pub fn from_entropy() -> Self

Seed the priority stream from the OS rather than from a constant.

The default constructor takes an explicit seed because a reproducible tree shape is what makes a benchmark and a bug report mean anything. That same property is a liability when an attacker can both choose the keys and observe the latency: the priority sequence is then known, and a chosen key order can force the spine the randomized bound rules out. Reach for this when the key stream is untrusted, and accept that two runs no longer produce the same tree.

Source

pub fn from_sorted( seed: u64, items: impl IntoIterator<Item = (K, V)>, ) -> Result<Self, TreapError>

Build from already-sorted input in O(n), skipping the n rotating inserts a naive rebuild would pay.

Keys must be strictly ascending; duplicates are rejected rather than collapsed, because silently dropping one of two entries is the wrong answer for every workload that reaches for this. Pairs with Treap::collect_in_order as a snapshot / restore round trip.

use subms_treap::Treap;
let t = Treap::from_sorted(1, [(1u32, "a"), (2, "b"), (3, "c")]).unwrap();
assert_eq!(t.len(), 3);
assert_eq!(t.get(&2).copied(), Some("b"));
Examples found in repository?
examples/sample_app.rs (line 168)
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
Source

pub fn len(&self) -> usize

Examples found in repository?
examples/sample_app.rs (line 74)
71fn apply_tape() -> Treap<u32, u64> {
72    println!("== bid-side depth book ==");
73    let book = build_book();
74    println!("  applied {} events -> {} levels", TAPE.len(), book.len());
75    book
76}
77
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
104
105/// Read the book the way a trader does: best price first, then the touch and
106/// its neighbours. `iter_rev` walks the ladder high to low; `floor` and
107/// `predecessor` answer "what is at or below this price" without a scan.
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137/// Sweep an aggressive sell through the bid side. `pop_last` takes the best
138/// level in expected O(log n) and hands back both key and value, so the fill
139/// loop never re-descends to find the next price.
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
163
164/// End-of-day restore. `collect_in_order` gives a sorted snapshot; `from_sorted`
165/// rebuilds in O(n) instead of paying n rotating inserts.
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
Source

pub fn is_empty(&self) -> bool

Source

pub fn height(&self) -> usize

Longest root-to-leaf path in edges; 0 for an empty or single-node tree. The randomized-priority bound puts this near 3 * ln(n) in expectation, so it is the cheapest way to see whether the priority stream is doing its job on real keys.

Examples found in repository?
examples/sample_app.rs (line 112)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137/// Sweep an aggressive sell through the bid side. `pop_last` takes the best
138/// level in expected O(log n) and hands back both key and value, so the fill
139/// loop never re-descends to find the next price.
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
163
164/// End-of-day restore. `collect_in_order` gives a sorted snapshot; `from_sorted`
165/// rebuilds in O(n) instead of paying n rotating inserts.
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
Source

pub fn clear(&mut self)

Drop every entry and reset to empty, keeping the arena’s capacity so a rebuild does not pay the growth path again.

Source

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

Examples found in repository?
examples/perf_features.rs (line 46)
43fn build(n: usize) -> Treap<u64, u64> {
44    let mut t = Treap::new(SEED);
45    for i in 0..n {
46        t.insert(key_at(i), i as u64);
47    }
48    t
49}
More examples
Hide additional examples
examples/sample_app.rs (line 83)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
104
105/// Read the book the way a trader does: best price first, then the touch and
106/// its neighbours. `iter_rev` walks the ladder high to low; `floor` and
107/// `predecessor` answer "what is at or below this price" without a scan.
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137/// Sweep an aggressive sell through the bid side. `pop_last` takes the best
138/// level in expected O(log n) and hands back both key and value, so the fill
139/// loop never re-descends to find the next price.
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
163
164/// End-of-day restore. `collect_in_order` gives a sorted snapshot; `from_sorted`
165/// rebuilds in O(n) instead of paying n rotating inserts.
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
181
182/// Sum resting depth in a price band without
183/// materialising the whole ladder. `range` descends to the low bound in
184/// expected O(log N), then walks only the window in ascending order. Each
185/// bound is independently inclusive, exclusive, or unbounded.
186fn band_depth() {
187    use subms_treap::RangeBound;
188    println!("\n== range-query: depth in a price band ==");
189    let book = build_book();
190    let (lo, hi) = (9_996u32, 10_000u32);
191    let band: Vec<(u32, u64)> = book
192        .range(RangeBound::Inclusive(&lo), RangeBound::Inclusive(&hi))
193        .map(|(k, v)| (*k, *v))
194        .collect();
195    let depth: u64 = band.iter().map(|(_, q)| *q).sum();
196    println!("  [{lo}, {hi}] -> {} levels, {depth} lots", band.len());
197    assert_eq!(
198        band.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
199        vec![9_996, 9_998, 9_999, 10_000]
200    );
201    assert_eq!(depth, 2_500);
202
203    // Exclusive upper bound drops the touch itself.
204    let inside: u64 = book
205        .range(RangeBound::Inclusive(&lo), RangeBound::Exclusive(&hi))
206        .map(|(_, q)| *q)
207        .sum();
208    println!("  same band, exclusive of {hi}: {inside} lots");
209    assert_eq!(inside, 1_850);
210}
211
212/// `persistent` feature: version the book so a prior state stays queryable.
213/// Each `insert` / `remove` returns a NEW book and leaves the receiver
214/// untouched - the shape a risk what-if branch or an audit trail wants.
215#[cfg(feature = "persistent")]
216fn versioned_book() {
217    use subms_treap::PersistentTreap;
218    println!("\n== persistent: versioned book ==");
219    let open: PersistentTreap<u32, u64> = PersistentTreap::new(SEED);
220    let open = open
221        .insert(9_999, 250)
222        .insert(10_000, 500)
223        .insert(10_001, 100);
224
225    // Branch: what does the book look like if the 9999 level fills?
226    let after_fill = open.remove(&9_999);
227    println!(
228        "  open: {} levels, depth@9999 {:?}",
229        open.len(),
230        open.get(&9_999).copied()
231    );
232    println!(
233        "  after fill: {} levels, depth@9999 {:?}",
234        after_fill.len(),
235        after_fill.get(&9_999)
236    );
237    assert_eq!(open.get(&9_999).copied(), Some(250), "prior version intact");
238    assert_eq!(after_fill.get(&9_999), None);
239    assert_eq!((open.len(), after_fill.len()), (3, 2));
240}
241
242/// `merge-split` feature: partition the ladder at the touch in expected
243/// O(log N), then stitch it back. This is the treap's distinguishing
244/// operation - a red-black tree has no cheap equivalent. `merge` requires
245/// every key on the left to be strictly less than every key on the right.
246#[cfg(feature = "merge-split")]
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}
285
286/// `concurrent-reads` feature: freeze the book into a shared snapshot and fan
287/// it out to reader threads (market-data / risk consumers) while the writer
288/// keeps applying updates. Every reader sees a stable point-in-time book.
289#[cfg(feature = "concurrent-reads")]
290fn published_snapshot() {
291    use std::thread;
292    use subms_treap::TreapSnapshot;
293    println!("\n== concurrent-reads: published book snapshot ==");
294    let mut book: Treap<u32, u64> = Treap::new(SEED);
295    for px in 9_990..10_010u32 {
296        book.insert(px, (px as u64) * 10);
297    }
298    let snap = TreapSnapshot::from_treap(&book);
299
300    let readers: Vec<_> = (0..4)
301        .map(|_| {
302            let s = snap.clone();
303            thread::spawn(move || s.range(&9_995, &10_004).count())
304        })
305        .collect();
306
307    // Writer churn after the snapshot: readers must not observe it.
308    book.insert(12_345, 1);
309    book.remove(&9_990);
310
311    for r in readers {
312        assert_eq!(
313            r.join().unwrap(),
314            10,
315            "reader sees the frozen 10-level band"
316        );
317    }
318    println!("  4 readers each counted 10 levels in [9995, 10004]");
319    assert!(
320        snap.get(&12_345).is_none(),
321        "snapshot isolated from later writes"
322    );
323    assert_eq!(snap.len(), 20);
324}
Source

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

Examples found in repository?
examples/sample_app.rs (line 97)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
More examples
Hide additional examples
examples/perf_features.rs (line 112)
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_mut(&mut self, key: &K) -> Option<&mut V>

Mutable access to a resting value. The amend path for a price level: no re-descent through insert, no priority redraw, no rotation.

Examples found in repository?
examples/sample_app.rs (line 86)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
Source

pub fn contains_key(&self, key: &K) -> bool

Examples found in repository?
examples/sample_app.rs (line 101)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
Source

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

Examples found in repository?
examples/sample_app.rs (line 91)
78fn build_book() -> Treap<u32, u64> {
79    let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80    for event in &TAPE {
81        match event {
82            Event::Post(px, qty) => {
83                book.insert(*px, *qty);
84            }
85            Event::Amend(px, delta) => {
86                if let Some(qty) = book.get_mut(px) {
87                    *qty = qty.saturating_add_signed(*delta);
88                }
89            }
90            Event::Cancel(px) => {
91                book.remove(px);
92            }
93        }
94    }
95    assert_eq!(book.len(), 9);
96    assert_eq!(
97        book.get(&10_000).copied(),
98        Some(650),
99        "amend applied in place"
100    );
101    assert!(!book.contains_key(&9997), "cancelled level is gone");
102    book
103}
104
105/// Read the book the way a trader does: best price first, then the touch and
106/// its neighbours. `iter_rev` walks the ladder high to low; `floor` and
107/// `predecessor` answer "what is at or below this price" without a scan.
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137/// Sweep an aggressive sell through the bid side. `pop_last` takes the best
138/// level in expected O(log n) and hands back both key and value, so the fill
139/// loop never re-descends to find the next price.
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
163
164/// End-of-day restore. `collect_in_order` gives a sorted snapshot; `from_sorted`
165/// rebuilds in O(n) instead of paying n rotating inserts.
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
181
182/// Sum resting depth in a price band without
183/// materialising the whole ladder. `range` descends to the low bound in
184/// expected O(log N), then walks only the window in ascending order. Each
185/// bound is independently inclusive, exclusive, or unbounded.
186fn band_depth() {
187    use subms_treap::RangeBound;
188    println!("\n== range-query: depth in a price band ==");
189    let book = build_book();
190    let (lo, hi) = (9_996u32, 10_000u32);
191    let band: Vec<(u32, u64)> = book
192        .range(RangeBound::Inclusive(&lo), RangeBound::Inclusive(&hi))
193        .map(|(k, v)| (*k, *v))
194        .collect();
195    let depth: u64 = band.iter().map(|(_, q)| *q).sum();
196    println!("  [{lo}, {hi}] -> {} levels, {depth} lots", band.len());
197    assert_eq!(
198        band.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
199        vec![9_996, 9_998, 9_999, 10_000]
200    );
201    assert_eq!(depth, 2_500);
202
203    // Exclusive upper bound drops the touch itself.
204    let inside: u64 = book
205        .range(RangeBound::Inclusive(&lo), RangeBound::Exclusive(&hi))
206        .map(|(_, q)| *q)
207        .sum();
208    println!("  same band, exclusive of {hi}: {inside} lots");
209    assert_eq!(inside, 1_850);
210}
211
212/// `persistent` feature: version the book so a prior state stays queryable.
213/// Each `insert` / `remove` returns a NEW book and leaves the receiver
214/// untouched - the shape a risk what-if branch or an audit trail wants.
215#[cfg(feature = "persistent")]
216fn versioned_book() {
217    use subms_treap::PersistentTreap;
218    println!("\n== persistent: versioned book ==");
219    let open: PersistentTreap<u32, u64> = PersistentTreap::new(SEED);
220    let open = open
221        .insert(9_999, 250)
222        .insert(10_000, 500)
223        .insert(10_001, 100);
224
225    // Branch: what does the book look like if the 9999 level fills?
226    let after_fill = open.remove(&9_999);
227    println!(
228        "  open: {} levels, depth@9999 {:?}",
229        open.len(),
230        open.get(&9_999).copied()
231    );
232    println!(
233        "  after fill: {} levels, depth@9999 {:?}",
234        after_fill.len(),
235        after_fill.get(&9_999)
236    );
237    assert_eq!(open.get(&9_999).copied(), Some(250), "prior version intact");
238    assert_eq!(after_fill.get(&9_999), None);
239    assert_eq!((open.len(), after_fill.len()), (3, 2));
240}
241
242/// `merge-split` feature: partition the ladder at the touch in expected
243/// O(log N), then stitch it back. This is the treap's distinguishing
244/// operation - a red-black tree has no cheap equivalent. `merge` requires
245/// every key on the left to be strictly less than every key on the right.
246#[cfg(feature = "merge-split")]
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}
285
286/// `concurrent-reads` feature: freeze the book into a shared snapshot and fan
287/// it out to reader threads (market-data / risk consumers) while the writer
288/// keeps applying updates. Every reader sees a stable point-in-time book.
289#[cfg(feature = "concurrent-reads")]
290fn published_snapshot() {
291    use std::thread;
292    use subms_treap::TreapSnapshot;
293    println!("\n== concurrent-reads: published book snapshot ==");
294    let mut book: Treap<u32, u64> = Treap::new(SEED);
295    for px in 9_990..10_010u32 {
296        book.insert(px, (px as u64) * 10);
297    }
298    let snap = TreapSnapshot::from_treap(&book);
299
300    let readers: Vec<_> = (0..4)
301        .map(|_| {
302            let s = snap.clone();
303            thread::spawn(move || s.range(&9_995, &10_004).count())
304        })
305        .collect();
306
307    // Writer churn after the snapshot: readers must not observe it.
308    book.insert(12_345, 1);
309    book.remove(&9_990);
310
311    for r in readers {
312        assert_eq!(
313            r.join().unwrap(),
314            10,
315            "reader sees the frozen 10-level band"
316        );
317    }
318    println!("  4 readers each counted 10 levels in [9995, 10004]");
319    assert!(
320        snap.get(&12_345).is_none(),
321        "snapshot isolated from later writes"
322    );
323    assert_eq!(snap.len(), 20);
324}
Source

pub fn first(&self) -> Option<(&K, &V)>

Smallest key and its value.

Source

pub fn last(&self) -> Option<(&K, &V)>

Largest key and its value.

Examples found in repository?
examples/sample_app.rs (line 109)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137/// Sweep an aggressive sell through the bid side. `pop_last` takes the best
138/// level in expected O(log n) and hands back both key and value, so the fill
139/// loop never re-descends to find the next price.
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
Source

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

Greatest key <= key.

Examples found in repository?
examples/sample_app.rs (line 130)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
Source

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

Least key >= key.

Examples found in repository?
examples/sample_app.rs (line 131)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
Source

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

Greatest key strictly < key.

Examples found in repository?
examples/sample_app.rs (line 121)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
Source

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

Least key strictly > key.

Source

pub fn pop_first(&mut self) -> Option<(K, V)>

Remove and return the smallest entry. The top-of-book sweep.

Source

pub fn pop_last(&mut self) -> Option<(K, V)>

Remove and return the largest entry.

Examples found in repository?
examples/sample_app.rs (line 144)
140fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141    let mut to_fill = 1_200u64;
142    let mut fills = Vec::new();
143    while to_fill > 0 {
144        let Some((px, qty)) = book.pop_last() else {
145            break;
146        };
147        let take = qty.min(to_fill);
148        to_fill -= take;
149        fills.push((px, take));
150        if qty > take {
151            book.insert(px, qty - take); // partial fill, level survives
152        }
153    }
154    println!("  sweep 1200 lots -> {fills:?}");
155    assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156    assert_eq!(book.len(), 8);
157    assert_eq!(
158        book.last().map(|(k, _)| *k),
159        Some(10_001),
160        "partial fill left the level"
161    );
162}
Source

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

Cut the treap at pivot, keeping everything below it and returning everything at or above it.

The cut itself is the treap’s distinguishing operation against a red-black tree: one descent, expected O(log n), no rebalancing pass. The arena then charges for what it buys elsewhere - the upper half’s m nodes are relocated into their own arena, so the whole call is expected O(log n) + O(m). Where that relocation matters, the merge-split feature’s SplittableTreap is the pointer-backed variant that hands the detached subtree over without touching it.

use subms_treap::Treap;
let mut book: Treap<u32, u64> = Treap::new(7);
for px in [9998u32, 9999, 10_000, 10_001] { book.insert(px, 100); }
let marketable = book.split_off(&10_000);
assert_eq!(book.len(), 2);
assert_eq!(marketable.len(), 2);
assert_eq!(marketable.first().map(|(k, _)| *k), Some(10_000));
Source

pub fn join(&mut self, other: Self) -> Result<(), TreapError>

Splice other onto the end of self. Every key in self must be strictly below every key in other.

The splice is expected O(log n); as with Treap::split_off, moving other’s m nodes into this arena adds O(m). An overlapping range is refused rather than silently corrupting the BST invariant, and both treaps are left as they were.

Source

pub fn iter(&self) -> Iter<'_, K, V>

Ascending in-order iteration. Lazy: the only allocation is the traversal stack, sized to the tree’s height.

Examples found in repository?
examples/sample_app.rs (line 167)
166fn restore_from_snapshot(book: &Treap<u32, u64>) {
167    let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168    let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169    println!(
170        "  restored {} levels from a sorted snapshot, height {}",
171        restored.len(),
172        restored.height()
173    );
174    let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175    assert_eq!(round_tripped, snapshot);
176
177    // Unsorted input is rejected rather than silently reordered.
178    let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179    assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
Source

pub fn iter_rev(&self) -> IterRev<'_, K, V>

Descending in-order iteration. A bid ladder is read best price first, which is the reverse of the stored order.

Examples found in repository?
examples/sample_app.rs (line 117)
108fn report(book: &Treap<u32, u64>) {
109    let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110    println!(
111        "  best bid {best_px} x {best_qty} | height {} | {} levels",
112        book.height(),
113        book.len()
114    );
115
116    println!("  top 5, best first:");
117    for (px, qty) in book.iter_rev().take(5) {
118        println!("    {px}  {qty:>5}");
119    }
120
121    let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122    println!("  next level down: {inside}");
123    assert_eq!(inside, 10_001);
124
125    // A price that is not a resting level still answers, which is the whole
126    // reason for an ordered index over a hash map.
127    let probe = 9_990u32;
128    println!(
129        "  probe {probe}: floor {:?}, ceiling {:?}",
130        book.floor(&probe).map(|(k, _)| *k),
131        book.ceiling(&probe).map(|(k, _)| *k)
132    );
133    assert_eq!(book.floor(&probe), None);
134    assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
Source

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

In-order traversal; pushes (key, value) references into a Vec.

Trait Implementations§

Source§

impl<K: Ord + Debug, V: Debug> Debug for Treap<K, V>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K, V> Drop for Treap<K, V>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<'a, K: Ord, V> IntoIterator for &'a Treap<K, V>

Source§

type Item = (&'a K, &'a V)

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, K, V>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

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

§

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

§

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

§

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

§

impl<K, V> Unpin for Treap<K, V>
where K: Unpin, V: Unpin,

§

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

§

impl<K, V> UnwindSafe for Treap<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.