init lab4

This commit is contained in:
jacekpoz 2024-06-05 16:01:17 +02:00
parent 2d1d836575
commit 78a1b3bc5a
Signed by: poz
SSH key fingerprint: SHA256:JyLeVWE4bF3tDnFeUpUaJsPsNlJyBldDGV/dIKSLyN8
12 changed files with 975 additions and 0 deletions

1
lab4/zad1/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
target

87
lab4/zad1/Cargo.lock generated Normal file
View file

@ -0,0 +1,87 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libgen"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "libtree"
version = "0.1.0"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zad1"
version = "0.1.0"
dependencies = [
"libgen",
"libtree",
]

8
lab4/zad1/Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "zad1"
version = "0.1.0"
edition = "2021"
[dependencies]
libgen = { path = "../../libgen" }
libtree = { path = "../../libtree" }

34
lab4/zad1/src/main.rs Normal file
View file

@ -0,0 +1,34 @@
use libgen::{gen_asc, gen_rand};
use libtree::BinarySearchTree;
fn main() {
println!("1. insert 50 ascending; delete 50 random");
let mut tree1 = BinarySearchTree::new(50);
for i in gen_asc(50) {
println!("insert {i}");
tree1.insert(i);
println!("{}", tree1);
}
for i in gen_rand(50) {
println!("delete {i}");
tree1.delete(i);
println!("{}", tree1);
}
println!("2. insert 50 random; delete 50 random");
let mut tree2 = BinarySearchTree::new(50);
for i in gen_rand(50) {
println!("insert {i}");
tree2.insert(i);
println!("{}", tree2);
}
for i in gen_rand(50) {
println!("delete {i}");
tree2.delete(i);
println!("{}", tree2);
}
}

2
lab4/zad2/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
target
results

285
lab4/zad2/Cargo.lock generated Normal file
View file

@ -0,0 +1,285 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "either"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libgen"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "libtree"
version = "0.1.0"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "redox_syscall"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "zad2"
version = "0.1.0"
dependencies = [
"dashmap",
"libgen",
"libtree",
"rayon",
]

10
lab4/zad2/Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "zad2"
version = "0.1.0"
edition = "2021"
[dependencies]
libtree = { path = "../../libtree" }
libgen = { path = "../../libgen" }
rayon = "1.10.0"
dashmap = "5.5.3"

277
lab4/zad2/src/main.rs Normal file
View file

@ -0,0 +1,277 @@
use std::{fs::{self, OpenOptions}, io::{self, Write}, sync::Arc};
use dashmap::DashMap;
use libgen::{gen_asc, gen_rand};
use rayon::{current_thread_index, iter::{IntoParallelIterator, ParallelIterator}};
use libtree::{BinarySearchTree, Stats};
fn comp_avg(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, f64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, (results.iter()
.map(|res| res.comparisons)
.sum::<u64>() as f64 / results.len() as f64))
})
.collect()
}
fn comp_max(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, u64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, results.iter()
.map(|s| s.comparisons)
.max()
.unwrap())
})
.collect()
}
fn read_avg(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, f64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, (results.iter()
.map(|res| res.reads)
.sum::<u64>() as f64 / results.len() as f64))
})
.collect()
}
fn read_max(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, u64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, results.iter()
.map(|s| s.reads)
.max()
.unwrap())
})
.collect()
}
fn write_avg(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, f64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, (results.iter()
.map(|res| res.writes)
.sum::<u64>() as f64 / results.len() as f64))
})
.collect()
}
fn write_max(results_map: &DashMap<u64, Vec<Stats>>) -> DashMap<u64, u64> {
results_map.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, results.iter()
.map(|s| s.writes)
.max()
.unwrap())
})
.collect()
}
fn main() -> io::Result<()> {
let m = 20;
let asc_results: Arc<DashMap<u64, Vec<Stats>>> = Arc::new(DashMap::new());
let asc_heights: Arc<DashMap<u64, Vec<usize>>> = Arc::new(DashMap::new());
let rand_results: Arc<DashMap<u64, Vec<Stats>>> = Arc::new(DashMap::new());
let rand_heights: Arc<DashMap<u64, Vec<usize>>> = Arc::new(DashMap::new());
let asc_results_clone = Arc::clone(&asc_results);
let asc_heights_clone = Arc::clone(&asc_heights);
let rand_results_clone = Arc::clone(&rand_results);
let rand_heights_clone = Arc::clone(&rand_heights);
(10000u64..=100000u64).step_by(10000).collect::<Vec<_>>().into_par_iter().for_each(move |n| {
if asc_results_clone.get(&n).is_some() {
return;
}
if asc_heights_clone.get(&n).is_some() {
return;
}
if rand_results_clone.get(&n).is_some() {
return;
}
if rand_heights_clone.get(&n).is_some() {
return;
}
println!("{}: starting n: {n}", current_thread_index().unwrap());
asc_results_clone.insert(n, vec![]);
asc_heights_clone.insert(n, vec![]);
rand_results_clone.insert(n, vec![]);
rand_heights_clone.insert(n, vec![]);
let mut asc = BinarySearchTree::new(n as usize);
let mut rand = BinarySearchTree::new(n as usize);
for _ in 0..m {
for i in gen_asc(n) {
asc.insert(i);
asc_heights_clone.get_mut(&n).unwrap().push(asc.height());
}
for i in gen_rand(n) {
asc.delete(i);
asc_heights_clone.get_mut(&n).unwrap().push(asc.height());
}
asc_results_clone.get_mut(&n).unwrap().push(asc.stats.clone());
for i in gen_rand(n) {
rand.insert(i);
rand_heights_clone.get_mut(&n).unwrap().push(rand.height());
}
for i in gen_rand(n) {
rand.delete(i);
rand_heights_clone.get_mut(&n).unwrap().push(rand.height());
}
rand_results_clone.get_mut(&n).unwrap().push(rand.stats.clone());
}
println!("{}: finished n: {n}", current_thread_index().unwrap());
});
let asc_comp_averages = comp_avg(&asc_results);
let asc_read_averages = read_avg(&asc_results);
let asc_write_averages = write_avg(&asc_results);
let asc_height_averages: DashMap<_, _> = asc_heights.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, results.iter().sum::<usize>() as f64 / results.len() as f64)
})
.collect();
let asc_comp_max = comp_max(&asc_results);
let asc_read_max = read_max(&asc_results);
let asc_write_max = write_max(&asc_results);
let asc_height_max: DashMap<_, _> = asc_heights.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, *results.iter().max().unwrap())
})
.collect();
let rand_comp_averages = comp_avg(&rand_results);
let rand_read_averages = read_avg(&rand_results);
let rand_write_averages = write_avg(&rand_results);
let rand_height_averages: DashMap<_, _> = rand_heights.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, results.iter().sum::<usize>() as f64 / results.len() as f64)
})
.collect();
let rand_comp_max = comp_max(&rand_results);
let rand_read_max = read_max(&rand_results);
let rand_write_max = write_max(&rand_results);
let rand_height_max: DashMap<_, _> = rand_heights.iter()
.map(|ref_multi| {
let (i, results) = ref_multi.pair();
(*i, *results.iter().max().unwrap())
})
.collect();
_ = fs::create_dir_all("./results");
let mut asc_comp_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/asc_comp")?;
let mut asc_read_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/asc_read")?;
let mut asc_write_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/asc_write")?;
let mut asc_height_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/asc_height")?;
let mut rand_comp_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/rand_comp")?;
let mut rand_read_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/rand_read")?;
let mut rand_write_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/rand_write")?;
let mut rand_height_file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./results/rand_height")?;
for n in (10000u64..=100000u64).step_by(10000) {
writeln!(asc_comp_file, "{n} {} {}",
asc_comp_averages.get(&n).unwrap().value(),
asc_comp_max.get(&n).unwrap().value(),
)?;
writeln!(asc_read_file, "{n} {} {}",
asc_read_averages.get(&n).unwrap().value(),
asc_read_max.get(&n).unwrap().value(),
)?;
writeln!(asc_write_file, "{n} {} {}",
asc_write_averages.get(&n).unwrap().value(),
asc_write_max.get(&n).unwrap().value(),
)?;
writeln!(asc_height_file, "{n} {} {}",
asc_height_averages.get(&n).unwrap().value(),
asc_height_max.get(&n).unwrap().value(),
)?;
writeln!(rand_comp_file, "{n} {} {}",
rand_comp_averages.get(&n).unwrap().value(),
rand_comp_max.get(&n).unwrap().value(),
)?;
writeln!(rand_read_file, "{n} {} {}",
rand_read_averages.get(&n).unwrap().value(),
rand_read_max.get(&n).unwrap().value(),
)?;
writeln!(rand_write_file, "{n} {} {}",
rand_write_averages.get(&n).unwrap().value(),
rand_write_max.get(&n).unwrap().value(),
)?;
writeln!(rand_height_file, "{n} {} {}",
rand_height_averages.get(&n).unwrap().value(),
rand_height_max.get(&n).unwrap().value(),
)?;
}
Ok(())
}

1
libtree/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
target

7
libtree/Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "libtree"
version = "0.1.0"

6
libtree/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "libtree"
version = "0.1.0"
edition = "2021"
[dependencies]

257
libtree/src/lib.rs Normal file
View file

@ -0,0 +1,257 @@
use std::fmt::Display;
#[derive(Clone, Default)]
pub struct Stats {
pub comparisons: u64,
pub reads: u64,
pub writes: u64,
}
impl Stats {
pub fn new() -> Stats {
Self {
comparisons: 0,
reads: 0,
writes: 0,
}
}
}
impl std::ops::AddAssign for Stats {
fn add_assign(&mut self, rhs: Self) {
self.comparisons += rhs.comparisons;
self.reads += rhs.reads;
self.writes += rhs.writes;
}
}
#[derive(Clone)]
pub struct Node {
pub key: u64,
pub left: Tree,
pub right: Tree,
}
impl Node {
pub fn new(key: u64) -> Self {
Self {
key,
left: Tree(None),
right: Tree(None),
}
}
pub fn height(&self) -> usize {
match (&self.left.0, &self.right.0) {
(None, None) =>
1,
(None, Some(right)) =>
1 + right.height(),
(Some(left), None) =>
1 + left.height(),
(Some(left), Some(right)) =>
1 + (left.height()).max(right.height()),
}
}
// https://stackoverflow.com/a/66661638
fn replace_nth_char_ascii(s: &mut str, idx: usize, newchar: char) {
let s_bytes: &mut [u8] = unsafe { s.as_bytes_mut() };
assert!(idx < s_bytes.len());
assert!(s_bytes[idx].is_ascii());
assert!(newchar.is_ascii());
// we've made sure this is safe.
s_bytes[idx] = newchar as u8;
}
fn _print(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, prefix: char, left_trace: &mut String, right_trace: &mut String) -> std::fmt::Result {
if let Some(left) = &self.left.0 {
left._print(f, depth + 1, '/', left_trace, right_trace)?;
}
if prefix == '/' {
Self::replace_nth_char_ascii(left_trace, depth - 1, '|');
}
if prefix == '\\' {
Self::replace_nth_char_ascii(right_trace, depth - 1, ' ');
}
if depth == 0 {
write!(f, "-")?;
}
if depth > 0 {
write!(f, " ")?;
}
if depth > 0 {
for i in 0..(depth - 1) {
if left_trace.chars().nth(i).unwrap() == '|' || right_trace.chars().nth(i).unwrap() == '|' {
write!(f, "| ")?;
} else {
write!(f, " ")?;
}
}
write!(f, "{}-", prefix)?;
}
writeln!(f, "[{}]", self.key)?;
Self::replace_nth_char_ascii(left_trace, depth, ' ');
if let Some(right) = &self.right.0 {
Self::replace_nth_char_ascii(right_trace, depth, '|');
right._print(f, depth + 1, '\\', left_trace, right_trace)?;
}
Ok(())
}
}
#[derive(Clone)]
pub struct Tree(Option<Box<Node>>);
impl Tree {
pub fn insert(&mut self, key: u64) -> (bool, Stats) {
let mut stats = Stats::new();
if self.0.is_none() {
stats.writes += 1;
self.0 = Some(Box::new(Node::new(key)));
return (true, stats);
}
let mut current = self;
while let Some(ref mut node) = current.0 {
stats.reads += 1;
use std::cmp::Ordering::*;
stats.comparisons += 1;
match node.key.cmp(&key) {
Greater => {
stats.reads += 1;
current = &mut node.left;
},
Less => {
stats.reads += 1;
current = &mut node.right;
},
Equal => return (false, stats),
}
}
stats.writes += 1;
current.0 = Some(Box::new(Node::new(key)));
(true, stats)
}
pub fn delete(&mut self, key: u64) -> (bool, Stats) {
let mut current: *mut Tree = self;
let mut stats = Stats::default();
unsafe {
while let Some(ref mut node) = (*current).0 {
stats.reads += 1;
use std::cmp::Ordering::*;
stats.comparisons += 1;
match node.key.cmp(&key) {
Greater => {
stats.reads += 1;
current = &mut node.left;
},
Less => {
stats.reads += 1;
current = &mut node.right;
},
Equal => {
match (node.left.0.as_mut(), node.right.0.as_mut()) {
(None, None) => {
stats.writes += 1;
(*current).0 = None;
},
(None, Some(_)) => {
stats.writes += 1;
(*current).0 = node.right.0.take();
},
(Some(_), None) => {
stats.writes += 1;
(*current).0 = node.left.0.take();
},
(Some(_), Some(_)) => {
(*current).0.as_mut().unwrap().key = {
let mut to_return = None;
stats.reads += 1;
if node.right.0.is_some() {
stats.reads += 1;
let mut current = &mut node.right;
stats.reads += 1;
while current.0.as_ref().unwrap().left.0.is_some() {
stats.writes += 1;
current = &mut current.0.as_mut().unwrap().left;
}
let node = current.0.take().unwrap();
to_return = Some(node.key);
stats.writes += 1;
current.0 = node.right.0;
}
to_return.unwrap()
};
},
}
return (true, stats);
},
}
}
}
(false, stats)
}
}
pub struct BinarySearchTree {
pub root: Tree,
pub size: usize,
print_capacity: usize,
pub stats: Stats,
}
impl BinarySearchTree {
pub fn new(print_capacity: usize) -> Self {
Self {
root: Tree(None),
size: 0,
print_capacity,
stats: Stats::default(),
}
}
pub fn height(&self) -> usize {
match &self.root.0 {
Some(root) => root.height(),
None => 0,
}
}
pub fn insert(&mut self, key: u64) -> bool {
let (ret, stats) = self.root.insert(key);
self.stats += stats;
ret
}
pub fn delete(&mut self, key: u64) -> bool {
let (ret, stats) = self.root.delete(key);
self.stats += stats;
ret
}
}
impl Display for BinarySearchTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.root.0 {
Some(root) => root._print(f, 0, '-', &mut " ".repeat(self.print_capacity), &mut " ".repeat(self.print_capacity)),
None => Ok(()),
}
}
}