use crate::errors::{ParquetError, Result};
use crate::util::bit_util::{FromBitpacked, FromBytes};
pub(crate) const ALP_HEADER_SIZE: usize = 7;
pub(crate) const ALP_COMPRESSION_MODE: u8 = 0;
pub(crate) const ALP_INTEGER_ENCODING_FOR_BIT_PACK: u8 = 0;
pub(crate) const ALP_MIN_LOG_VECTOR_SIZE: u8 = 3;
pub(crate) const ALP_MAX_LOG_VECTOR_SIZE: u8 = 15;
pub(crate) const ALP_DEFAULT_LOG_VECTOR_SIZE: u8 = 10;
pub(crate) const ALP_MAX_EXPONENT_F32: u8 = 10;
pub(crate) const ALP_MAX_EXPONENT_F64: u8 = 18;
#[derive(Debug, Clone, Copy)]
pub(crate) struct AlpHeader {
pub(crate) compression_mode: u8,
pub(crate) integer_encoding: u8,
pub(crate) vector_size: usize,
pub(crate) num_elements: usize,
}
impl AlpHeader {
pub(crate) fn deserialize(bytes: &[u8]) -> Result<Self> {
if bytes.len() < ALP_HEADER_SIZE {
return Err(general_err!(
"Invalid ALP page: expected at least {} bytes for header, got {}",
ALP_HEADER_SIZE,
bytes.len()
));
}
let log_vector_size = bytes[2];
let vector_size = 1usize
.checked_shl(u32::from(log_vector_size))
.ok_or_else(|| {
general_err!(
"Invalid ALP page: log_vector_size {} too large to represent a vector size",
log_vector_size
)
})?;
let num_elements_i32 = i32::from_le_bytes([bytes[3], bytes[4], bytes[5], bytes[6]]);
let num_elements = usize::try_from(num_elements_i32).map_err(|_| {
general_err!(
"Invalid ALP page: num_elements {} must be >= 0",
num_elements_i32
)
})?;
Ok(Self {
compression_mode: bytes[0],
integer_encoding: bytes[1],
vector_size,
num_elements,
})
}
pub(crate) fn serialize(&self) -> Result<[u8; ALP_HEADER_SIZE]> {
if !self.vector_size.is_power_of_two() {
return Err(general_err!(
"Invalid ALP page: vector_size {} is not a power of two",
self.vector_size
));
}
let log_vector_size = self.vector_size.trailing_zeros() as u8;
let num_elements = i32::try_from(self.num_elements).map_err(|_| {
general_err!(
"Invalid ALP page: num_elements {} exceeds i32::MAX",
self.num_elements
)
})?;
let mut out = [0u8; ALP_HEADER_SIZE];
out[0] = self.compression_mode;
out[1] = self.integer_encoding;
out[2] = log_vector_size;
out[3..7].copy_from_slice(&num_elements.to_le_bytes());
Ok(out)
}
pub(crate) fn num_vectors(&self) -> usize {
debug_assert!(self.vector_size.is_power_of_two());
(self.num_elements + self.vector_size - 1) >> self.vector_size.trailing_zeros()
}
pub(crate) fn vector_num_elements(&self, vector_index: usize) -> u16 {
let start = vector_index.saturating_mul(self.vector_size);
let remaining = self.num_elements.saturating_sub(start);
remaining.min(self.vector_size) as u16
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct AlpInfo {
pub(crate) exponent: u8,
pub(crate) factor: u8,
pub(crate) num_exceptions: u16,
}
impl AlpInfo {
pub(crate) const STORED_SIZE: usize = 4;
pub(crate) fn extend_serialized(&self, out: &mut Vec<u8>) {
out.push(self.exponent);
out.push(self.factor);
out.extend_from_slice(&self.num_exceptions.to_le_bytes());
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ForInfo<Exact: AlpExact> {
pub(crate) frame_of_reference: Exact,
pub(crate) bit_width: u8,
}
impl<Exact: AlpExact> ForInfo<Exact> {
pub(crate) fn stored_size() -> usize {
Exact::WIDTH + 1
}
pub(crate) fn extend_serialized(&self, out: &mut Vec<u8>) {
self.frame_of_reference.extend_le_bytes(out);
out.push(self.bit_width);
}
pub(crate) fn get_bit_packed_size(&self, num_elements: u16) -> usize {
(self.bit_width as usize * num_elements as usize).div_ceil(8)
}
pub(crate) fn get_data_stored_size(&self, num_elements: u16, num_exceptions: u16) -> usize {
let bit_packed_size = self.get_bit_packed_size(num_elements);
bit_packed_size
+ num_exceptions as usize * std::mem::size_of::<u16>()
+ num_exceptions as usize * Exact::WIDTH
}
}
pub(crate) trait AlpExact:
Copy + std::fmt::Debug + PartialEq + FromBitpacked + Default
{
const WIDTH: usize;
type Signed: Copy + Ord + std::fmt::Debug + Send;
fn from_le_slice(slice: &[u8]) -> Self;
fn wrapping_add(self, rhs: Self) -> Self;
fn wrapping_sub(self, rhs: Self) -> Self;
fn reinterpret_as_signed(self) -> Self::Signed;
fn reinterpret_from_signed(signed: Self::Signed) -> Self;
fn to_u64(self) -> u64;
fn extend_le_bytes(self, out: &mut Vec<u8>);
}
impl AlpExact for u32 {
const WIDTH: usize = 4;
type Signed = i32;
fn from_le_slice(slice: &[u8]) -> Self {
u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]])
}
fn wrapping_add(self, rhs: Self) -> Self {
self.wrapping_add(rhs)
}
fn wrapping_sub(self, rhs: Self) -> Self {
self.wrapping_sub(rhs)
}
fn reinterpret_as_signed(self) -> Self::Signed {
i32::from_ne_bytes(self.to_ne_bytes())
}
fn reinterpret_from_signed(signed: Self::Signed) -> Self {
u32::from_ne_bytes(signed.to_ne_bytes())
}
fn to_u64(self) -> u64 {
u64::from(self)
}
fn extend_le_bytes(self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.to_le_bytes());
}
}
impl AlpExact for u64 {
const WIDTH: usize = 8;
type Signed = i64;
fn from_le_slice(slice: &[u8]) -> Self {
u64::from_le_bytes([
slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
])
}
fn wrapping_add(self, rhs: Self) -> Self {
self.wrapping_add(rhs)
}
fn wrapping_sub(self, rhs: Self) -> Self {
self.wrapping_sub(rhs)
}
fn reinterpret_as_signed(self) -> Self::Signed {
i64::from_ne_bytes(self.to_ne_bytes())
}
fn reinterpret_from_signed(signed: Self::Signed) -> Self {
u64::from_ne_bytes(signed.to_ne_bytes())
}
fn to_u64(self) -> u64 {
self
}
fn extend_le_bytes(self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.to_le_bytes());
}
}
pub(crate) const ALP_POW10_F32: [f32; 11] = [
1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
];
pub(crate) const ALP_POW10_F64: [f64; 19] = [
1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0,
10000000000000000.0,
100000000000000000.0,
1000000000000000000.0,
];
pub(crate) const ALP_NEG_POW10_F32: [f32; 11] = [
1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
];
pub(crate) const ALP_NEG_POW10_F64: [f64; 19] = [
1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001,
0.0000000000000001,
0.00000000000000001,
0.000000000000000001,
];
pub(crate) trait AlpFloat:
Copy + Default + PartialEq + std::ops::Mul<Output = Self>
{
type Exact: AlpExact + FromBytes;
type Scale: Copy + Send;
const MAX_EXPONENT: u8;
const MAGIC_NUMBER: Self;
const ENCODING_UPPER_LIMIT: Self;
const ENCODING_LOWER_LIMIT: Self;
const ENCODING_SENTINEL: <Self::Exact as AlpExact>::Signed;
fn decode_scale(exponent: u8, factor: u8) -> Self::Scale;
fn decode_value(signed_encoded: <Self::Exact as AlpExact>::Signed, scale: Self::Scale) -> Self;
fn from_exact_bits(bits: Self::Exact) -> Self;
fn to_exact_bits(self) -> Self::Exact;
fn encode_scale(exponent: u8, factor: u8) -> Self::Scale;
fn apply_scale(self, scale: Self::Scale) -> Self;
fn is_impossible_to_encode(self) -> bool;
fn fast_round(self) -> <Self::Exact as AlpExact>::Signed;
fn encode_value(self, scale: Self::Scale) -> <Self::Exact as AlpExact>::Signed {
let scaled = self.apply_scale(scale);
if scaled.is_impossible_to_encode() {
return Self::ENCODING_SENTINEL;
}
scaled.fast_round()
}
}
impl AlpFloat for f32 {
type Exact = u32;
type Scale = (f32, f32);
const MAX_EXPONENT: u8 = ALP_MAX_EXPONENT_F32;
const MAGIC_NUMBER: Self = 12582912.0; const ENCODING_UPPER_LIMIT: Self = 2147483500.0;
const ENCODING_LOWER_LIMIT: Self = -2147483500.0;
const ENCODING_SENTINEL: i32 = 2147483520;
fn decode_scale(exponent: u8, factor: u8) -> Self::Scale {
debug_assert!(exponent <= ALP_MAX_EXPONENT_F32);
debug_assert!(factor <= exponent);
(
ALP_POW10_F32[factor as usize],
ALP_NEG_POW10_F32[exponent as usize],
)
}
fn decode_value(signed_encoded: i32, scale: Self::Scale) -> Self {
((signed_encoded as f32) * scale.0) * scale.1
}
fn from_exact_bits(bits: Self::Exact) -> Self {
f32::from_bits(bits)
}
fn to_exact_bits(self) -> Self::Exact {
self.to_bits()
}
fn encode_scale(exponent: u8, factor: u8) -> Self::Scale {
debug_assert!(exponent <= ALP_MAX_EXPONENT_F32);
debug_assert!(factor <= exponent);
(
ALP_POW10_F32[exponent as usize],
ALP_NEG_POW10_F32[factor as usize],
)
}
fn apply_scale(self, scale: Self::Scale) -> Self {
(self * scale.0) * scale.1
}
fn is_impossible_to_encode(self) -> bool {
self.is_nan()
|| !(Self::ENCODING_LOWER_LIMIT..=Self::ENCODING_UPPER_LIMIT).contains(&self)
|| (self == 0.0 && self.is_sign_negative())
}
fn fast_round(self) -> i32 {
((self + Self::MAGIC_NUMBER) - Self::MAGIC_NUMBER) as i32
}
}
impl AlpFloat for f64 {
type Exact = u64;
type Scale = (f64, f64);
const MAX_EXPONENT: u8 = ALP_MAX_EXPONENT_F64;
const MAGIC_NUMBER: Self = 6755399441055744.0; const ENCODING_UPPER_LIMIT: Self = 9223372036854775000.0;
const ENCODING_LOWER_LIMIT: Self = -9223372036854775000.0;
const ENCODING_SENTINEL: i64 = 9223372036854774784;
fn decode_scale(exponent: u8, factor: u8) -> Self::Scale {
debug_assert!(exponent <= ALP_MAX_EXPONENT_F64);
debug_assert!(factor <= exponent);
(
ALP_POW10_F64[factor as usize],
ALP_NEG_POW10_F64[exponent as usize],
)
}
fn decode_value(signed_encoded: i64, scale: Self::Scale) -> Self {
((signed_encoded as f64) * scale.0) * scale.1
}
fn from_exact_bits(bits: Self::Exact) -> Self {
f64::from_bits(bits)
}
fn to_exact_bits(self) -> Self::Exact {
self.to_bits()
}
fn encode_scale(exponent: u8, factor: u8) -> Self::Scale {
debug_assert!(exponent <= ALP_MAX_EXPONENT_F64);
debug_assert!(factor <= exponent);
(
ALP_POW10_F64[exponent as usize],
ALP_NEG_POW10_F64[factor as usize],
)
}
fn apply_scale(self, scale: Self::Scale) -> Self {
(self * scale.0) * scale.1
}
fn is_impossible_to_encode(self) -> bool {
self.is_nan()
|| !(Self::ENCODING_LOWER_LIMIT..=Self::ENCODING_UPPER_LIMIT).contains(&self)
|| (self == 0.0 && self.is_sign_negative())
}
fn fast_round(self) -> i64 {
((self + Self::MAGIC_NUMBER) - Self::MAGIC_NUMBER) as i64
}
}