1brc/src/main/rust/src/lib.rs

102 lines
2.7 KiB
Rust

use std::fmt::Display;
use std::fs::File;
use std::io::{BufReader, Bytes};
#[derive(Copy, Clone)]
pub struct StationMeasurements {
pub min: isize,
pub max: isize,
pub count: isize,
pub sum: isize,
}
impl StationMeasurements {
pub fn update(&mut self, v: isize) {
self.min = self.min.min(v);
self.max = self.max.max(v);
self.count += 1;
self.sum += v;
}
pub fn merge(&mut self, other: &Self) {
self.min = self.min.min(other.min);
self.max = self.max.max(other.max);
self.count += other.count;
self.sum += other.sum;
}
}
impl Display for StationMeasurements {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let min = self.min as f64 / 10.0;
let max = self.max as f64 / 10.0;
let avg = (self.sum as f64 / self.count as f64) / 10.0;
write!(f, "{min}/{avg:.1}/{max}")
}
}
pub fn format_nums(num: usize) -> String {
num.to_string()
.as_bytes()
.rchunks(3)
.rev()
.map(std::str::from_utf8)
.collect::<Result<Vec<&str>, _>>()
.unwrap()
.join("_")
}
#[inline]
pub const fn get_digit(b: u8) -> u32 {
(b as u32).wrapping_sub('0' as u32)
}
#[inline]
pub fn parse_temp(bytes: &[u8]) -> isize {
let is_negative = bytes[0] == b'-';
let as_decimal = match (is_negative, bytes.len()) {
(true, 4) => get_digit(bytes[1]) * 10 + get_digit(bytes[3]),
(true, 5) => get_digit(bytes[1]) * 100 + get_digit(bytes[2]) * 10 + get_digit(bytes[4]),
(false, 3) => get_digit(bytes[0]) * 10 + get_digit(bytes[2]),
(false, 4) => get_digit(bytes[0]) * 100 + get_digit(bytes[1]) * 10 + get_digit(bytes[3]),
_x => panic!("could not parse temp: is_negative = {is_negative}, length = {}", bytes.len()),
};
if is_negative {
-(as_decimal as isize)
} else {
as_decimal as isize
}
}
#[inline]
pub fn read_bytes_until(bytes: &mut Bytes<BufReader<&File>>, delimiter: u8) -> Option<[u8; 108]> {
// 108 max length of line in bytes
let mut buf: [u8; 108] = [b'#'; 108];
let mut idx = 0;
while let Some(byte) = bytes.next() {
if byte.is_err() {
panic!("Could not read byte");
}
let byte = byte.unwrap();
if delimiter == byte {
return Some(buf);
}
buf[idx] = byte;
idx += 1;
}
None
}
#[inline]
pub fn parse_line(line: &[u8]) -> (&[u8], &[u8]) {
let mut idx = 0;
while idx < line.len() && line[idx] != b';' {
idx += 1;
}
let station = &line[0..idx];
let midpoint = idx + 1;
while idx < line.len() && line[idx] != b'#' {
idx += 1;
}
(station, &line[midpoint..idx])
}