Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

add faster safe rust variant that does not drop needlessly #52

Merged
merged 2 commits into from
May 18, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ rand = "0.4.2"
refcount = []
idiomatic = []
unsafe = []
swap_forget = []

[profile.release]
lto = true
Expand Down
7 changes: 6 additions & 1 deletion rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
```

Expand Down
6 changes: 6 additions & 0 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
113 changes: 113 additions & 0 deletions rust/src/swap_forget.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use std::mem;

use rand;

type NodeCell = Option<Box<Node>>;

struct Node {
x: i32,
y: i32,
left: NodeCell,
right: NodeCell,
}

impl Node {
fn new(x: i32) -> Self {
Self {
x,
y: rand::random::<i32>(),
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);
::std::mem::swap(&mut orig_node.right, &mut split_pair.0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

::std:: can be dropped here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I've updated to fix this.

::std::mem::forget(split_pair.0);
(Some(orig_node), split_pair.1)
} else {
let mut split_pair = split_binary(orig_node.left.take(), value);
::std::mem::swap(&mut orig_node.left, &mut split_pair.1);
::std::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);
}
}