Skip to content

Instantly share code, notes, and snippets.

@malleusinferni
Last active August 26, 2016 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malleusinferni/2d7a51687f399c82747db20e724a76ba to your computer and use it in GitHub Desktop.
Save malleusinferni/2d7a51687f399c82747db20e724a76ba to your computer and use it in GitHub Desktop.
extern crate rand;
extern crate time;
use std::path::Path;
use std::iter::Peekable;
use std::slice;
struct Parser<'input> {
input: Peekable<slice::Iter<'input, u8>>,
line: usize,
}
#[derive(Debug)]
struct Row(u32, u32, f32);
#[derive(Debug)]
struct LineNr(usize);
impl<'input> Parser<'input> {
fn new(input: &'input [u8]) -> Self {
Parser {
input: input.iter().peekable(),
line: 1,
}
}
#[inline(always)]
fn parse_row(&mut self) -> Result<Row, LineNr> {
let src = try!(self.parse_int());
try!(self.expect(b' '));
try!(self.expect(b'-'));
try!(self.expect(b' '));
let dst = try!(self.parse_int());
try!(self.expect(b','));
let magnitude = try!(self.parse_float());
try!(self.parse_eol());
Ok(Row(src, dst, magnitude))
}
#[inline(always)]
fn parse_int(&mut self) -> Result<u32, LineNr> {
let mut accum = 0;
while let Some(n) = self.parse_digit() {
accum *= 10;
accum += n;
}
Ok(accum)
}
#[inline(always)]
fn parse_float(&mut self) -> Result<f32, LineNr> {
let a = try!(self.parse_int()) as f32;
try!(self.expect(b'.'));
let mut b = 0.0f32;
let mut pow = 1;
while let Some(n) = self.parse_digit() {
b = b.mul_add(10.0, n as f32);
pow += 1;
}
Ok(a + b * (10.0f32).powi(-pow + 1))
}
#[inline(always)]
fn parse_digit(&mut self) -> Option<u32> {
match self.input.peek() {
Some(&&u) if b'0' <= u && u <= b'9' => {
self.input.next();
Some((u - b'0') as u32)
},
_ => None,
}
}
#[inline(always)]
fn parse_eol(&mut self) -> Result<(), LineNr> {
match self.input.next() {
None => Ok(()),
Some(&b'\n') => { self.line += 1; Ok(()) },
_ => Err(LineNr(self.line)),
}
}
#[inline(always)]
fn expect(&mut self, byte: u8) -> Result<(), LineNr> {
match self.input.next() {
Some(&n) if n == byte => Ok(()),
_ => Err(LineNr(self.line)),
}
}
}
impl<'input> Iterator for Parser<'input> {
type Item = Result<Row, LineNr>;
fn next(&mut self) -> Option<Self::Item> {
if self.input.peek().is_some() {
Some(self.parse_row())
} else {
None
}
}
}
#[test]
fn test_parse() {
let mut parser = Parser::new(b"2224 - 26466,79.2503490704\n");
let Row(src, dst, magnitude) = parser.parse_row().expect("Bad parse");
assert_eq!(src, 2224);
assert_eq!(dst, 26466);
assert_eq!(magnitude, 79.2503490704);
}
fn write_test_data(path: &Path) {
use std::io::Write;
use std::fs::File;
use rand::{Rng, StdRng};
println!("Generating test data...");
let mut rng = StdRng::new().expect("Couldn't start RNG");
let mut outfile = File::create(path).expect("Couln't open");
for _ in 0 .. 100_000 {
let src: u32 = rng.gen();
let dst: u32 = rng.gen();
let magnitude: f64 = rng.gen::<f64>() * 10.0 + 25.0;
writeln!(&mut outfile, "{} - {},{}", src, dst, magnitude)
.expect("Couldn't write");
}
println!("Done.");
}
fn read_test_data(path: &Path) {
use std::io::Read;
use std::fs::File;
let mut infile = File::open(path).expect("Couldn't open");
let mut buf = Vec::with_capacity(100_000);
infile.read_to_end(&mut buf).expect("Oh no");
for result in Parser::new(&buf) {
result.expect("Parse failed");
}
}
fn main() {
let path = "test.dat";
write_test_data(path.as_ref());
let start_s = time::precise_time_s();
let start_ns = time::precise_time_ns();
read_test_data(path.as_ref());
let end_s = time::precise_time_s();
let end_ns = time::precise_time_ns();
let duration_ns = end_ns - start_ns;
let per_iter = duration_ns / 100_000;
println!("Execution took {} seconds", end_s - start_s);
println!("{} ns per iteration", per_iter);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment