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(box_syntax)]
45 use std
::ascii
::OwnedAsciiExt
;
50 static TABLE
: [u8;4] = [ 'A'
as u8, 'C'
as u8, 'G'
as u8, 'T'
as u8 ];
51 static TABLE_SIZE
: uint
= 2 << 16;
53 static OCCURRENCES
: [&'
static str;5] = [
61 // Code implementation
63 #[derive(Copy, PartialEq, PartialOrd, Ord, Eq)]
67 fn hash(&self) -> u64 {
68 let Code(ret
) = *self;
72 fn push_char(&self, c
: u8) -> Code
{
73 Code((self.hash() << 2) + (pack_symbol(c
) as u64))
76 fn rotate(&self, c
: u8, frame
: uint
) -> Code
{
77 Code(self.push_char(c
).hash() & ((1u64 << (2 * frame
)) - 1))
80 fn pack(string
: &str) -> Code
{
81 string
.bytes().fold(Code(0u64), |a
, b
| a
.push_char(b
))
84 fn unpack(&self, frame
: uint
) -> String
{
85 let mut key
= self.hash();
86 let mut result
= Vec
::new();
88 result
.push(unpack_symbol((key
as u8) & 3));
93 String
::from_utf8(result
).unwrap()
97 // Hash table implementation
100 fn f(&self, entry
: &mut Entry
);
105 impl TableCallback
for BumpCallback
{
106 fn f(&self, entry
: &mut Entry
) {
111 struct PrintCallback(&'
static str);
113 impl TableCallback
for PrintCallback
{
114 fn f(&self, entry
: &mut Entry
) {
115 let PrintCallback(s
) = *self;
116 println
!("{}\t{}", entry
.count
as int
, s
);
123 next
: Option
<Box
<Entry
>>,
127 items
: Vec
<Option
<Box
<Entry
>>>
131 cur
: Option
<&'a Entry
>,
132 items
: slice
::Iter
<'a
, Option
<Box
<Entry
>>>,
138 items
: (0..TABLE_SIZE
).map(|_
| None
).collect()
142 fn search_remainder
<C
:TableCallback
>(item
: &mut Entry
, key
: Code
, c
: C
) {
145 let mut entry
= box Entry
{
151 item
.next
= Some(entry
);
153 Some(ref mut entry
) => {
154 if entry
.code
== key
{
159 Table
::search_remainder(&mut **entry
, key
, c
)
164 fn lookup
<C
:TableCallback
>(&mut self, key
: Code
, c
: C
) {
165 let index
= key
.hash() % (TABLE_SIZE
as u64);
168 if self.items
[index
as uint
].is_none() {
169 let mut entry
= box Entry
{
175 self.items
[index
as uint
] = Some(entry
);
181 let entry
= self.items
[index
as uint
].as_mut().unwrap();
182 if entry
.code
== key
{
187 Table
::search_remainder(&mut **entry
, key
, c
)
191 fn iter(&self) -> Items
{
192 Items { cur: None, items: self.items.iter() }
196 impl<'a
> Iterator
for Items
<'a
> {
197 type Item
= &'a Entry
;
199 fn next(&mut self) -> Option
<&'a Entry
> {
200 let ret
= match self.cur
{
204 match self.items
.next() {
207 Some(&Some(ref a
)) => { i = &**a; break }
210 self.cur
= Some(&*i
);
216 None
=> { self.cur = None; }
217 Some(ref next
) => { self.cur = Some(&**next); }
225 fn pack_symbol(c
: u8) -> u8 {
231 _
=> panic
!("{}", c
as char),
235 fn unpack_symbol(c
: u8) -> u8 {
239 fn generate_frequencies(mut input
: &[u8], frame
: uint
) -> Table
{
240 let mut frequencies
= Table
::new();
241 if input
.len() < frame { return frequencies; }
242 let mut code
= Code(0);
246 code
= code
.push_char(input
[0]);
249 frequencies
.lookup(code
, BumpCallback
);
251 while input
.len() != 0 && input
[0] != ('
>'
as u8) {
252 code
= code
.rotate(input
[0], frame
);
253 frequencies
.lookup(code
, BumpCallback
);
259 fn print_frequencies(frequencies
: &Table
, frame
: uint
) {
260 let mut vector
= Vec
::new();
261 for entry
in frequencies
.iter() {
262 vector
.push((entry
.count
, entry
.code
));
266 let mut total_count
= 0;
267 for &(count
, _
) in &vector
{
268 total_count
+= count
;
271 for &(count
, key
) in vector
.iter().rev() {
274 (count
as f32 * 100.0) / (total_count
as f32));
279 fn print_occurrences(frequencies
: &mut Table
, occurrence
: &'
static str) {
280 frequencies
.lookup(Code
::pack(occurrence
), PrintCallback(occurrence
))
283 fn get_sequence
<R
: Buffer
>(r
: &mut R
, key
: &str) -> Vec
<u8> {
284 let mut res
= Vec
::new();
285 for l
in r
.lines().map(|l
| l
.ok().unwrap())
286 .skip_while(|l
| key
!= &l
[..key
.len()]).skip(1)
288 res
.push_all(l
.trim().as_bytes());
290 res
.into_ascii_uppercase()
294 let input
= if std
::env
::var_os("RUST_BENCH").is_some() {
295 let fd
= std
::old_io
::File
::open(&Path
::new("shootout-k-nucleotide.data"));
296 get_sequence(&mut std
::old_io
::BufferedReader
::new(fd
), ">THREE")
298 let mut stdin
= std
::old_io
::stdin();
299 let mut stdin
= stdin
.lock();
300 get_sequence(&mut *stdin
, ">THREE")
302 let input
= Arc
::new(input
);
304 let nb_freqs
: Vec
<_
> = (1..3).map(|i
| {
305 let input
= input
.clone();
306 (i
, thread
::scoped(move|| generate_frequencies(&input
, i
)))
308 let occ_freqs
: Vec
<_
> = OCCURRENCES
.iter().map(|&occ
| {
309 let input
= input
.clone();
310 thread
::scoped(move|| generate_frequencies(&input
, occ
.len()))
313 for (i
, freq
) in nb_freqs
{
314 print_frequencies(&freq
.join(), i
);
316 for (&occ
, freq
) in OCCURRENCES
.iter().zip(occ_freqs
.into_iter()) {
317 print_occurrences(&mut freq
.join(), occ
);