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