X-Git-Url: https://git.ralfj.de/rust-101.git/blobdiff_plain/5f6e02d64e3789115ea4327a045b8ad3c39b1808..a16f3d282a991ef1c28fded477f9a1d30c6f3b5c:/solutions/src/rgrep.rs?ds=sidebyside diff --git a/solutions/src/rgrep.rs b/solutions/src/rgrep.rs index a3b74cc..e64d2fd 100644 --- a/solutions/src/rgrep.rs +++ b/solutions/src/rgrep.rs @@ -1,5 +1,5 @@ use std::io::prelude::*; -use std::{io, fs, thread, process}; +use std::{io, fs, thread, process, cmp}; use std::sync::mpsc::{sync_channel, SyncSender, Receiver}; use std::sync::Arc; @@ -23,6 +23,17 @@ struct Line { line: usize, } +impl PartialEq for Line { + fn eq(&self, other: &Line) -> bool { + self.data.eq(&other.data) + } +} +impl PartialOrd for Line { + fn partial_cmp(&self, other: &Line) -> Option { + self.data.partial_cmp(&other.data) + } +} + fn read_files(options: Arc, out_channel: SyncSender) { for (fileidx, file) in options.files.iter().enumerate() { let file = fs::File::open(file).unwrap(); @@ -42,6 +53,33 @@ fn filter_lines(options: Arc, in_channel: Receiver, out_channel: } } +fn sort(data: &mut [T]) { + if data.len() < 2 { return; } + + let mut lpos = 1; + let mut rpos = data.len(); + // Invariant: pivot is data[0]; (0,lpos) is <= pivot; [rpos,len) is >= pivot; lpos < rpos + loop { + while lpos < rpos && data[lpos] <= data[0] { + lpos += 1; + } + while rpos > lpos && data[rpos-1] >= data[0] { + rpos -= 1; + } + if rpos == lpos { + break; + } + + data.swap(lpos, rpos-1); + } + + data.swap(0, lpos-1); // put pivot in the right place + + let (part1, part2) = data.split_at_mut(lpos); + sort(&mut part1[..lpos-1]); + sort(part2); +} + fn output_lines(options: Arc, in_channel: Receiver) { match options.output_mode { Print => { @@ -54,8 +92,11 @@ fn output_lines(options: Arc, in_channel: Receiver) { println!("{} hits for {}.", count, options.pattern); }, SortAndPrint => { - let _data: Vec = in_channel.iter().collect(); - unimplemented!() + let mut data: Vec = in_channel.iter().collect(); + sort(&mut data[..]); + for line in data.iter() { + println!("{}:{}: {}", options.files[line.file], line.line, line.data); + } } } } @@ -93,7 +134,7 @@ fn get_options() -> Options { fn run(options: Options) { let options = Arc::new(options); - // Set up the chain of threads. Use `sync_channel` with buffer-size of 16 to avoid needlessly filling RAM. + // This sets up the chain of threads. Use `sync_channel` with buffer-size of 16 to avoid needlessly filling RAM. let (line_sender, line_receiver) = sync_channel(16); let (filtered_sender, filtered_receiver) = sync_channel(16);