use std::cmp::Ordering;
use crate::schema::{ColumnLocator, SchemaColumn, TypeCode};
use gnitz_wire::RowSource;
use gnitz_wire::{cmp_col_window, ScalarKind};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WideKind {
Fixed(TypeCode),
Bytes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ImageKind {
Scalar(ScalarKind),
Wide(WideKind),
}
impl ImageKind {
pub(crate) const fn of(tc: TypeCode) -> Self {
match ScalarKind::from_type_code(tc) {
Some(kind) => Self::Scalar(kind),
None if tc.is_german_string() => Self::Wide(WideKind::Bytes),
None => Self::Wide(WideKind::Fixed(tc)),
}
}
}
impl WideKind {
#[inline(always)]
pub(crate) fn cmp_native(self, a: &[u8], b: &[u8]) -> Ordering {
match self {
Self::Fixed(tc) => cmp_col_window(a, &[], b, &[], tc),
Self::Bytes => a.cmp(b),
}
}
}
#[inline(always)]
pub(crate) fn order_bits(loc: &ColumnLocator, src: &impl RowSource, row: usize, kind: ScalarKind) -> u64 {
debug_assert_eq!(ScalarKind::from_type_code(loc.type_code()), Some(kind));
match kind {
ScalarKind::Int(fi) => (loc.decode_i64(src, row, fi) as u64) ^ ((fi.is_signed() as u64) << 63),
ScalarKind::F32 => ieee_order_bits_f32(u32::from_le_bytes(loc.bytes(src, row).try_into().unwrap())),
ScalarKind::F64 => ieee_order_bits(u64::from_le_bytes(loc.bytes(src, row).try_into().unwrap())),
}
}
#[inline(always)]
pub(crate) fn order_inverse(kind: ScalarKind, e: u64) -> u64 {
match kind {
ScalarKind::Int(fi) => e ^ ((fi.is_signed() as u64) << 63),
ScalarKind::F32 => ieee_order_bits_f32_reverse(e) as u64,
ScalarKind::F64 => ieee_order_bits_reverse(e),
}
}
#[inline(always)]
pub(crate) fn ieee_order_bits(raw_bits: u64) -> u64 {
if raw_bits >> 63 != 0 {
!raw_bits
} else {
raw_bits ^ (1u64 << 63)
}
}
#[inline(always)]
pub(crate) fn ieee_order_bits_f32(raw_bits: u32) -> u64 {
(if raw_bits >> 31 != 0 {
!raw_bits
} else {
raw_bits ^ (1u32 << 31)
}) as u64
}
#[inline(always)]
fn ieee_order_bits_reverse(encoded: u64) -> u64 {
if encoded >> 63 != 0 {
encoded ^ (1u64 << 63)
} else {
!encoded
}
}
#[inline(always)]
fn ieee_order_bits_f32_reverse(encoded: u64) -> u32 {
let e = encoded as u32;
if e >> 31 != 0 {
e ^ (1u32 << 31)
} else {
!e
}
}
pub(crate) const fn image_slot_col(wide: bool) -> SchemaColumn {
SchemaColumn::new(if wide { TypeCode::U128 } else { TypeCode::U64 }, false)
}
pub(crate) const IMAGE_COL: SchemaColumn = SchemaColumn::new(TypeCode::Blob, false);
#[inline(always)]
pub(crate) fn wide_native<'a>(
loc: &ColumnLocator,
kind: WideKind,
mb: &'a impl RowSource,
row: usize,
scratch: &'a mut [u8; 16],
) -> &'a [u8] {
match kind {
WideKind::Bytes => loc.content(mb, row),
WideKind::Fixed(_) => loc.native_le_bytes(mb, row, scratch),
}
}
fn append_bytes_image(invert: bool, content: &[u8], out: &mut Vec<u8>) {
let start = out.len();
for &b in content {
out.push(b);
if b == 0 {
out.push(0xFF);
}
}
out.extend_from_slice(&[0, 0]);
if invert {
out[start..].iter_mut().for_each(|b| *b = !*b);
}
}
#[inline(always)]
pub(crate) fn int16_image(loc: &ColumnLocator, invert: bool, src: &impl RowSource, row: usize) -> [u8; 16] {
let image = loc.opk_image(src, row);
(if invert { !image } else { image }).to_be_bytes()
}
pub(crate) fn has_fixed_image(kind: ImageKind) -> bool {
kind != ImageKind::Wide(WideKind::Bytes)
}
#[inline]
pub(crate) fn write_image_slot(slot: &mut [u8], image: &[u8]) {
let take = image.len().min(slot.len());
slot[..take].copy_from_slice(&image[..take]);
slot[take..].fill(0);
}
pub(crate) fn wide_native_of_image(kind: WideKind, invert: bool, image: &[u8]) -> Vec<u8> {
let mut v = image.to_vec();
if invert {
v.iter_mut().for_each(|b| *b = !*b);
}
match kind {
WideKind::Fixed(tc) => {
let (n, mut native) = (v.len(), [0u8; 16]);
gnitz_wire::decode_pk_cell(&v, tc.is_signed_int(), &mut native[..n]);
v.copy_from_slice(&native[..n]);
v
}
WideKind::Bytes => {
debug_assert!(v.ends_with(&[0, 0]), "a byte-string image ends in its terminator");
let n = v.len() - 2;
let (mut r, mut w) = (0, 0);
while r < n {
let b = v[r];
v[w] = b;
w += 1;
r += if b == 0 { 2 } else { 1 };
}
v.truncate(w);
v
}
}
}
#[inline]
pub(crate) fn scalar_image(
loc: &ColumnLocator,
kind: ScalarKind,
invert: bool,
src: &impl RowSource,
row: usize,
) -> u64 {
let v = order_bits(loc, src, row, kind);
if invert {
!v
} else {
v
}
}
#[inline(always)]
pub(crate) fn scalar_native_of_image(kind: ScalarKind, invert: bool, image: u64) -> u64 {
order_inverse(kind, if invert { !image } else { image })
}
#[inline]
pub(crate) fn append_image(
loc: &ColumnLocator,
kind: ImageKind,
invert: bool,
src: &impl RowSource,
row: usize,
out: &mut Vec<u8>,
) {
match kind {
ImageKind::Scalar(kind) => out.extend_from_slice(&scalar_image(loc, kind, invert, src, row).to_be_bytes()),
ImageKind::Wide(WideKind::Fixed(_)) => out.extend_from_slice(&int16_image(loc, invert, src, row)),
ImageKind::Wide(WideKind::Bytes) => append_bytes_image(invert, loc.content(src, row), out),
}
}
#[cfg(test)]
#[path = "tests/order_image.rs"]
mod tests;