1 // The Computer Language Benchmarks Game
2 // http://benchmarksgame.alioth.debian.org/
4 // contributed by the Rust Project Developers
6 // Copyright (c) 2014 The Rust Project Developers
8 // All rights reserved.
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
14 // - Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
17 // - Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in
19 // the documentation and/or other materials provided with the
22 // - Neither the name of "The Computer Language Benchmarks Game" nor
23 // the name of "The Computer Language Shootout Benchmarks" nor the
24 // names of its contributors may be used to endorse or promote
25 // products derived from this software without specific prior
26 // written permission.
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 // OF THE POSSIBILITY OF SUCH DAMAGE.
41 // ignore-android see #10393 #13206
43 #![feature(associated_types, slicing_syntax)]
45 use std::ascii::OwnedAsciiExt;
46 use std::iter::repeat;
49 use std::thread::Thread;
51 static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
52 static TABLE_SIZE: uint = 2 << 16;
54 static OCCURRENCES: [&'static str;5] = [
62 // Code implementation
64 #[derive(PartialEq, PartialOrd, Ord, Eq)]
70 fn hash(&self) -> u64 {
71 let Code(ret) = *self;
75 fn push_char(&self, c: u8) -> Code {
76 Code((self.hash() << 2) + (pack_symbol(c) as u64))
79 fn rotate(&self, c: u8, frame: uint) -> Code {
80 Code(self.push_char(c).hash() & ((1u64 << (2 * frame)) - 1))
83 fn pack(string: &str) -> Code {
84 string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
87 fn unpack(&self, frame: uint) -> String {
88 let mut key = self.hash();
89 let mut result = Vec::new();
90 for _ in range(0, frame) {
91 result.push(unpack_symbol((key as u8) & 3));
96 String::from_utf8(result).unwrap()
100 // Hash table implementation
102 trait TableCallback {
103 fn f(&self, entry: &mut Entry);
108 impl TableCallback for BumpCallback {
109 fn f(&self, entry: &mut Entry) {
114 struct PrintCallback(&'static str);
116 impl TableCallback for PrintCallback {
117 fn f(&self, entry: &mut Entry) {
118 let PrintCallback(s) = *self;
119 println!("{}\t{}", entry.count as int, s);
126 next: Option<Box<Entry>>,
130 items: Vec<Option<Box<Entry>>>
134 cur: Option<&'a Entry>,
135 items: slice::Iter<'a, Option<Box<Entry>>>,
141 items: range(0, TABLE_SIZE).map(|_| None).collect()
145 fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
148 let mut entry = box Entry {
154 item.next = Some(entry);
156 Some(ref mut entry) => {
157 if entry.code == key {
162 Table::search_remainder(&mut **entry, key, c)
167 fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
168 let index = key.hash() % (TABLE_SIZE as u64);
171 if self.items[index as uint].is_none() {
172 let mut entry = box Entry {
178 self.items[index as uint] = Some(entry);
184 let entry = self.items[index as uint].as_mut().unwrap();
185 if entry.code == key {
190 Table::search_remainder(&mut **entry, key, c)
194 fn iter(&self) -> Items {
195 Items { cur: None, items: self.items.iter() }
199 impl<'a> Iterator for Items<'a> {
200 type Item = &'a Entry;
202 fn next(&mut self) -> Option<&'a Entry> {
203 let ret = match self.cur {
207 match self.items.next() {
210 Some(&Some(ref a)) => { i = &**a; break }
213 self.cur = Some(&*i);
219 None => { self.cur = None; }
220 Some(ref next) => { self.cur = Some(&**next); }
228 fn pack_symbol(c: u8) -> u8 {
234 _ => panic!("{}", c as char),
238 fn unpack_symbol(c: u8) -> u8 {
242 fn generate_frequencies(mut input: &[u8], frame: uint) -> Table {
243 let mut frequencies = Table::new();
244 if input.len() < frame { return frequencies; }
245 let mut code = Code(0);
248 for _ in range(0, frame) {
249 code = code.push_char(input[0]);
252 frequencies.lookup(code, BumpCallback);
254 while input.len() != 0 && input[0] != ('>' as u8) {
255 code = code.rotate(input[0], frame);
256 frequencies.lookup(code, BumpCallback);
262 fn print_frequencies(frequencies: &Table, frame: uint) {
263 let mut vector = Vec::new();
264 for entry in frequencies.iter() {
265 vector.push((entry.count, entry.code));
267 vector.as_mut_slice().sort();
269 let mut total_count = 0;
270 for &(count, _) in vector.iter() {
271 total_count += count;
274 for &(count, key) in vector.iter().rev() {
276 key.unpack(frame).as_slice(),
277 (count as f32 * 100.0) / (total_count as f32));
282 fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
283 frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
286 fn get_sequence<R: Buffer>(r: &mut R, key: &str) -> Vec<u8> {
287 let mut res = Vec::new();
288 for l in r.lines().map(|l| l.ok().unwrap())
289 .skip_while(|l| key != l.as_slice().slice_to(key.len())).skip(1)
291 res.push_all(l.as_slice().trim().as_bytes());
293 res.into_ascii_uppercase()
297 let input = if std::os::getenv("RUST_BENCH").is_some() {
298 let fd = std::io::File::open(&Path::new("shootout-k-nucleotide.data"));
299 get_sequence(&mut std::io::BufferedReader::new(fd), ">THREE")
301 get_sequence(&mut *std::io::stdin().lock(), ">THREE")
303 let input = Arc::new(input);
305 let nb_freqs: Vec<_> = range(1u, 3).map(|i| {
306 let input = input.clone();
307 (i, Thread::spawn(move|| generate_frequencies(input.as_slice(), i)))
309 let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| {
310 let input = input.clone();
311 Thread::spawn(move|| generate_frequencies(input.as_slice(), occ.len()))
314 for (i, freq) in nb_freqs.into_iter() {
315 print_frequencies(&freq.join().ok().unwrap(), i);
317 for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs.into_iter()) {
318 print_occurrences(&mut freq.join().ok().unwrap(), occ);