pub struct Treap<K, V> { /* private fields */ }Implementations§
Source§impl<K: Ord, V> Treap<K, V>
impl<K: Ord, V> Treap<K, V>
Sourcepub fn range<'a>(
&'a self,
from: RangeBound<'a, K>,
to: RangeBound<'a, K>,
) -> RangeIter<'a, K, V> ⓘ
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?
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>
impl<K: Ord, V> Treap<K, V>
Sourcepub fn new(seed: u64) -> Self
pub fn new(seed: u64) -> Self
Examples found in repository?
More examples
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}Sourcepub fn with_capacity(seed: u64, capacity: usize) -> Self
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?
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}Sourcepub fn from_entropy() -> Self
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.
Sourcepub fn from_sorted(
seed: u64,
items: impl IntoIterator<Item = (K, V)>,
) -> Result<Self, TreapError>
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?
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}Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Examples found in repository?
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}pub fn is_empty(&self) -> bool
Sourcepub fn height(&self) -> usize
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?
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}Sourcepub fn clear(&mut self)
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.
Sourcepub fn insert(&mut self, key: K, value: V) -> Option<V>
pub fn insert(&mut self, key: K, value: V) -> Option<V>
Examples found in repository?
More examples
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}Sourcepub fn get(&self, key: &K) -> Option<&V>
pub fn get(&self, key: &K) -> Option<&V>
Examples found in repository?
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
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}Sourcepub fn get_mut(&mut self, key: &K) -> Option<&mut V>
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?
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}Sourcepub fn contains_key(&self, key: &K) -> bool
pub fn contains_key(&self, key: &K) -> bool
Examples found in repository?
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}Sourcepub fn remove(&mut self, key: &K) -> Option<V>
pub fn remove(&mut self, key: &K) -> Option<V>
Examples found in repository?
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}Sourcepub fn last(&self) -> Option<(&K, &V)>
pub fn last(&self) -> Option<(&K, &V)>
Largest key and its value.
Examples found in repository?
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}Sourcepub fn floor(&self, key: &K) -> Option<(&K, &V)>
pub fn floor(&self, key: &K) -> Option<(&K, &V)>
Greatest key <= key.
Examples found in repository?
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}Sourcepub fn ceiling(&self, key: &K) -> Option<(&K, &V)>
pub fn ceiling(&self, key: &K) -> Option<(&K, &V)>
Least key >= key.
Examples found in repository?
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}Sourcepub fn predecessor(&self, key: &K) -> Option<(&K, &V)>
pub fn predecessor(&self, key: &K) -> Option<(&K, &V)>
Greatest key strictly < key.
Examples found in repository?
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}Sourcepub fn pop_first(&mut self) -> Option<(K, V)>
pub fn pop_first(&mut self) -> Option<(K, V)>
Remove and return the smallest entry. The top-of-book sweep.
Sourcepub fn pop_last(&mut self) -> Option<(K, V)>
pub fn pop_last(&mut self) -> Option<(K, V)>
Remove and return the largest entry.
Examples found in repository?
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}Sourcepub fn split_off(&mut self, pivot: &K) -> Self
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));Sourcepub fn join(&mut self, other: Self) -> Result<(), TreapError>
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.
Sourcepub fn iter(&self) -> Iter<'_, K, V> ⓘ
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?
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}Sourcepub fn iter_rev(&self) -> IterRev<'_, K, V> ⓘ
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?
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}Sourcepub fn collect_in_order(&self) -> Vec<(&K, &V)>
pub fn collect_in_order(&self) -> Vec<(&K, &V)>
In-order traversal; pushes (key, value) references into a Vec.