diff --git a/Cargo.lock b/Cargo.lock index c2d26d6..8cf0fcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ dependencies = [ "arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "permutate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "sys-info 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -61,6 +62,11 @@ dependencies = [ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "numtoa" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "odds" version = "0.2.25" @@ -126,6 +132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e030dc72013ed68994d1b2cbf36a94dd0e58418ba949c4b0db7eeb70a7a6352" "checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5" "checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39" +"checksum numtoa 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "45c4d44bd57b868697b32b4445d06f96b9e4aa6389cf029c23f0b5216c6b2ffb" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum permutate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b4ba980af238a6d6fcc0df53fe0d7920376bc4ce2c6ce298992891a230b47a8" "checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753" diff --git a/Cargo.toml b/Cargo.toml index d5f25e2..6a90787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" [dependencies] itoa = "0.1" +numtoa = "0.0.3" num_cpus = "1.2" permutate = "0.2" arrayvec = "0.3" diff --git a/src/execute/dry.rs b/src/execute/dry.rs index 1eba349..8472303 100644 --- a/src/execute/dry.rs +++ b/src/execute/dry.rs @@ -2,7 +2,7 @@ use input_iterator::{InputIterator, InputIteratorErr}; use tokenizer::Token; use arguments; use execute::command; -use misc::NumToA; +use numtoa::NumToA; use std::io::{self, StdoutLock, Write}; @@ -18,8 +18,8 @@ pub fn dry_run(flags: u16, inputs: InputIterator, arguments: &[Token]) { let pipe = flags & arguments::PIPE_IS_ENABLED != 0; let mut id_buffer = [0u8; 20]; let mut total_buffer = [0u8; 20]; - let truncate = inputs.total_arguments.numtoa(10, &mut total_buffer); - let job_total = &total_buffer[0..truncate]; + let start_indice = inputs.total_arguments.numtoa(10, &mut total_buffer); + let job_total = &total_buffer[start_indice..]; // If `SHELL_QUOTE` is enabled then the quoted command will be printed, otherwise the command will be // printed unmodified. The correct function to execute will be assigned here in advance. @@ -40,10 +40,10 @@ pub fn dry_run(flags: u16, inputs: InputIterator, arguments: &[Token]) { for (job_id, input) in inputs.enumerate() { match input { Ok(input) => { - let truncate = job_id.numtoa(10, &mut id_buffer); + let start_indice = job_id.numtoa(10, &mut id_buffer); let command = command::ParallelCommand { slot_no: slot, - job_no: &id_buffer[0..truncate], + job_no: &id_buffer[start_indice..], job_total: job_total, input: &input, command_template: arguments, diff --git a/src/execute/exec_commands.rs b/src/execute/exec_commands.rs index 20eb811..810ce53 100644 --- a/src/execute/exec_commands.rs +++ b/src/execute/exec_commands.rs @@ -1,7 +1,7 @@ use arguments::{VERBOSE_MODE, JOBLOG}; use execute::command::{self, CommandErr}; use input_iterator::InputsLock; -use misc::NumToA; +use numtoa::NumToA; use time::{self, Timespec}; use tokenizer::Token; use verbose; @@ -39,8 +39,8 @@ impl ExecCommands { let mut id_buffer = [0u8; 20]; let mut job_buffer = [0u8; 20]; let mut total_buffer = [0u8; 20]; - let truncate = self.num_inputs.numtoa(10, &mut total_buffer); - let job_total = &total_buffer[0..truncate]; + let mut start_indice = self.num_inputs.numtoa(10, &mut total_buffer); + let job_total = &total_buffer[start_indice..]; while let Some(job_id) = self.inputs.try_next(&mut input) { @@ -48,10 +48,10 @@ impl ExecCommands { verbose::processing_task(&stdout, job_id+1, self.num_inputs, &input); } - let truncate = (job_id+1).numtoa(10, &mut id_buffer); + start_indice = (job_id+1).numtoa(10, &mut id_buffer); let command = command::ParallelCommand { slot_no: slot, - job_no: &id_buffer[0..truncate], + job_no: &id_buffer[start_indice..], job_total: job_total, input: &input, command_template: self.arguments, diff --git a/src/execute/job_log.rs b/src/execute/job_log.rs index 98cc2d8..91fbf4e 100644 --- a/src/execute/job_log.rs +++ b/src/execute/job_log.rs @@ -1,5 +1,5 @@ use arguments::JOBLOG_8601; -use misc::NumToA; +use numtoa::NumToA; use std::fs::File; use std::io::{Write, BufWriter}; use time::{at, Timespec}; @@ -25,11 +25,12 @@ pub struct JobLog { impl JobLog { /// Writes an individual job log to the job log file, efficiently. pub fn write_entry(&self, joblog: &mut File, id_buffer: &mut [u8], pad: usize) { + let mut start_indice; // 1: JobID let mut joblog = BufWriter::new(joblog); - let bytes_written = (self.job_id + 1).numtoa(10, id_buffer); - let _ = joblog.write(&id_buffer[0..bytes_written]); - for _ in 0..pad-bytes_written { + start_indice = (self.job_id + 1).numtoa(10, id_buffer); + let _ = joblog.write(&id_buffer[start_indice..]); + for _ in 0..pad-id_buffer[start_indice..].len() { let _ = joblog.write(b" "); } @@ -37,62 +38,64 @@ impl JobLog { if self.flags & JOBLOG_8601 != 0 { // ISO 8601 representation of the time let tm = at(self.start_time); + // TODO: Eliminate heap allocation let message = format!("{}-{:02}-{:02} {:02}:{:02}:{:02} ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); let _ = joblog.write(message.as_bytes()); } else { // Represented in seconds, with two decimal places - let bytes_written = self.start_time.sec.numtoa(10, id_buffer); - let _ = joblog.write(&id_buffer[0..bytes_written]); + // TODO: write an abstraction for printing decimals + start_indice = self.start_time.sec.numtoa(10, id_buffer); + let _ = joblog.write(&id_buffer[start_indice..]); let _ = joblog.write(b"."); let decimal = (self.start_time.nsec % 1_000_000_000) / 1_000_000; if decimal == 0 { let _ = joblog.write(b"000"); } else { - let bytes_written = decimal.numtoa(10, id_buffer); - match bytes_written { + start_indice = decimal.numtoa(10, id_buffer); + match id_buffer[start_indice..].len() { 1 => { let _ = joblog.write(b"00"); }, 2 => { let _ = joblog.write(b"0"); }, _ => (), }; - let _ = joblog.write(&id_buffer[0..bytes_written]); + let _ = joblog.write(&id_buffer[start_indice..]); } let _ = joblog.write(b" "); } // 3: Runtime in seconds, with up to three decimal places. - let bytes_written = (self.runtime / 1_000_000_000).numtoa(10, id_buffer); - for _ in 0..6-bytes_written { + start_indice = (self.runtime / 1_000_000_000).numtoa(10, id_buffer); + for _ in 0..6-id_buffer[start_indice..].len() { let _ = joblog.write(b" "); } - let _ = joblog.write(&id_buffer[0..bytes_written]); + let _ = joblog.write(&id_buffer[start_indice..]); let _ = joblog.write(b"."); let decimal = (self.runtime % 1_000_000_000) / 1_000_000; if decimal == 0 { let _ = joblog.write(b"000"); } else { - let bytes_written = decimal.numtoa(10, id_buffer); - match bytes_written { + start_indice = decimal.numtoa(10, id_buffer); + match id_buffer[start_indice..].len() { 1 => { let _ = joblog.write(b"00"); }, 2 => { let _ = joblog.write(b"0"); }, _ => (), }; - let _ = joblog.write(&id_buffer[0..bytes_written]); + let _ = joblog.write(&id_buffer[start_indice..]); } let _ = joblog.write(b" "); // 4: Exit Value - let bytes_written = self.exit_value.numtoa(10, id_buffer); - let _ = joblog.write(&id_buffer[0..bytes_written]); - for _ in 0..9-bytes_written { + start_indice = self.exit_value.numtoa(10, id_buffer); + let _ = joblog.write(&id_buffer[start_indice..]); + for _ in 0..9-id_buffer[start_indice..].len() { let _ = joblog.write(b" "); } // 5: Signal - let bytes_written = self.signal.numtoa(10, id_buffer); - let _ = joblog.write(&id_buffer[0..bytes_written]); - for _ in 0..8-bytes_written { + start_indice = self.signal.numtoa(10, id_buffer); + let _ = joblog.write(&id_buffer[start_indice..]); + for _ in 0..8-id_buffer[start_indice..].len() { let _ = joblog.write(b" "); } diff --git a/src/filepaths.rs b/src/filepaths.rs index ec1c3a7..fcdc375 100644 --- a/src/filepaths.rs +++ b/src/filepaths.rs @@ -1,5 +1,5 @@ +use numtoa::NumToA; use std::path::PathBuf; -use misc::NumToA; #[cfg(not(windows))] pub fn base() -> Option { @@ -19,8 +19,8 @@ pub fn new_job(base: &str, id: usize, buffer: &mut [u8]) -> (usize, String, Stri let mut stdout = String::from(base) + "/stdout_"; let mut stderr = String::from(base) + "/stderr_"; let truncate_value = stdout.len(); - let length = id.numtoa(10, buffer); - for byte in &buffer[0..length] { + let start_indice = id.numtoa(10, buffer); + for byte in &buffer[start_indice..] { stdout.push(*byte as char); stderr.push(*byte as char); } @@ -30,8 +30,8 @@ pub fn new_job(base: &str, id: usize, buffer: &mut [u8]) -> (usize, String, Stri pub fn next_job_path(id: usize, truncate: usize, buffer: &mut [u8], stdout: &mut String, stderr: &mut String) { stdout.truncate(truncate); stderr.truncate(truncate); - let length = id.numtoa(10, buffer); - for byte in &buffer[0..length] { + let start_indice = id.numtoa(10, buffer); + for byte in &buffer[start_indice..] { stdout.push(*byte as char); stderr.push(*byte as char); } diff --git a/src/main.rs b/src/main.rs index 79adc10..110fd46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ extern crate alloc_system; extern crate arrayvec; extern crate itoa; +extern crate numtoa; extern crate num_cpus; extern crate permutate; extern crate smallvec; diff --git a/src/misc/mod.rs b/src/misc/mod.rs index 7c04787..fb27965 100644 --- a/src/misc/mod.rs +++ b/src/misc/mod.rs @@ -1,10 +1,5 @@ ///! The purpose of this module is to supply supporting miscellanious traits for use throughout the project. mod digits; -mod numtoa; /// The `Digits` trait is used to get the number of digits within a number. pub use self::digits::Digits; - -/// The `NumToA` trait converts integers into their string representation, -/// but stores the results in a mutable stack-allocated byte slice. -pub use self::numtoa::NumToA; diff --git a/src/misc/numtoa.rs b/src/misc/numtoa.rs deleted file mode 100644 index 86bdf30..0000000 --- a/src/misc/numtoa.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::ptr::swap; - -/// Converts a number into a string representation, storing the conversion into a mutable byte slice. -pub trait NumToA { - /// Given a base for encoding and a mutable byte slice, write the number into the byte slice and return the - /// amount of bytes that were written. - /// - /// # Panics - /// If the supplied buffer is smaller than the number of bytes needed to write the integer, this will panic. - fn numtoa(self, base: T, string: &mut [u8]) -> usize; -} - -// A lookup table to prevent the need for conditional branching -// The value of the remainder of each step will be used as the index -const LOOKUP: &'static [u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/// Because the integer to string conversion writes the representation in reverse, this will correct it. -fn reverse(string: &mut [u8], length: usize) { - let mut start = 0isize; - let mut end = length as isize - 1; - while start < end { - unsafe { - let x = string.as_mut_ptr().offset(start); - let y = string.as_mut_ptr().offset(end); - swap(x, y); - } - start += 1; - end -= 1; - } -} - -macro_rules! base_10 { - ($number:ident, $index:ident, $string:ident) => { - // Decode four characters at the same time - while $number > 9999 { - let rem = $number % 10000; - $string[$index+3] = LOOKUP[(rem / 1000) as usize]; - $string[$index+2] = LOOKUP[(rem % 1000 / 100) as usize]; - $string[$index+1] = LOOKUP[(rem % 100 / 10) as usize]; - $string[$index] = LOOKUP[(rem % 10) as usize]; - $index += 4; - $number /= 10000; - } - - if $number > 999 { - let rem = $number % 1000; - $string[$index+3] = LOOKUP[($number / 1000) as usize]; - $string[$index+2] = LOOKUP[(rem / 100) as usize]; - $string[$index+1] = LOOKUP[(rem % 100 / 10) as usize]; - $string[$index] = LOOKUP[(rem % 10) as usize]; - $index += 4; - } else if $number > 99 { - let rem = $number % 100; - $string[$index+2] = LOOKUP[($number / 100) as usize]; - $string[$index+1] = LOOKUP[(rem / 10) as usize]; - $string[$index] = LOOKUP[(rem % 10) as usize]; - $index += 3; - } else if $number > 9 { - $string[$index+1] = LOOKUP[($number / 10) as usize]; - $string[$index] = LOOKUP[($number % 10) as usize]; - $index += 2; - } else { - $string[$index] = LOOKUP[$number as usize]; - $index += 1; - } - } -} - -macro_rules! impl_unsized_numtoa_for { - ($t:ty) => { - impl NumToA<$t> for $t { - fn numtoa(mut self, base: $t, string: &mut [u8]) -> usize { - if self == 0 { - string[0] = b'0'; - return 1; - } - - let mut index = 0; - - if base == 10 { - base_10!(self, index, string); - } else { - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index += 1; - self /= base; - } - } - - reverse(string, index); - index - } - } - } -} - -macro_rules! impl_sized_numtoa_for { - ($t:ty) => { - impl NumToA<$t> for $t { - fn numtoa(mut self, base: $t, string: &mut [u8]) -> usize { - let mut index = 0; - let mut is_negative = false; - - if self < 0 { - is_negative = true; - self = self.abs(); - } else if self == 0 { - string[0] = b'0'; - return 1; - } - - if base == 10 { - base_10!(self, index, string); - } else { - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index += 1; - self /= base; - } - } - - if is_negative { - string[index] = b'-'; - index += 1; - } - - reverse(string, index); - index - } - } - - } -} - -impl_sized_numtoa_for!(i16); -impl_sized_numtoa_for!(i32); -impl_sized_numtoa_for!(i64); -impl_sized_numtoa_for!(isize); -impl_unsized_numtoa_for!(u16); -impl_unsized_numtoa_for!(u32); -impl_unsized_numtoa_for!(u64); -impl_unsized_numtoa_for!(usize); - -impl NumToA for i8 { - fn numtoa(mut self, base: i8, string: &mut [u8]) -> usize { - let mut index = 0; - let mut is_negative = false; - - if self < 0 { - is_negative = true; - self = self.abs(); - } else if self == 0 { - string[0] = b'0'; - return 1; - } - - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index += 1; - self /= base; - } - - if is_negative { - string[index] = b'-'; - index += 1; - } - - reverse(string, index); - index - } -} - -impl NumToA for u8 { - fn numtoa(mut self, base: u8, string: &mut [u8]) -> usize { - if self == 0 { - string[0] = b'0'; - return 1; - } - - let mut index = 0; - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index += 1; - self /= base; - } - - reverse(string, index); - index - } -}