Skip to main content

PersistentTreap

Struct PersistentTreap 

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

Implementations§

Source§

impl<K: Ord + Clone, V: Clone> PersistentTreap<K, V>

Source

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
Hide additional 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}
Source

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}
Source

pub fn is_empty(&self) -> bool

Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

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

Trait Implementations§

Source§

impl<K, V> Clone for PersistentTreap<K, V>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

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>

§

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

§

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

§

impl<K, V> UnwindSafe for PersistentTreap<K, V>

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

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

Source§

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

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

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

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = Infallible

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

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

Performs the conversion.
Source§

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

Source§

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

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

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

Performs the conversion.