summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Aaron Murphy <mmstickman@gmail.com>2017-01-17 02:25:10 -0500
committerMichael Aaron Murphy <mmstickman@gmail.com>2017-01-17 02:25:10 -0500
commit776dbca3fd98c393bf51d4e3f268815b15ff8ac7 (patch)
tree7758686b2041fc6f74e1f2ad30b09c92c694908b
parentd71d0f6e000a303e266b580c16de349c2391cfd6 (diff)
Swap internal `numtoa` module for external `numtoa` crate
- I've spun the `numtoa` module off into a new crate - The new crate contains more performance optimizations - The `numtoa` crate has the same performance as the `itoa` crate - Integer conversions have never been better
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml1
-rw-r--r--src/execute/dry.rs10
-rw-r--r--src/execute/exec_commands.rs10
-rw-r--r--src/execute/job_log.rs45
-rw-r--r--src/filepaths.rs10
-rw-r--r--src/main.rs1
-rw-r--r--src/misc/mod.rs5
-rw-r--r--src/misc/numtoa.rs194
9 files changed, 48 insertions, 235 deletions
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)",
@@ -62,6 +63,11 @@ dependencies = [
]
[[package]]
+name = "numtoa"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "odds"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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<PathBuf> {
@@ -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<T> {
- /// 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<i8> 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<u8> 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
- }
-}