diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 9c4c500..7b64a84 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -10,6 +10,7 @@ rand = "0.4.2" refcount = [] idiomatic = [] unsafe = [] +swap_forget = [] [profile.release] lto = true diff --git a/rust/README.md b/rust/README.md index 38fc31c..2a0765f 100644 --- a/rust/README.md +++ b/rust/README.md @@ -4,7 +4,8 @@ Author: Vlad Frolov (@frol) ## Compile -NOTE: The idiomatic, refcount, and unsafe versions of this benchmark are locked behind feature gates. +NOTE: The idiomatic, swap_forget, refcount, and unsafe versions of this +benchmark are locked behind feature gates. ``` cargo build --release --features refcount @@ -18,6 +19,10 @@ strip -s target/release/rust ``` cargo build --release --features unsafe +``` + +``` +cargo build --release --features swap_forget strip -s target/release/rust ``` diff --git a/rust/src/main.rs b/rust/src/main.rs index ea4b469..1f244b7 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -6,6 +6,12 @@ mod idiomatic_impl; #[cfg(feature = "idiomatic")] use idiomatic_impl::Tree; +#[cfg(feature = "swap_forget")] +mod swap_forget; + +#[cfg(feature = "swap_forget")] +use swap_forget::Tree; + #[cfg(feature = "refcount")] mod refcount_impl; diff --git a/rust/src/swap_forget.rs b/rust/src/swap_forget.rs new file mode 100644 index 0000000..7179f1e --- /dev/null +++ b/rust/src/swap_forget.rs @@ -0,0 +1,113 @@ +use std::mem; + +use rand; + +type NodeCell = Option>; + +struct Node { + x: i32, + y: i32, + left: NodeCell, + right: NodeCell, +} + +impl Node { + fn new(x: i32) -> Self { + Self { + x, + y: rand::random::(), + left: None, + right: None, + } + } +} + +fn merge(lower: NodeCell, greater: NodeCell) -> NodeCell { + match (lower, greater) { + (None, greater) => greater, + + (lower, None) => lower, + + (Some(mut lower_node), Some(mut greater_node)) => { + if lower_node.y < greater_node.y { + let mut merged = merge(lower_node.right.take(), Some(greater_node)); + mem::swap(&mut lower_node.right, &mut merged); + mem::forget(merged); + Some(lower_node) + } else { + let mut merged = merge(Some(lower_node), greater_node.left.take()); + mem::swap(&mut greater_node.left, &mut merged); + mem::forget(merged); + Some(greater_node) + } + } + } +} + +fn split_binary(orig: NodeCell, value: i32) -> (NodeCell, NodeCell) { + if let Some(mut orig_node) = orig { + if orig_node.x < value { + let mut split_pair = split_binary(orig_node.right.take(), value); + mem::swap(&mut orig_node.right, &mut split_pair.0); + mem::forget(split_pair.0); + (Some(orig_node), split_pair.1) + } else { + let mut split_pair = split_binary(orig_node.left.take(), value); + mem::swap(&mut orig_node.left, &mut split_pair.1); + mem::forget(split_pair.1); + (split_pair.0, Some(orig_node)) + } + } else { + (None, None) + } +} + +fn merge3(lower: NodeCell, equal: NodeCell, greater: NodeCell) -> NodeCell { + merge(merge(lower, equal), greater) +} + +struct SplitResult { + lower: NodeCell, + equal: NodeCell, + greater: NodeCell, +} + +fn split(orig: NodeCell, value: i32) -> SplitResult { + let (lower, equal_greater) = split_binary(orig, value); + let (equal, greater) = split_binary(equal_greater, value + 1); + SplitResult { + lower, + equal, + greater, + } +} + +pub struct Tree { + root: NodeCell, +} + +impl Tree { + pub fn new() -> Self { + Self { root: None } + } + + pub fn has_value(&mut self, x: i32) -> bool { + let splited = split(self.root.take(), x); + let res = splited.equal.is_some(); + self.root = merge3(splited.lower, splited.equal, splited.greater); + res + } + + pub fn insert(&mut self, x: i32) { + let mut splited = split(self.root.take(), x); + if splited.equal.is_none() { + splited.equal = Some(Box::new(Node::new(x))); + } + self.root = merge3(splited.lower, splited.equal, splited.greater); + } + + pub fn erase(&mut self, x: i32) { + let splited = split(self.root.take(), x); + self.root = merge(splited.lower, splited.greater); + } +}