From c1d6c4151094b0ce3ba08187e0db12e96ea397ca Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Mon, 3 Sep 2018 18:50:37 -0700 Subject: [PATCH] programming rust: finish chapter 2. --- lr/ch2/gcd/Cargo.toml | 6 ++ lr/ch2/gcd/src/main.rs | 43 +++++++++ lr/ch2/iron-gcd/Cargo.toml | 10 +++ lr/ch2/iron-gcd/src/main.rs | 96 ++++++++++++++++++++ lr/ch2/mandelbrot/Cargo.toml | 9 ++ lr/ch2/mandelbrot/src/main.rs | 165 ++++++++++++++++++++++++++++++++++ ostep/hw5.txt | 35 ++++++++ 7 files changed, 364 insertions(+) create mode 100644 lr/ch2/gcd/Cargo.toml create mode 100644 lr/ch2/gcd/src/main.rs create mode 100644 lr/ch2/iron-gcd/Cargo.toml create mode 100644 lr/ch2/iron-gcd/src/main.rs create mode 100644 lr/ch2/mandelbrot/Cargo.toml create mode 100644 lr/ch2/mandelbrot/src/main.rs create mode 100644 ostep/hw5.txt diff --git a/lr/ch2/gcd/Cargo.toml b/lr/ch2/gcd/Cargo.toml new file mode 100644 index 0000000..49854a3 --- /dev/null +++ b/lr/ch2/gcd/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "gcd" +version = "0.1.0" +authors = ["Kyle Isom "] + +[dependencies] diff --git a/lr/ch2/gcd/src/main.rs b/lr/ch2/gcd/src/main.rs new file mode 100644 index 0000000..34fbea7 --- /dev/null +++ b/lr/ch2/gcd/src/main.rs @@ -0,0 +1,43 @@ +use std::io::Write; +use std::str::FromStr; + +fn gcd(mut n: u64, mut m: u64) -> u64 { + assert!(n != 0 && m != 0); + while m != 0 { + if m < n { + let t = m; + m = n; + n = t; + } + m = m % n; + } + n +} + +#[test] +fn test_gcd() { + assert_eq!(gcd(14, 15), 1); + assert_eq!(gcd(2 * 3 * 5 * 11 * 17, + 3 * 7 * 11 * 13 * 19), + 3 * 11); +} + +fn main() { + let mut numbers = Vec::new(); + + for arg in std::env::args().skip(1) { + numbers.push(u64::from_str(&arg).expect("error parsing argument as u64")); + } + + if numbers.len() == 0 { + writeln!(std::io::stderr(), "Usage: gcd NUMBER...").unwrap(); + std::process::exit(1); + } + + let mut d = numbers[0]; + for m in &numbers[1..] { + d = gcd(d, *m); + } + + println!("The greatest common divisor of {:?} is {}", numbers, d); +} diff --git a/lr/ch2/iron-gcd/Cargo.toml b/lr/ch2/iron-gcd/Cargo.toml new file mode 100644 index 0000000..d218551 --- /dev/null +++ b/lr/ch2/iron-gcd/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "iron-gcd" +version = "0.1.0" +authors = ["Kyle Isom "] + +[dependencies] +iron = "0.5.1" +mime = "0.2.3" +router = "0.5.1" +urlencoded = "0.5.0" diff --git a/lr/ch2/iron-gcd/src/main.rs b/lr/ch2/iron-gcd/src/main.rs new file mode 100644 index 0000000..8fd677d --- /dev/null +++ b/lr/ch2/iron-gcd/src/main.rs @@ -0,0 +1,96 @@ +extern crate iron; +extern crate router; +extern crate urlencoded; +#[macro_use] extern crate mime; + +use std::str::FromStr; +use urlencoded::UrlEncodedBody; + +use iron::prelude::*; +use iron::status; +use router::Router; + +fn gcd(mut n: u64, mut m: u64) -> u64 { + assert!(n != 0 && m != 0); + while m != 0 { + if m < n { + let t = m; + m = n; + n = t; + } + m = m % n; + } + n +} + +fn main() { + let mut router = Router::new(); + + router.get("/", get_form, "root"); + router.post("/gcd", post_gcd, "gcd"); + + println!("Serving on http://localhost:3000..."); + Iron::new(router).http("localhost:3000").unwrap(); +} + +fn get_form(_request: &mut Request) -> IronResult { + let mut response = Response::new(); + + response.set_mut(status::Ok); + response.set_mut(mime!(Text/Html; Charset=Utf8)); + response.set_mut(r#" + GCD calculator +
+ + + +
+ "#); + + Ok(response) +} + +fn post_gcd(request: &mut Request) -> IronResult { + let mut response = Response::new(); + + let form_data = match request.get_ref::() { + Err(e) => { + response.set_mut(status::BadRequest); + response.set_mut(format!("Error parsing form data: {:?}\n", e)); + return Ok(response); + } + Ok(map) => map + }; + + let unparsed_numbers = match form_data.get("n") { + None => { + response.set_mut(status::BadRequest); + response.set_mut(format!("Form has no 'n' parameters!\n")); + return Ok(response); + } + Some(nums) => nums + }; + + let mut numbers = Vec::new(); + for unparsed in unparsed_numbers { + match u64::from_str(&unparsed) { + Err(_) => { + response.set_mut(status::BadRequest); + response.set_mut(format!("Value for 'n' parameter isn't a number {:?}\n", unparsed)); + return Ok(response); + } + Ok(n) => { numbers.push(n); } + } + } + + let mut d = numbers[0]; + for m in &numbers[1..] { + d = gcd(d, *m); + } + + response.set_mut(status::Ok); + response.set_mut(mime!(Text/Html; Charset=Utf8)); + response.set_mut(format!("The GCD of {:?} is {}.\n", numbers, d)); + + Ok(response) +} diff --git a/lr/ch2/mandelbrot/Cargo.toml b/lr/ch2/mandelbrot/Cargo.toml new file mode 100644 index 0000000..463a2e7 --- /dev/null +++ b/lr/ch2/mandelbrot/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "mandelbrot" +version = "0.1.0" +authors = ["Kyle Isom "] + +[dependencies] +crossbeam = "0.2.8" +image = "0.13.0" +num = "0.1.27" \ No newline at end of file diff --git a/lr/ch2/mandelbrot/src/main.rs b/lr/ch2/mandelbrot/src/main.rs new file mode 100644 index 0000000..d6ba629 --- /dev/null +++ b/lr/ch2/mandelbrot/src/main.rs @@ -0,0 +1,165 @@ +extern crate crossbeam; +extern crate image; +extern crate num; + +use image::png::PNGEncoder; +use image::ColorType; +use num::Complex; +use std::fs::File; +use std::io::Write; +use std::str::FromStr; + +#[allow(dead_code)] + +fn parse_pair(s: &str, separator: char) -> Option<(T, T)> { + match s.find(separator) { + None => None, + Some(index) => match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) { + (Ok(l), Ok(r)) => Some((l, r)), + _ => None, + }, + } +} + +fn parse_complex(s: &str) -> Option> { + match parse_pair(s, ',') { + Some((re, im)) => Some(Complex { re, im }), + None => None, + } +} + +#[test] +fn test_parse_complex() { + assert_eq!( + parse_complex("1.25,-0.0625"), + Some(Complex { + re: 1.25, + im: -0.0625 + }) + ); + assert_eq!(parse_complex(",-0.0625", None)) +} + +fn escape_time(c: Complex, limit: u32) -> Option { + let mut z = Complex { re: 0.0, im: 0.0 }; + for i in 0..limit { + z = z * z + c; + if z.norm_sqr() > 4.0 { + return Some(i); + } + } + + None +} + +fn pixel_to_point( + bounds: (usize, usize), + pixel: (usize, usize), + upper_left: Complex, + lower_right: Complex, +) -> Complex { + let (width, height) = ( + lower_right.re - upper_left.re, + upper_left.im - lower_right.im, + ); + Complex { + re: upper_left.re + pixel.0 as f64 * width / bounds.0 as f64, + // Subtraction because pixel.1 increases downward, but the imaginary + // component increases upward. + im: upper_left.im - pixel.1 as f64 * height / bounds.1 as f64, + } +} + +#[test] +fn test_pixel_to_point() { + assert_eq!( + pixel_to_point( + (100, 100), + (25, 75), + Complex { re: -1.0, im: 1.0 }, + Complex { re: 1.0, im: -1.0 } + ), + Complex { re: -0.5, im: -0.5 } + ); +} + +fn render( + pixels: &mut [u8], + bounds: (usize, usize), + upper_left: Complex, + lower_right: Complex, +) { + assert!(pixels.len() == bounds.0 * bounds.1); + + for row in 0..bounds.1 { + for column in 0..bounds.1 { + let point = pixel_to_point(bounds, (column, row), upper_left, lower_right); + pixels[row * bounds.0 + column] = match escape_time(point, 255) { + None => 0, + Some(count) => 255 - count as u8, + }; + } + } +} + +fn write_image( + filename: &str, + pixels: &[u8], + bounds: (usize, usize), +) -> Result<(), std::io::Error> { + let output = File::create(filename)?; + + let encoder = PNGEncoder::new(output); + encoder.encode( + &pixels, + bounds.0 as u32, + bounds.1 as u32, + ColorType::Gray(8), + )?; + Ok(()) +} + +fn main() { + let args: Vec = std::env::args().collect(); + + if args.len() != 5 { + writeln!( + std::io::stderr(), + "Usage: mandelbrot FILE PIXELS UPPERLEFT LOWERRIGHT" + ).unwrap(); + writeln!( + std::io::stderr(), + "Example: {} mandel.png 1000x750 -1.20,0.35 -1,0.20", + args[0] + ).unwrap(); + std::process::exit(1); + } + + let bounds: (usize, usize) = parse_pair(&args[2], 'x').expect("error parsing image dimensions"); + let upper_left = parse_complex(&args[3]).expect("error parsing upper left corner point"); + let lower_right = parse_complex(&args[4]).expect("error parsing lower right corner point"); + + let mut pixels = vec![0; bounds.0 * bounds.1]; + + let threads = 8; + let rows_per_band = bounds.1 / threads + 1; + { + let bands: Vec<&mut [u8]> = pixels.chunks_mut(rows_per_band * bounds.0).collect(); + crossbeam::scope(|spawner| { + for (i, band) in bands.into_iter().enumerate() { + let top = rows_per_band * i; + let height = band.len() / bounds.0; + let band_bounds = (bounds.0, height); + let band_upper_left = pixel_to_point(bounds, (0, top), upper_left, lower_right); + let band_lower_right = + pixel_to_point(bounds, (bounds.0, top + height), upper_left, lower_right); + + spawner.spawn(move || { + println!("spawned: {}", i); + render(band, band_bounds, band_upper_left, band_lower_right); + }); + } + }); + } + write_image(&args[1], &pixels, bounds).expect("error writing PNG file"); +} diff --git a/ostep/hw5.txt b/ostep/hw5.txt new file mode 100644 index 0000000..0ca7752 --- /dev/null +++ b/ostep/hw5.txt @@ -0,0 +1,35 @@ +Homework for chapter 5: Interlude: Process API + +1. Write a program that calls fork(). Before calling fork(), have the main +program access a variable and set its value to something. What value is the +variable in the child process? What happens to the variable when both the child +and the parent change the value of x? + +2. Write a program that opens a new file with open() and then calls fork() to +create a new process. Can both the child and the parent access the file +descriptor returned by open()? What happens when they are writing to the file +concurrently? + +3. Write another program using fork(). The child process should print "hello", +the parent process should print "goodbye". You should try to ensure that the +child process always prints first; can you do this without calling wait() in +the parent? + +4. Write a program that calls fork() and then calls some form of exec() to run +/bin/ls. See if you can try all the variants of exec(), including execl(), +execle(), execlp(), execv(), execvp(), and execevP(). Why do you think there +are so many variants of the same basic call? + +5. Now write a program that uses wait() to wait for the child process to finish +in the parent. What does wait() return? What happens if you use wait() in the +child()? + +6. Write a slight modification of the previous program, this time using +waitpid() instead of wait(). When would waitpid() be useful? + +7. Write a program that creates a child process, and then in the child close +standard output. What happens if the child calls printf() to print some output +after closing the descriptor? + +8. Write a program that creates two children, and connects the standard output +of one to the standard input of the other using the pipe() system call.