1 // The Computer Language Benchmarks Game
2 // http://benchmarksgame.alioth.debian.org/
4 // contributed by the Rust Project Developers
6 // Copyright (c) 2013-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(slicing_syntax, unboxed_closures)]
47 use std::io::stdio::{stdin_raw, stdout_raw};
48 use std::io::{IoResult, EndOfFile};
49 use std::num::{div_rem};
50 use std::ptr::{copy_memory, Unique};
51 use std::thread::Thread;
55 table16: [u16;1 << 16]
60 let mut table8 = [0;1 << 8];
61 for (i, v) in table8.iter_mut().enumerate() {
62 *v = Tables::computed_cpl8(i as u8);
64 let mut table16 = [0;1 << 16];
65 for (i, v) in table16.iter_mut().enumerate() {
66 *v = (table8[i & 255] as u16) << 8 |
67 table8[i >> 8] as u16;
69 Tables { table8: table8, table16: table16 }
72 fn computed_cpl8(c: u8) -> u8 {
94 /// Retreives the complement for `i`.
95 fn cpl8(&self, i: u8) -> u8 {
96 self.table8[i as uint]
99 /// Retreives the complement for `i`.
100 fn cpl16(&self, i: u16) -> u16 {
101 self.table16[i as uint]
105 /// Reads all remaining bytes from the stream.
106 fn read_to_end<R: Reader>(r: &mut R) -> IoResult<Vec<u8>> {
107 // As reading the input stream in memory is a bottleneck, we tune
108 // Reader::read_to_end() with a fast growing policy to limit
109 // recopies. If MREMAP_RETAIN is implemented in the linux kernel
110 // and jemalloc use it, this trick will become useless.
111 const CHUNK: uint = 64 * 1024;
113 let mut vec = Vec::with_capacity(CHUNK);
115 // workaround: very fast growing
117 if vec.capacity() - len < CHUNK {
118 let cap = vec.capacity();
119 let mult = if cap < 256 * 1024 * 1024 {
124 vec.reserve_exact(mult * cap - len);
126 match r.push_at_least(1, CHUNK, &mut vec) {
128 Err(ref e) if e.kind == EndOfFile => break,
129 Err(e) => return Err(e)
135 /// Finds the first position at which `b` occurs in `s`.
136 fn memchr(h: &[u8], n: u8) -> Option<uint> {
137 use libc::{c_void, c_int, size_t};
139 libc::memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
144 Some(res as uint - h.as_ptr() as uint)
148 /// A mutable iterator over DNA sequences
149 struct MutDnaSeqs<'a> { s: &'a mut [u8] }
150 fn mut_dna_seqs<'a>(s: &'a mut [u8]) -> MutDnaSeqs<'a> {
153 impl<'a> Iterator for MutDnaSeqs<'a> {
154 type Item = &'a mut [u8];
156 fn next(&mut self) -> Option<&'a mut [u8]> {
157 let tmp = std::mem::replace(&mut self.s, &mut []);
158 let tmp = match memchr(tmp, b'\n') {
159 Some(i) => tmp.slice_from_mut(i + 1),
162 let (seq, tmp) = match memchr(tmp, b'>') {
163 Some(i) => tmp.split_at_mut(i),
166 tmp.split_at_mut(len)
174 /// Length of a normal line without the terminating \n.
175 const LINE_LEN: uint = 60;
177 /// Compute the reverse complement.
178 fn reverse_complement(seq: &mut [u8], tables: &Tables) {
179 let seq = seq.init_mut();// Drop the last newline
181 let off = LINE_LEN - len % (LINE_LEN + 1);
182 let mut i = LINE_LEN;
185 copy_memory(seq.as_mut_ptr().offset((i - off + 1) as int),
186 seq.as_ptr().offset((i - off) as int), off);
187 *seq.get_unchecked_mut(i - off) = b'\n';
192 let (div, rem) = div_rem(len, 4);
194 let mut left = seq.as_mut_ptr() as *mut u16;
195 // This is slow if len % 2 != 0 but still faster than bytewise operations.
196 let mut right = seq.as_mut_ptr().offset(len as int - 2) as *mut u16;
197 let end = left.offset(div as int);
199 let tmp = tables.cpl16(*left);
200 *left = tables.cpl16(*right);
202 left = left.offset(1);
203 right = right.offset(-1);
206 let end = end as *mut u8;
208 1 => *end = tables.cpl8(*end),
210 let tmp = tables.cpl8(*end);
211 *end = tables.cpl8(*end.offset(1));
212 *end.offset(1) = tmp;
215 *end.offset(1) = tables.cpl8(*end.offset(1));
216 let tmp = tables.cpl8(*end);
217 *end = tables.cpl8(*end.offset(2));
218 *end.offset(2) = tmp;
228 unsafe impl<T: 'static> Send for Racy<T> {}
230 /// Executes a closure in parallel over the given iterator over mutable slice.
231 /// The closure `f` is run in parallel with an element of `iter`.
232 fn parallel<'a, I, T, F>(mut iter: I, f: F)
233 where T: 'a+Send + Sync,
234 I: Iterator<Item=&'a mut [T]>,
235 F: Fn(&mut [T]) + Sync {
240 // Need to convert `f` and `chunk` to something that can cross the task
242 let f = Racy(&f as *const F as *const uint);
243 let raw = Racy(chunk.repr());
244 Thread::spawn(move|| {
245 let f = f.0 as *const F;
246 unsafe { (*f)(mem::transmute(raw.0)) }
248 }).collect::<Vec<_>>();
252 let mut data = read_to_end(&mut stdin_raw()).unwrap();
253 let tables = &Tables::new();
254 parallel(mut_dna_seqs(data.as_mut_slice()), |&: seq| reverse_complement(seq, tables));
255 stdout_raw().write(data.as_mut_slice()).unwrap();