Skip to content

Commit 7cf488f

Browse files
authored
Merge pull request #172 from estie-inc/perf/decode-parser-allocations
perf(result-table): avoid decode parser allocations
2 parents f1aba10 + 9369e23 commit 7cf488f

1 file changed

Lines changed: 26 additions & 21 deletions

File tree

src/result_table/decode.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{iter::repeat_n, result::Result as StdResult};
1+
use std::result::Result as StdResult;
22

33
use chrono::{DateTime, Days, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc};
44

@@ -470,15 +470,18 @@ fn parse_scaled_decimal_i128(s: &str, scale: i64, kind: &'static str) -> StdResu
470470
return Err(format!("Could not decode {kind}: {s}"));
471471
}
472472

473-
let mut digits = frac_str.bytes().collect::<Vec<_>>();
474-
if digits.len() < scale as usize {
475-
digits.resize(scale as usize, b'0');
473+
let mut frac = 0i128;
474+
for b in frac_str.bytes() {
475+
frac = frac
476+
.checked_mul(10)
477+
.and_then(|value| value.checked_add(i128::from(b - b'0')))
478+
.ok_or_else(|| format!("Could not decode {kind}: {s}"))?;
479+
}
480+
for _ in frac_str.len()..scale as usize {
481+
frac = frac
482+
.checked_mul(10)
483+
.ok_or_else(|| format!("Could not decode {kind}: {s}"))?;
476484
}
477-
478-
let frac = std::str::from_utf8(&digits)
479-
.map_err(|_| format!("Could not decode {kind}: {s}"))?
480-
.parse::<i128>()
481-
.map_err(|_| format!("Could not decode {kind}: {s}"))?;
482485
scaled = scaled
483486
.checked_add(frac)
484487
.ok_or_else(|| format!("Could not decode {kind}: {s}"))?;
@@ -562,7 +565,9 @@ fn parse_legacy_timestamp_tz_wire(s: &str, scale: i64) -> StdResult<TimestampTzW
562565

563566
let tz_index =
564567
i32::try_from(tz_index).map_err(|_| format!("invalid timezone for timestamp_tz: {s}"))?;
565-
let tz_index = parse_timestamp_tz_index(&tz_index.to_string(), s)?;
568+
if !(0..=2880).contains(&tz_index) {
569+
return Err(format!("invalid timezone for timestamp_tz: {s}"));
570+
}
566571

567572
Ok(TimestampTzWire { utc, tz_index })
568573
}
@@ -625,19 +630,19 @@ pub(crate) fn parse_time_seconds_and_nanos(
625630
return Ok((secs, 0));
626631
}
627632

628-
let mut frac_digits = frac_str.as_bytes().to_vec();
629-
if frac_digits.len() > scale {
630-
frac_digits.truncate(scale);
633+
let mut frac_scaled = 0u32;
634+
let used_digits = frac_str.len().min(scale);
635+
for b in frac_str.bytes().take(used_digits) {
636+
frac_scaled = frac_scaled
637+
.checked_mul(10)
638+
.and_then(|value| value.checked_add(u32::from(b - b'0')))
639+
.ok_or_else(|| format!("invalid time: {value}"))?;
631640
}
632-
if frac_digits.len() < scale {
633-
frac_digits.extend(repeat_n(b'0', scale - frac_digits.len()));
641+
for _ in used_digits..scale {
642+
frac_scaled = frac_scaled
643+
.checked_mul(10)
644+
.ok_or_else(|| format!("invalid time: {value}"))?;
634645
}
635-
636-
let frac_scaled = {
637-
let s = std::str::from_utf8(&frac_digits).map_err(|_| format!("invalid time: {value}"))?;
638-
s.parse::<u32>()
639-
.map_err(|_| format!("invalid time: {value}"))?
640-
};
641646
let nsec = frac_scaled
642647
.checked_mul(10u32.pow((9 - scale) as u32))
643648
.ok_or_else(|| format!("invalid time: {value}"))?;

0 commit comments

Comments
 (0)