use core::hash::Hash;
use core::cmp::min;
use std::mem::MaybeUninit;
use num_traits::Zero;
use serde::{Deserialize, Serialize};
use crate::encode_decode::{Coder, internal_coder};
pub const MAX_KEY_LENGTH : usize = 95;
pub trait TableConfig {
type KeyCharT : 'static + Copy + Eq + Hash + Serialize + serde::de::DeserializeOwned;
type DistanceT : 'static + Copy + Zero + PartialOrd + PartialEq + From<u8>;
type ValueT : 'static + Serialize + serde::de::DeserializeOwned;
type CoderT : 'static + crate::Coder + Send + Sync;
const UTF8_KEYS : bool = true;
const MAX_DELETES : usize = 2;
const MEANINGFUL_KEY_LEN : usize = 12;
const GROUP_VARIANT_OVERLAP_THRESHOLD : usize = 5;
const DISTANCE_FUNCTION : DistanceFunction<Self::KeyCharT, Self::DistanceT> = Self::levenstein_distance;
fn levenstein_distance(key_a : &[Self::KeyCharT], key_b : &[Self::KeyCharT]) -> Self::DistanceT {
let m = key_a.len()+1;
let n = key_b.len()+1;
#[allow(clippy::uninit_assumed_init)]
let mut d : [[MaybeUninit<u8>; MAX_KEY_LENGTH + 1]; MAX_KEY_LENGTH + 1] = [[MaybeUninit::uninit(); MAX_KEY_LENGTH + 1]; MAX_KEY_LENGTH + 1];
for (i, row) in d.iter_mut().enumerate().skip(1) {
unsafe{ *(row[0].as_mut_ptr()) = i as u8; }
}
for (j, element) in d[0].iter_mut().enumerate() {
unsafe{ *element.as_mut_ptr() = j as u8; }
}
for j in 1..n {
for i in 1..m {
let substitution_cost = if key_a[i-1] == key_b[j-1] {
0
} else {
1
};
let deletion_distance = unsafe {d.get_unchecked(i-1).get_unchecked(j).assume_init()} + 1;
let insertion_distance = unsafe {d.get_unchecked(i).get_unchecked(j-1).assume_init()} + 1;
let substitution_distance = unsafe {d.get_unchecked(i-1).get_unchecked(j-1).assume_init()} + substitution_cost;
let smallest_distance = min(min(deletion_distance, insertion_distance), substitution_distance);
let element = unsafe{ d.get_unchecked_mut(i).get_unchecked_mut(j) };
unsafe{ *element.as_mut_ptr() = smallest_distance; }
}
}
Self::DistanceT::from(unsafe{ d[m-1][n-1].assume_init() })
}
fn metadata() -> TableMetadata {
let temp_coder = Self::CoderT::new();
TableMetadata {
key_char_type: std::any::type_name::<Self::KeyCharT>().into(),
distance_type: std::any::type_name::<Self::DistanceT>().into(),
value_type: std::any::type_name::<Self::ValueT>().into(),
value_coder_name: temp_coder.format_name().to_string(),
internal_coder_name: internal_coder!().format_name().to_string(),
utf8_keys: Self::UTF8_KEYS,
max_deletes: Self::MAX_DELETES,
meaningful_key_len: Self::MEANINGFUL_KEY_LEN,
group_variant_overlap_threshold: Self::GROUP_VARIANT_OVERLAP_THRESHOLD,
}
}
}
pub type DistanceFunction<KeyCharT, DistanceT> = fn(key_a : &[KeyCharT], key_b : &[KeyCharT]) -> DistanceT;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TableMetadata {
pub key_char_type: String,
pub distance_type: String,
pub value_type: String,
pub value_coder_name: String,
pub internal_coder_name: String,
pub utf8_keys: bool,
pub max_deletes: usize,
pub meaningful_key_len: usize,
pub group_variant_overlap_threshold: usize,
}
pub struct DefaultTableConfig();
impl TableConfig for DefaultTableConfig {
type KeyCharT = char;
type DistanceT = u8;
type ValueT = String;
type CoderT = crate::DefaultCoder;
const UTF8_KEYS : bool = true;
const MAX_DELETES : usize = 2;
const MEANINGFUL_KEY_LEN : usize = 12;
const GROUP_VARIANT_OVERLAP_THRESHOLD : usize = 5;
const DISTANCE_FUNCTION : DistanceFunction<Self::KeyCharT, Self::DistanceT> = Self::levenstein_distance;
}