pub struct PersistentTreap<K, V> { /* private fields */ }Implementations§
Source§impl<K: Ord + Clone, V: Clone> PersistentTreap<K, V>
impl<K: Ord + Clone, V: Clone> PersistentTreap<K, V>
Sourcepub fn new(seed: u64) -> Self
pub fn new(seed: u64) -> Self
Examples found in repository?
examples/sample_app.rs (line 219)
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}More examples
examples/perf_features.rs (line 122)
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 229)
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}pub fn is_empty(&self) -> bool
Sourcepub fn insert(&self, key: K, value: V) -> Self
pub fn insert(&self, key: K, value: V) -> Self
Return a NEW treap with key -> value inserted (or its value
replaced). self is left untouched. Shared subtrees are
reference-counted with the previous version.
Examples found in repository?
examples/sample_app.rs (line 221)
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}More examples
examples/perf_features.rs (line 124)
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 remove(&self, key: &K) -> Self
pub fn remove(&self, key: &K) -> Self
Return a NEW treap with key removed. If key is absent, the
returned treap is structurally identical (root pointer cloned).
Examples found in repository?
examples/sample_app.rs (line 226)
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}More examples
examples/perf_features.rs (line 145)
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(&self, key: &K) -> Option<&V>
pub fn get(&self, key: &K) -> Option<&V>
Examples found in repository?
examples/sample_app.rs (line 230)
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}More examples
examples/perf_features.rs (line 141)
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 collect_in_order(&self) -> Vec<(K, V)>
Trait Implementations§
Auto Trait Implementations§
impl<K, V> !Send for PersistentTreap<K, V>
impl<K, V> !Sync for PersistentTreap<K, V>
impl<K, V> Freeze for PersistentTreap<K, V>
impl<K, V> RefUnwindSafe for PersistentTreap<K, V>where
K: RefUnwindSafe,
V: RefUnwindSafe,
impl<K, V> Unpin for PersistentTreap<K, V>
impl<K, V> UnsafeUnpin for PersistentTreap<K, V>
impl<K, V> UnwindSafe for PersistentTreap<K, V>where
K: RefUnwindSafe,
V: RefUnwindSafe,
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