use std::{f32, ptr};
use reifydb_type::value::r#type::Type;
use crate::encoded::{row::EncodedRow, shape::RowShape};
impl RowShape {
pub fn set_f32(&self, row: &mut EncodedRow, index: usize, value: impl Into<f32>) {
let field = &self.fields()[index];
debug_assert!(row.len() >= self.total_static_size());
debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Float4);
row.set_valid(index, true);
unsafe {
ptr::write_unaligned(
row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut f32,
value.into(),
)
}
}
pub fn get_f32(&self, row: &EncodedRow, index: usize) -> f32 {
let field = &self.fields()[index];
debug_assert!(row.len() >= self.total_static_size());
debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Float4);
unsafe { (row.as_ptr().add(field.offset as usize) as *const f32).read_unaligned() }
}
pub fn try_get_f32(&self, row: &EncodedRow, index: usize) -> Option<f32> {
if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Float4 {
Some(self.get_f32(row, index))
} else {
None
}
}
}
#[cfg(test)]
#[allow(clippy::approx_constant)]
pub mod tests {
use std::f32::consts::{E, PI};
use reifydb_type::value::r#type::Type;
use crate::encoded::shape::RowShape;
#[test]
fn test_set_get_f32() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
shape.set_f32(&mut row, 0, 1.25f32);
assert_eq!(shape.get_f32(&row, 0), 1.25f32);
}
#[test]
fn test_try_get_f32() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
assert_eq!(shape.try_get_f32(&row, 0), None);
shape.set_f32(&mut row, 0, 1.25f32);
assert_eq!(shape.try_get_f32(&row, 0), Some(1.25f32));
}
#[test]
fn test_special_values() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
shape.set_f32(&mut row, 0, 0.0f32);
assert_eq!(shape.get_f32(&row, 0), 0.0f32);
let mut row2 = shape.allocate();
shape.set_f32(&mut row2, 0, -0.0f32);
assert_eq!(shape.get_f32(&row2, 0), -0.0f32);
let mut row3 = shape.allocate();
shape.set_f32(&mut row3, 0, f32::INFINITY);
assert_eq!(shape.get_f32(&row3, 0), f32::INFINITY);
let mut row4 = shape.allocate();
shape.set_f32(&mut row4, 0, f32::NEG_INFINITY);
assert_eq!(shape.get_f32(&row4, 0), f32::NEG_INFINITY);
let mut row5 = shape.allocate();
shape.set_f32(&mut row5, 0, f32::NAN);
assert!(shape.get_f32(&row5, 0).is_nan());
}
#[test]
fn test_extreme_values() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
shape.set_f32(&mut row, 0, f32::MAX);
assert_eq!(shape.get_f32(&row, 0), f32::MAX);
let mut row2 = shape.allocate();
shape.set_f32(&mut row2, 0, f32::MIN);
assert_eq!(shape.get_f32(&row2, 0), f32::MIN);
let mut row3 = shape.allocate();
shape.set_f32(&mut row3, 0, f32::MIN_POSITIVE);
assert_eq!(shape.get_f32(&row3, 0), f32::MIN_POSITIVE);
}
#[test]
fn test_mixed_with_other_types() {
let shape = RowShape::testing(&[Type::Float4, Type::Int4, Type::Float4]);
let mut row = shape.allocate();
shape.set_f32(&mut row, 0, 3.14f32);
shape.set_i32(&mut row, 1, 42);
shape.set_f32(&mut row, 2, -2.718f32);
assert_eq!(shape.get_f32(&row, 0), 3.14f32);
assert_eq!(shape.get_i32(&row, 1), 42);
assert_eq!(shape.get_f32(&row, 2), -2.718f32);
}
#[test]
fn test_undefined_handling() {
let shape = RowShape::testing(&[Type::Float4, Type::Float4]);
let mut row = shape.allocate();
shape.set_f32(&mut row, 0, 3.14f32);
assert_eq!(shape.try_get_f32(&row, 0), Some(3.14f32));
assert_eq!(shape.try_get_f32(&row, 1), None);
shape.set_none(&mut row, 0);
assert_eq!(shape.try_get_f32(&row, 0), None);
}
#[test]
fn test_try_get_f32_wrong_type() {
let shape = RowShape::testing(&[Type::Boolean]);
let mut row = shape.allocate();
shape.set_bool(&mut row, 0, true);
assert_eq!(shape.try_get_f32(&row, 0), None);
}
#[test]
fn test_subnormal_values() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
let min_subnormal = f32::from_bits(0x00000001);
shape.set_f32(&mut row, 0, min_subnormal);
assert_eq!(shape.get_f32(&row, 0).to_bits(), min_subnormal.to_bits());
let max_subnormal = f32::from_bits(0x007fffff);
shape.set_f32(&mut row, 0, max_subnormal);
assert_eq!(shape.get_f32(&row, 0).to_bits(), max_subnormal.to_bits());
let neg_subnormal = f32::from_bits(0x80000001);
shape.set_f32(&mut row, 0, neg_subnormal);
assert_eq!(shape.get_f32(&row, 0).to_bits(), neg_subnormal.to_bits());
}
#[test]
fn test_nan_payload_preservation() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
let quiet_nan = f32::NAN;
shape.set_f32(&mut row, 0, quiet_nan);
assert!(shape.get_f32(&row, 0).is_nan());
let nan_with_payload = f32::from_bits(0x7fc00001);
shape.set_f32(&mut row, 0, nan_with_payload);
assert_eq!(shape.get_f32(&row, 0).to_bits(), nan_with_payload.to_bits());
let neg_nan = f32::from_bits(0xffc00000);
shape.set_f32(&mut row, 0, neg_nan);
assert_eq!(shape.get_f32(&row, 0).to_bits(), neg_nan.to_bits());
}
#[test]
fn test_repeated_operations() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
let initial_len = row.len();
for i in 0..1000 {
let value = (i as f32) * 0.1;
shape.set_f32(&mut row, 0, value);
assert_eq!(shape.get_f32(&row, 0), value);
}
assert_eq!(row.len(), initial_len);
}
#[test]
fn test_unaligned_access() {
let shape = create_unaligned_layout(Type::Float4);
let mut row = shape.allocate();
shape.set_f32(&mut row, 1, PI);
assert_eq!(shape.get_f32(&row, 1), PI);
shape.set_f32(&mut row, 3, E);
assert_eq!(shape.get_f32(&row, 3), E);
assert_eq!(shape.get_f32(&row, 1), PI);
assert_eq!(shape.get_f32(&row, 3), E);
}
#[test]
fn test_denormalized_transitions() {
let shape = RowShape::testing(&[Type::Float4]);
let mut row = shape.allocate();
let values = [
f32::MIN_POSITIVE, f32::MIN_POSITIVE / 2.0, f32::MIN_POSITIVE / 4.0, 0.0f32, ];
for value in values {
shape.set_f32(&mut row, 0, value);
let retrieved = shape.get_f32(&row, 0);
if value == 0.0 {
assert_eq!(retrieved, 0.0);
} else {
assert_eq!(retrieved.to_bits(), value.to_bits());
}
}
}
pub fn create_unaligned_layout(target_type: Type) -> RowShape {
RowShape::testing(&[
Type::Int1, target_type.clone(), Type::Int1, target_type,
])
}
}