-
Notifications
You must be signed in to change notification settings - Fork 545
Add a fourth approach to the rust version of the Bob problem #2058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
2b06a52
d1eec13
bad88c5
269a110
f45e484
b028618
febe656
6b244df
caba2c4
1468d73
10e8201
b6ed43d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "code" | ||
| version = "0.1.0" | ||
| edition = "2024" | ||
|
|
||
| [dependencies] | ||
|
|
||
| [[bin]] | ||
| name = "code" | ||
| path = "main.rs" |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ fn main() { | |||||
| println!("Hello, world!"); | ||||||
| } | ||||||
|
|
||||||
| // Reply using match | ||||||
| pub fn reply_match(msg: &str) -> &str { | ||||||
| let message = msg.trim_end(); | ||||||
| if message.is_empty() { | ||||||
|
|
@@ -24,6 +25,7 @@ pub fn reply_match(msg: &str) -> &str { | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Reply using if chain | ||||||
| pub fn reply_if_chain(msg: &str) -> &str { | ||||||
| let message = msg.trim_end(); | ||||||
| if message.is_empty() { | ||||||
|
|
@@ -47,6 +49,7 @@ pub fn reply_if_chain(msg: &str) -> &str { | |||||
| "Whatever." | ||||||
| } | ||||||
|
|
||||||
| // Reply using array | ||||||
| const ANSWERS: &'static [&'static str] = &[ | ||||||
| "Whatever.", | ||||||
| "Sure.", | ||||||
|
|
@@ -71,20 +74,132 @@ pub fn reply_array(msg: &str) -> &str { | |||||
| ANSWERS[is_questioning + is_yelling] | ||||||
| } | ||||||
|
|
||||||
| // Reply using state machine | ||||||
| enum State { | ||||||
| Initial, | ||||||
| HasQuestionMark, | ||||||
| NoQuestionMarkUpperCase, | ||||||
| NoQuestionMarkUndefined, | ||||||
| QuestionMarkUpperCase, | ||||||
| QuestionMarkUndefined, | ||||||
| } | ||||||
|
|
||||||
| const FINE_BE_THAT_WAY: &str = "Fine. Be that way!"; | ||||||
| const WHATEVER: &str = "Whatever."; | ||||||
| const SURE: &str = "Sure."; | ||||||
| const CHILL_OUT: &str = "Whoa, chill out!"; | ||||||
| const CALM_DOWN: &str = "Calm down, I know what I'm doing!"; | ||||||
|
|
||||||
| pub fn reply_state_machine(message: &str) -> &str { | ||||||
| let message = message.trim(); | ||||||
| if message.is_empty() { | ||||||
| return FINE_BE_THAT_WAY; | ||||||
| } | ||||||
| let mut state = State::Initial; | ||||||
| for c in message.chars().rev() { | ||||||
| match state { | ||||||
| State::Initial => { | ||||||
| state = if c == '?' { | ||||||
| State::HasQuestionMark | ||||||
| } else { | ||||||
| if c.is_lowercase() { | ||||||
| return WHATEVER; | ||||||
| } | ||||||
| if c.is_uppercase() { | ||||||
| State::NoQuestionMarkUpperCase | ||||||
| } else { | ||||||
| State::NoQuestionMarkUndefined | ||||||
| } | ||||||
| }; | ||||||
| } | ||||||
| State::HasQuestionMark => { | ||||||
| state = if c.is_uppercase() { | ||||||
| State::QuestionMarkUpperCase | ||||||
| } else { | ||||||
| State::QuestionMarkUndefined | ||||||
| }; | ||||||
| } | ||||||
| State::NoQuestionMarkUpperCase => { | ||||||
| if c.is_lowercase() { | ||||||
| return WHATEVER; | ||||||
| } | ||||||
| } | ||||||
| State::NoQuestionMarkUndefined => { | ||||||
| if c.is_lowercase() { | ||||||
| return WHATEVER; | ||||||
| } | ||||||
| if c.is_uppercase() { | ||||||
| state = State::NoQuestionMarkUpperCase; | ||||||
| } | ||||||
| } | ||||||
| State::QuestionMarkUpperCase => { | ||||||
| if c.is_lowercase() { | ||||||
| return SURE; | ||||||
| } | ||||||
| } | ||||||
| State::QuestionMarkUndefined => { | ||||||
| if c.is_lowercase() { | ||||||
| return SURE; | ||||||
| } | ||||||
| if c.is_uppercase() { | ||||||
| state = State::QuestionMarkUpperCase; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| match state { | ||||||
| State::HasQuestionMark | State::QuestionMarkUndefined => SURE, | ||||||
| State::NoQuestionMarkUpperCase => CHILL_OUT, | ||||||
| State::NoQuestionMarkUndefined => WHATEVER, | ||||||
| State::QuestionMarkUpperCase => CALM_DOWN, | ||||||
| _ => panic!("Unexpected final state"), | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[bench] | ||||||
| /// multiple line question for match | ||||||
| fn multiple_line_question_match(b: &mut Bencher) { | ||||||
| b.iter(|| reply_match("\rDoes this cryogenic chamber make me look fat?\rNo.")); | ||||||
| b.iter(|| { | ||||||
| reply_match("\rDoes this cryogenic chamber make me look fat?\rNo."); | ||||||
| reply_match(" "); | ||||||
| reply_match("Does this cryogenic chamber make me look fat?"); | ||||||
| reply_match("WHAT'S GOING ON?"); | ||||||
| reply_match("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"); | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| #[bench] | ||||||
| /// multiple line question for if statements | ||||||
| fn multiple_line_question_if(b: &mut Bencher) { | ||||||
| b.iter(|| reply_if_chain("\rDoes this cryogenic chamber make me look fat?\rNo.")); | ||||||
| b.iter(|| { | ||||||
| reply_if_chain("\rDoes this cryogenic chamber make me look fat?\rNo."); | ||||||
|
||||||
| reply_if_chain("\rDoes this cryogenic chamber make me look fat?\rNo."); | |
| reply_if_chain(std::hint::black_box("\rDoes this cryogenic chamber make me look fat?\rNo.")); |
The inputs to the functions under test should be wrapped in black_box, to prevent the compiler from optimizing the function based on knowledge about its input. In my testing, multiple_line_question_array slows down a little from 120 ns/iter to 140 ns/iter, the other approaches stay the same.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,19 +7,21 @@ The [approaches page][approaches] lists two idiomatic approaches to this exercis | |||||||
| 1. [Using `if` statements][approach-if]. | ||||||||
| 2. [Using `match` on a `tuple`][approach-match]. | ||||||||
|
|
||||||||
| For our performance investigation, we'll also include a third approach that [uses an answer array][approach-answer-array]. | ||||||||
| For our performance investigation, we'll also include a third approach that [uses an answer array][approach-answer-array] and | ||||||||
| a fourth that uses a state machine. | ||||||||
|
||||||||
| For our performance investigation, we'll also include a third approach that [uses an answer array][approach-answer-array] and | |
| a fourth that uses a state machine. | |
| For our performance investigation, we'll also include a third approach that [uses an answer array][approach-answer-array] and a fourth that uses a state machine. |
Our convention in markdown is one sentence per line.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot reproduce this result. On my machine, the state machine approach is consistently the slowest:
test multiple_line_question_array ... bench: 119.61 ns/iter (+/- 1.57)
test multiple_line_question_if ... bench: 95.64 ns/iter (+/- 2.83)
test multiple_line_question_match ... bench: 96.57 ns/iter (+/- 5.44)
test multiple_line_question_state_machine ... bench: 151.83 ns/iter (+/- 7.84)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| All four approaches are close in performance, but the `if` statements and `match` approaches may be considered to be more idiomatic. The state machine approach is the fastest because it loops through the characters of the message only once. | |
| All four approaches are close in performance, but the `if` statements and `match` approaches may be considered to be more idiomatic. | |
| The state machine approach is the fastest because it loops through the characters of the message only once. |
same here, one sentence per line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A separate function could make sense here, to make it more clear that all benches are running the same code.