Skip to content

Commit c99e0e0

Browse files
author
Van-nam Do
committed
wip
1 parent d783b3c commit c99e0e0

File tree

3 files changed

+132
-29
lines changed

3 files changed

+132
-29
lines changed

challenges/wc-command/src/lib.rs

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use core::num;
12
use core::str;
3+
use std::time::Instant;
4+
use memmap2::MmapOptions;
25
use std::cmp::min;
36
use std::fs::File;
47
use std::sync::atomic::AtomicUsize;
58
use std::sync::atomic::Ordering;
69
use std::sync::Arc;
710
use std::thread;
8-
use memmap2::MmapOptions;
911

1012
pub fn read_file_as_string(file_path: &str) -> String {
1113
let file = File::open(file_path).expect("Path is not valid");
@@ -19,52 +21,101 @@ pub fn count_words(text: &str) -> usize {
1921
}
2022

2123
pub fn count_word_occurrences(text: &str, word: String) -> usize {
22-
count_in_paralell(text, move |chunk| count_word_occurrences_in_chunk(chunk, &word))
24+
count_in_paralell(text, move |chunk| {
25+
count_word_occurrences_in_chunk(chunk, &word)
26+
})
2327
}
2428

2529
fn count_in_paralell<F>(text: &str, count_fn: F) -> usize
2630
where
27-
F: Fn(&[String]) -> usize + Send + Sync + 'static,
31+
F: Fn(&[&str]) -> usize + Send + Sync + 'static,
2832
{
2933
let num_threads: usize = std::thread::available_parallelism().unwrap().get();
30-
let lines: Vec<String> = text.lines().map(|line| line.to_string()).collect();
34+
let lines: Vec<&str> = text.lines().collect();
3135
let lines_per_thread = (lines.len() + num_threads - 1) / num_threads;
3236
let total_word_count = Arc::new(AtomicUsize::new(0));
33-
let mut handles = Vec::new();
37+
// let mut handles = Vec::new();
3438
let count_fn = Arc::new(count_fn);
39+
let start = Instant::now();
40+
// for i in 0..num_threads {
41+
// let start = lines_per_thread * i;
42+
// let end = min(start + lines_per_thread, lines.len());
43+
// if is_valid_range(start, end, lines.len()) {
44+
// let chunk = lines[start..end].to_vec();
45+
// let count_fn_clone = Arc::clone(&count_fn);
46+
// let total_word_count_clone = total_word_count.clone();
3547

36-
for i in 0..num_threads {
37-
let start = lines_per_thread * i;
38-
let end = min(start + lines_per_thread, lines.len());
39-
let chunk = lines[start..end].to_vec();
40-
let count_fn_clone = Arc::clone(&count_fn);
41-
let total_word_count_clone = total_word_count.clone();
42-
43-
let handle = thread::spawn(move || {
44-
let count = count_fn_clone(&chunk);
45-
total_word_count_clone.fetch_add(count, Ordering::Relaxed);
46-
});
47-
handles.push(handle);
48-
}
48+
// let handle = thread::spawn(move || {
49+
// let count = count_fn_clone(chunk);
50+
// total_word_count_clone.fetch_add(count, Ordering::Relaxed);
51+
// });
52+
// handles.push(handle);
53+
// }
54+
// }
4955

50-
for handle in handles {
51-
handle.join().unwrap();
52-
}
56+
57+
thread::scope(|s| {
58+
for i in 0..num_threads {
59+
let start = lines_per_thread * i;
60+
let end = min(start + lines_per_thread, lines.len());
61+
62+
if is_valid_range(start, end, lines.len()) {
63+
let chunk = &lines[start..end]; // Borrow a slice of `&str`
64+
let count_fn_clone = Arc::clone(&count_fn);
65+
let total_word_count_clone = Arc::clone(&total_word_count);
66+
67+
s.spawn(move || {
68+
let count = count_fn_clone(chunk); // Use the borrowed slice here
69+
total_word_count_clone.fetch_add(count, Ordering::Relaxed);
70+
});
71+
}
72+
}
73+
});
74+
75+
println!("Finish loop in: {:?}", start.elapsed());
76+
77+
// for handle in handles {
78+
// handle.join().unwrap();
79+
// }
5380
total_word_count.load(Ordering::Relaxed)
5481
}
5582

83+
fn is_valid_range(start: usize, end: usize, len: usize) -> bool {
84+
start < end && end <= len
85+
}
5686

57-
fn count_words_in_chunk(chunk: &[String]) -> usize {
87+
fn chunk_text(text: &str, num_chunks: usize) -> Vec<&str> {
88+
let chunk_size = text.len() / num_chunks;
89+
let mut chunks = Vec::new();
90+
let mut start = 0;
91+
92+
while start < text.len() {
93+
let end = min(text.len(), start + chunk_size);
94+
let chunk = &text[start..end];
95+
chunks.push(chunk);
96+
start = end;
97+
}
98+
chunks
99+
}
100+
101+
102+
fn collect_lines_parallel(text: &str, num_threads: usize) -> Vec<&str> {
103+
let mut result: Vec<&str> = Vec::new();
104+
let mut handles = Vec::new();
105+
106+
}
107+
108+
fn count_words_in_chunk(chunk: &[&str]) -> usize {
58109
chunk
59110
.iter()
60111
.flat_map(|line| line.split_whitespace())
61112
.count()
62113
}
63114

64-
fn count_word_occurrences_in_chunk(chunk: &[String], word: &str) -> usize {
115+
fn count_word_occurrences_in_chunk(chunk: &[&str], word: &str) -> usize {
65116
chunk
66117
.iter()
67118
.flat_map(|line| line.split_whitespace())
68119
.filter(|&w| w == word)
69120
.count()
70-
}
121+
}

challenges/wc-command/src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
use wc_command::{count_word_occurrences, count_words, read_file_as_string};
3-
use std::env;
3+
use std::{env, time::Instant};
44

55
fn main() {
66
let args: Vec<String> = env::args().collect();
@@ -16,21 +16,23 @@ fn main() {
1616
eprintln!("Usage: rccwc -w <file>");
1717
return;
1818
}
19+
let start = Instant::now();
1920
let file_path = &args[3];
2021
let text = read_file_as_string(&file_path);
2122
let total_words = count_words(&text);
22-
println!("Total words: {}", total_words);
23+
println!("Total words: {}, elapsed time: {:?}", total_words, start.elapsed());
2324
}
2425
"-wo" => {
2526
if args.len() != 5 {
2627
eprintln!("Usage: rccwc -wc <word> <file_path>");
2728
return;
2829
}
30+
let start = Instant::now();
2931
let word = &args[3];
3032
let file_path = &args[4];
3133
let text = read_file_as_string(&file_path);
3234
let total_occurrences = count_word_occurrences(&text, word.to_string());
33-
println!("Total occurrences of '{}': {} ", word, total_occurrences);
35+
println!("Total occurrences of '{}': {}, elapsed time: {:?}", word, total_occurrences, start.elapsed());
3436
}
3537
_ => {
3638
eprintln!("Invalid option. Usage: rccwc -w <file_path> or -wo <word> <file_path>")

challenges/wc-command/tests/test.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,59 @@
11
#[cfg(test)]
22
mod tests {
3+
use wc_command::{count_word_occurrences, count_words};
34

5+
#[test]
6+
fn test_count_words_empty() {
7+
let text = "";
8+
assert_eq!(count_words(text), 0)
9+
}
10+
11+
#[test]
12+
fn test_count_words_single_line() {
13+
let text = "hello world";
14+
assert_eq!(count_words(text), 2);
15+
}
16+
17+
#[test]
18+
fn test_count_words_multiple_lines() {
19+
let text = "Hello world\nThis is a test\nRust is awesome";
20+
assert_eq!(count_words(text), 9);
21+
}
22+
23+
#[test]
24+
fn test_count_word_occurrences_empty() {
25+
let text = "";
26+
let word = "rust".to_string();
27+
assert_eq!(count_word_occurrences(text, word), 0);
28+
}
429

530
#[test]
6-
fn test_solve() {
7-
// Call the solve function and check for expected results
31+
fn test_count_word_occurrences_single_line() {
32+
let text = "performance and memory safety";
33+
let word = "performance".to_string();
34+
assert_eq!(count_word_occurrences(text, word), 1);
835
}
36+
37+
#[test]
38+
fn test_count_word_occurrences_multiple_occurrences() {
39+
let text = "Hello world\nThis is a test\nThis test is just a test";
40+
let word = "test".to_string();
41+
assert_eq!(count_word_occurrences(text, word), 3);
42+
}
43+
44+
#[test]
45+
fn test_count_word_large_input() {
46+
let text = "hello world ".repeat(1_000_000);
47+
assert_eq!(count_words(&text), 2_000_000);
48+
}
49+
50+
#[test]
51+
fn test_count_word_occurrences_large_input() {
52+
let text = "this is a test\nthis is another test\nfinally another test\n".repeat(1_000_000);
53+
let test = "test".to_string();
54+
let another = "another".to_string();
55+
assert_eq!(count_word_occurrences(&text, test), 3_000_000);
56+
assert_eq!(count_word_occurrences(&text, another), 2_000_000);
57+
}
58+
959
}

0 commit comments

Comments
 (0)