From 91b9b4b4417dc7e137ac3454ed19ff523abf91d9 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Sun, 18 May 2014 21:42:25 +0200 Subject: [PATCH 1/4] tr: use SmallIntMap instead of HashMap --- tr/tr.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tr/tr.rs b/tr/tr.rs index 76a944405..901330aca 100644 --- a/tr/tr.rs +++ b/tr/tr.rs @@ -12,7 +12,8 @@ extern crate collections; extern crate getopts; -use collections::hashmap::{HashMap, HashSet}; +use collections::hashmap::HashSet; +use collections::smallintmap::SmallIntMap; use getopts::OptGroup; use std::char::from_u32; use std::io::print; @@ -99,21 +100,21 @@ fn delete(set: Vec) { } fn tr(set1: &[char], set2: &[char]) { - let mut map = HashMap::new(); + let mut map = SmallIntMap::::new(); let mut out = stdout(); for i in range(0, set1.len()) { if i >= set2.len() { - map.insert(set1[i], set2[set2.len()-1]); + map.insert(set1[i] as uint, set2[set2.len()-1]); } else { - map.insert(set1[i], set2[i]); + map.insert(set1[i] as uint, set2[i]); } } for c in stdin().chars() { match c { Ok(inc) => { - let trc = match map.find(&inc) { + let trc = match map.find(&(inc as uint)) { Some(t) => *t, None => inc, }; From 1669c764428ed0c5cce9ba7e271ef55861a1d230 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Sun, 18 May 2014 21:47:53 +0200 Subject: [PATCH 2/4] tr: use BitvSet instead of HashSet --- tr/tr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tr/tr.rs b/tr/tr.rs index 901330aca..e75976804 100644 --- a/tr/tr.rs +++ b/tr/tr.rs @@ -12,7 +12,7 @@ extern crate collections; extern crate getopts; -use collections::hashmap::HashSet; +use collections::bitv::BitvSet; use collections::smallintmap::SmallIntMap; use getopts::OptGroup; use std::char::from_u32; @@ -83,16 +83,16 @@ fn expand_set(s: &str) -> Vec { } fn delete(set: Vec) { - let mut hset = HashSet::new(); + let mut bset = BitvSet::new(); let mut out = stdout(); for &c in set.iter() { - hset.insert(c); + bset.insert(c as uint); } for c in stdin().chars() { match c { - Ok(c) if !hset.contains(&c) => out.write_char(c).unwrap(), + Ok(c) if !bset.contains(&(c as uint)) => out.write_char(c).unwrap(), Ok(_) => (), Err(err) => fail!("{}", err), }; From 5fb465a9cd49a82d32d619da119220dd5033d0ab Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Sun, 18 May 2014 22:14:27 +0200 Subject: [PATCH 3/4] tr: add --complement --- tr/tr.rs | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/tr/tr.rs b/tr/tr.rs index e75976804..cddbc14ba 100644 --- a/tr/tr.rs +++ b/tr/tr.rs @@ -1,4 +1,5 @@ #![crate_id(name="tr", vers="1.0.0", author="Michael Gehring")] +#![feature(macro_rules)] /* * This file is part of the uutils coreutils package. @@ -22,6 +23,9 @@ use std::iter::FromIterator; use std::os; use std::vec::Vec; +#[path="../common/util.rs"] +mod util; + static NAME : &'static str = "tr"; static VERSION : &'static str = "1.0.0"; @@ -82,7 +86,7 @@ fn expand_set(s: &str) -> Vec { set } -fn delete(set: Vec) { +fn delete(set: Vec, complement: bool) { let mut bset = BitvSet::new(); let mut out = stdout(); @@ -90,9 +94,15 @@ fn delete(set: Vec) { bset.insert(c as uint); } + let is_allowed = if complement { + |c: char| bset.contains(&(c as uint)) + } else { + |c: char| !bset.contains(&(c as uint)) + }; + for c in stdin().chars() { match c { - Ok(c) if !bset.contains(&(c as uint)) => out.write_char(c).unwrap(), + Ok(c) if is_allowed(c) => out.write_char(c).unwrap(), Ok(_) => (), Err(err) => fail!("{}", err), }; @@ -139,6 +149,8 @@ fn usage(opts: &[OptGroup]) { pub fn main() { let args: Vec = os::args().iter().map(|x| x.to_strbuf()).collect(); let opts = [ + getopts::optflag("c", "complement", "use the complement of SET1"), + getopts::optflag("C", "", "same as -c"), getopts::optflag("d", "delete", "delete characters in SET1"), getopts::optflag("h", "help", "display this help and exit"), getopts::optflag("V", "version", "output version information and exit"), @@ -146,12 +158,15 @@ pub fn main() { let matches = match getopts::getopts(args.tail(), opts) { Ok(m) => m, - Err(err) => fail!("{}", err.to_err_msg()), + Err(err) => { + show_error!(1, "{}", err.to_err_msg()); + return; + } }; if matches.opt_present("help") { usage(opts); - return + return; } if matches.opt_present("version") { @@ -162,15 +177,21 @@ pub fn main() { if matches.free.len() == 0 { usage(opts); os::set_exit_status(1); - return + return; } let dflag = matches.opt_present("d"); + let cflag = matches.opts_present(["c".to_strbuf(), "C".to_strbuf()]); let sets = matches.free; + if cflag && !dflag { + show_error!(1, "-c is only supported with -d"); + return; + } + if dflag { let set1 = expand_set(sets.get(0).as_slice()); - delete(set1); + delete(set1, cflag); } else { let set1 = expand_set(sets.get(0).as_slice()); let set2 = expand_set(sets.get(1).as_slice()); From 358b7a115511491ee856d7178dcd4ce44e8b2b4b Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Sun, 18 May 2014 22:20:07 +0200 Subject: [PATCH 4/4] tr: add -c/-d tests --- tr/test.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tr/test.rs b/tr/test.rs index b6fc1456d..e62e79ed9 100644 --- a/tr/test.rs +++ b/tr/test.rs @@ -1,7 +1,7 @@ use std::io::process::Command; -fn run(input: &str, set1: &str, set2: &str) -> Vec { - let mut process = Command::new("build/tr").arg(set1).arg(set2).spawn().unwrap(); +fn run(input: &str, args: &[&'static str]) -> Vec { + let mut process = Command::new("build/tr").args(args).spawn().unwrap(); process.stdin.take_unwrap().write_str(input).unwrap(); @@ -14,20 +14,32 @@ fn run(input: &str, set1: &str, set2: &str) -> Vec { #[test] fn test_toupper() { - let out = run("!abcd!", "a-z", "A-Z"); + let out = run("!abcd!", ["a-z", "A-Z"]); assert_eq!(out.as_slice(), bytes!("!ABCD!")); } #[test] fn test_small_set2() { - let out = run("@0123456789", "0-9", "X"); + let out = run("@0123456789", ["0-9", "X"]); assert_eq!(out.as_slice(), bytes!("@XXXXXXXXXX")); } #[test] fn test_unicode() { - let out = run("(,°□°), ┬─┬", ", ┬─┬", "╯︵┻━┻"); + let out = run("(,°□°), ┬─┬", [", ┬─┬", "╯︵┻━┻"]); assert_eq!(out.as_slice(), bytes!("(╯°□°)╯︵┻━┻")); } +#[test] +fn test_delete() { + let out = run("aBcD", ["-d", "a-z"]); + assert_eq!(out.as_slice(), bytes!("BD")); +} + +#[test] +fn test_delete_complement() { + let out = run("aBcD", ["-d", "-c", "a-z"]); + assert_eq!(out.as_slice(), bytes!("ac")); +} +