// xfail-test extern mod std; use core::cast::transmute; use core::i32::range; use core::libc::{STDIN_FILENO, c_int, fdopen, fgets, fileno, fopen, fstat}; use core::libc::{stat, strlen}; use core::ptr::null; use core::unstable::intrinsics::init; use core::vec::{reverse, slice}; use std::sort::quick_sort3; static LINE_LEN: uint = 80; static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ]; static TABLE_SIZE: uint = 2 << 16; static OCCURRENCES: [&'static str, ..5] = [ "GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT", ]; // Code implementation #[deriving(Eq, Ord)] struct Code(u64); impl Code { fn hash(&self) -> u64 { **self } #[inline(always)] fn push_char(&self, c: u8) -> Code { Code((**self << 2) + (pack_symbol(c) as u64)) } fn rotate(&self, c: u8, frame: i32) -> Code { Code(*self.push_char(c) & ((1u64 << (2 * (frame as u64))) - 1)) } fn pack(string: &str) -> Code { let mut code = Code(0u64); for uint::range(0, string.len()) |i| { code = code.push_char(string[i]); } code } // XXX: Inefficient. fn unpack(&self, frame: i32) -> ~str { let mut key = **self; let mut result = ~[]; for (frame as uint).times { result.push(unpack_symbol((key as u8) & 3)); key >>= 2; } reverse(result); str::from_bytes(result) } } // Hash table implementation trait TableCallback { fn f(&self, entry: &mut Entry); } struct BumpCallback; impl TableCallback for BumpCallback { fn f(&self, entry: &mut Entry) { entry.count += 1; } } struct PrintCallback(&'static str); impl TableCallback for PrintCallback { fn f(&self, entry: &mut Entry) { println(fmt!("%d\t%s", entry.count as int, **self)); } } struct Entry { code: Code, count: i32, next: Option<~Entry>, } struct Table { count: i32, items: [Option<~Entry>, ..TABLE_SIZE] } impl Table { fn new() -> Table { Table { count: 0, items: [ None, ..TABLE_SIZE ], } } fn search_remainder(item: &mut Entry, key: Code, c: C) { match item.next { None => { let mut entry = ~Entry { code: key, count: 0, next: None, }; c.f(entry); item.next = Some(entry); } Some(ref mut entry) => { if entry.code == key { c.f(*entry); return; } Table::search_remainder(*entry, key, c) } } } fn lookup(&mut self, key: Code, c: C) { let index = *key % (TABLE_SIZE as u64); { if self.items[index].is_none() { let mut entry = ~Entry { code: key, count: 0, next: None, }; c.f(entry); self.items[index] = Some(entry); return; } } { let mut entry = &mut *self.items[index].get_mut_ref(); if entry.code == key { c.f(*entry); return; } Table::search_remainder(*entry, key, c) } } fn each(&self, f: &fn(entry: &Entry) -> bool) { for self.items.each |item| { match *item { None => {} Some(ref item) => { let mut item: &Entry = *item; loop { if !f(item) { return; } match item.next { None => break, Some(ref next_item) => item = &**next_item, } } } }; } } } // Main program fn pack_symbol(c: u8) -> u8 { match c { 'a' as u8 | 'A' as u8 => 0, 'c' as u8 | 'C' as u8 => 1, 'g' as u8 | 'G' as u8 => 2, 't' as u8 | 'T' as u8 => 3, _ => fail!(c.to_str()) } } fn unpack_symbol(c: u8) -> u8 { TABLE[c] } fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] { loop { buf = slice(buf, 1, buf.len()); if buf.len() == 0 { break; } if buf[0] != (' ' as u8) && buf[0] != ('\t' as u8) && buf[0] != ('\n' as u8) && buf[0] != 0 { break; } } buf } #[inline(never)] fn read_stdin() -> ~[u8] { unsafe { let mode = "r"; //let stdin = fdopen(STDIN_FILENO as c_int, transmute(&mode[0])); let path = "knucleotide-input.txt"; let stdin = fopen(transmute(&path[0]), transmute(&mode[0])); let mut st: stat = init(); fstat(fileno(stdin), &mut st); let mut buf = vec::from_elem(st.st_size as uint, 0); let header = str::byte_slice_no_callback(">THREE"); let header = vec::slice(header, 0, 6); { let mut window: &mut [u8] = buf; loop { fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin); { if vec::slice(window, 0, 6) == header { break; } } } while fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin) != null() { window = vec::mut_slice(window, strlen(transmute(&window[0])) as uint, window.len()); } } buf } } #[inline(never)] #[fixed_stack_segment] fn generate_frequencies(frequencies: &mut Table, mut input: &[u8], frame: i32) { let mut code = Code(0); // Pull first frame. for (frame as uint).times { code = code.push_char(input[0]); input = next_char(input); } frequencies.lookup(code, BumpCallback); while input.len() != 0 && input[0] != ('>' as u8) { code = code.rotate(input[0], frame); frequencies.lookup(code, BumpCallback); input = next_char(input); } } #[inline(never)] #[fixed_stack_segment] fn print_frequencies(frequencies: &Table, frame: i32) { let mut vector = ~[]; for frequencies.each |entry| { vector.push((entry.code, entry.count)); } quick_sort3(vector); let mut total_count = 0; for vector.each |&(_, count)| { total_count += count; } for vector.each |&(key, count)| { println(fmt!("%s %.3f", key.unpack(frame), (count as float * 100.0) / (total_count as float))); } } fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) { frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence)) } #[fixed_stack_segment] fn main() { let input = read_stdin(); let mut frequencies = ~Table::new(); generate_frequencies(frequencies, input, 1); print_frequencies(frequencies, 1); *frequencies = Table::new(); generate_frequencies(frequencies, input, 2); print_frequencies(frequencies, 2); for range(0, 5) |i| { let occurrence = OCCURRENCES[i]; *frequencies = Table::new(); generate_frequencies(frequencies, input, occurrence.len() as i32); print_occurrences(frequencies, occurrence); } }