use super::编码器;
use crate::contexts::default::{默认上下文, 默认决策, 默认决策变化, 默认安排};
use crate::{
位图, 元素, 可编码对象, 最大词长, 编码, 编码信息, 自动上屏, 键
};
use crate::{最大元素编码长度, 棱镜, 错误};
use rustc_hash::{FxHashMap, FxHashSet};
use std::iter::zip;
pub type 线性化决策 = Vec<键>;
#[derive(Clone)]
pub struct 编码空间 {
pub 线性表: Vec<u8>,
pub 线性表长度: usize,
pub 哈希表: FxHashMap<编码, u8>,
}
impl 编码空间 {
#[inline(always)]
pub fn 添加(&mut self, 编码: u64) {
if 编码 < self.线性表长度 as u64 {
let 编码 = 编码 as usize;
self.线性表[编码] = self.线性表[编码].saturating_add(1);
} else {
self.哈希表
.entry(编码)
.and_modify(|x| *x = x.saturating_add(1))
.or_insert(1);
}
}
#[inline(always)]
pub fn 查找数量(&self, 编码: u64) -> u8 {
if 编码 < self.线性表长度 as u64 {
self.线性表[编码 as usize]
} else {
*self.哈希表.get(&编码).unwrap_or(&0)
}
}
}
#[derive(Debug)]
pub struct 简码数量 {
pub prefix: usize,
pub select_keys: Vec<键>,
}
pub struct 编码配置 {
pub 进制: u64,
pub 乘数列表: Vec<u64>,
pub 最大码长: usize,
pub 自动上屏查找表: 自动上屏,
pub 选择键: Vec<键>,
pub 首选键: 键,
pub 简码配置列表: Option<[Vec<简码数量>; 最大词长]>,
}
impl 编码配置 {
pub fn new(上下文: &默认上下文) -> Result<Self, 错误> {
let 编码器配置 = &上下文.配置.encoder;
let 最大码长 = 编码器配置.max_length;
if 最大码长 >= 8 {
return Err("目前暂不支持最大码长大于等于 8 的方案计算!".into());
}
let 自动上屏查找表 = 上下文.预处理自动上屏()?;
let mut 简码配置列表 = None;
if let Some(configs) = &编码器配置.short_code {
简码配置列表 = Some(上下文.预处理简码配置(configs.clone())?);
}
Ok(Self {
自动上屏查找表,
最大码长,
进制: 上下文.棱镜.进制,
乘数列表: (0..=最大码长)
.map(|x| 上下文.棱镜.进制.pow(x as u32))
.collect(),
选择键: 上下文.选择键.clone(),
首选键: 上下文.选择键[0],
简码配置列表,
})
}
#[inline(always)]
pub fn 生成编码(
&self, 原始编码: u64, 原始编码候选位置: u8, 选择键乘数: u64
) -> u64 {
if 原始编码候选位置 == 0 {
if *self.自动上屏查找表.get(原始编码 as usize).unwrap_or(&true) {
return 原始编码;
} else {
return 原始编码 + self.首选键 * 选择键乘数;
}
}
let 选择键 = *self
.选择键
.get(原始编码候选位置 as usize)
.unwrap_or(&self.选择键[0]);
原始编码 + 选择键 * 选择键乘数
}
}
pub struct 默认编码器 {
棱镜: 棱镜,
编码配置: 编码配置,
词信息: Vec<可编码对象>,
全码空间: 编码空间,
简码空间: 编码空间,
包含元素的词: Vec<Vec<usize>>,
}
impl 默认编码器 {
pub fn 新建(上下文: &默认上下文) -> Result<Self, 错误> {
let 编码器配置 = &上下文.配置.encoder;
let 最大码长 = 编码器配置.max_length;
if 最大码长 >= 8 {
return Err("目前暂不支持最大码长大于等于 8 的方案计算!".into());
}
let 词信息 = 上下文.词列表.clone();
let 线性表长度 = 上下文.线性表长度();
let 全码空间 = 编码空间 {
线性表: vec![u8::default(); 线性表长度],
线性表长度,
哈希表: FxHashMap::default(),
};
let 简码空间 = 全码空间.clone();
let mut 包含元素的词 = vec![vec![]; 上下文.棱镜.元素总数()];
for (词序号, 词) in 词信息.iter().enumerate() {
let mut 词元素集合 = FxHashSet::default();
for (元素序列, _) in &词.全部元素序列 {
for 元素位 in 元素序列 {
let 元素 = *元素位 % 上下文.棱镜.元素总数(); 词元素集合.insert(元素);
}
}
for 元素 in 词元素集合 {
if 元素 != 0 {
包含元素的词[元素].push(词序号);
}
}
}
let 编码配置 = 编码配置::new(上下文)?;
Ok(Self {
编码配置,
词信息,
全码空间,
简码空间,
包含元素的词,
棱镜: 上下文.棱镜.clone(),
})
}
fn 重置(&mut self) {
self.全码空间.线性表.iter_mut().for_each(|x| {
*x = 0;
});
self.全码空间.哈希表.clear();
self.简码空间.线性表.iter_mut().for_each(|x| {
*x = 0;
});
self.简码空间.哈希表.clear();
}
fn 刷新元素序列表(&mut self, 映射: &线性化决策) {
let mut 位图 = 位图::new();
for (元素位, 键位) in 映射.iter().enumerate() {
let 元素 = 元素位 % self.棱镜.元素总数();
if *键位 != 0 {
if let Some(&位图索引) = self.棱镜.可选元素位图索引.get(&元素) {
位图.insert(位图索引);
}
}
}
for 词信息 in &mut self.词信息 {
词信息.元素序列 = 词信息
.全部元素序列
.iter()
.find(|x| x.1.subset(&位图))
.unwrap()
.0;
}
}
fn 输出全码(
&mut self,
映射: &线性化决策,
纯移动元素: &Option<Vec<元素>>,
编码结果: &mut [编码信息],
) {
let 编码配置 = &self.编码配置;
if let Some(纯移动元素) = 纯移动元素 {
for 元素 in 纯移动元素 {
for 索引 in &self.包含元素的词[*元素] {
let 词 = &self.词信息[*索引];
let 全码信息 = &mut 编码结果[*索引].全码;
let mut 原始编码 = 0;
for (元素位, 乘数) in zip(&词.元素序列, &编码配置.乘数列表) {
if *元素位 == 0 {
break;
}
原始编码 += 映射[*元素位] * 乘数;
}
全码信息.原始编码 = 原始编码;
}
}
} else {
for (词, 编码信息) in zip(&self.词信息, 编码结果.iter_mut()) {
let 全码信息 = &mut 编码信息.全码;
let mut 原始编码 = 0;
for (元素位, 乘数) in zip(&词.元素序列, &编码配置.乘数列表) {
if *元素位 == 0 {
break;
}
原始编码 += 映射[*元素位] * 乘数;
}
全码信息.原始编码 = 原始编码;
}
}
for (编码信息, 词) in 编码结果.iter_mut().zip(&self.词信息) {
let 全码信息 = &mut 编码信息.全码;
let 原始编码候选位置 = self.全码空间.查找数量(全码信息.原始编码);
全码信息.原始编码候选位置 = 原始编码候选位置;
self.全码空间.添加(全码信息.原始编码);
let 乘数 = 编码配置.乘数列表[词.元素序列.iter().position(|x| *x == 0).unwrap_or(0)];
let 编码 = 编码配置.生成编码(全码信息.原始编码, 0, 乘数);
全码信息.更新(编码, 原始编码候选位置);
}
}
fn 输出简码(&mut self, 编码结果: &mut [编码信息]) {
let 编码配置 = &self.编码配置;
let 简码配置列表 = 编码配置.简码配置列表.as_ref().unwrap();
for (词, 编码结果) in zip(&self.词信息, 编码结果.iter_mut()) {
if 词.简码长度 == u64::MAX {
continue;
}
let 原始编码 = 编码结果.全码.原始编码 % 编码配置.乘数列表[词.简码长度 as usize];
编码结果.简码.原始编码 = 原始编码;
let 序号 = self.简码空间.查找数量(原始编码);
let 乘数 = 编码配置.乘数列表[词.简码长度 as usize];
let 编码 = 编码配置.生成编码(原始编码, 序号, 乘数);
编码结果.简码.更新(编码, 序号);
self.简码空间.添加(原始编码);
}
for (词, 编码结果) in zip(&self.词信息, 编码结果.iter_mut()) {
if 词.简码长度 != u64::MAX {
continue;
}
let 简码配置 = &简码配置列表[词.词长 - 1];
let mut 有简码 = false;
let 全码信息 = &编码结果.全码;
let 简码信息 = &mut 编码结果.简码;
for 出简方式 in 简码配置 {
let 简码数量 {
prefix,
select_keys,
} = 出简方式;
let 乘数 = 编码配置.乘数列表[*prefix];
if 全码信息.原始编码 < 乘数 {
continue;
}
let 原始编码 = 全码信息.原始编码 % 乘数;
let 序号 = self.全码空间.查找数量(原始编码) + self.简码空间.查找数量(原始编码);
if 序号 >= select_keys.len() as u8 {
continue;
}
let 编码 = 编码配置.生成编码(原始编码, 序号, 乘数);
简码信息.原始编码 = 原始编码;
简码信息.原始编码候选位置 = 序号;
简码信息.更新(编码, 0);
self.简码空间.添加(原始编码);
有简码 = true;
break;
}
if !有简码 {
let 序号 = self.简码空间.查找数量(全码信息.原始编码);
简码信息.原始编码 = 全码信息.原始编码;
简码信息.原始编码候选位置 = 序号;
简码信息.更新(全码信息.实际编码, 序号);
self.简码空间.添加(全码信息.原始编码);
}
}
}
pub fn 线性化(
&self,
决策: &默认决策,
棱镜: &棱镜,
纯移动字根: &mut Option<Vec<usize>>,
) -> 线性化决策 {
let radix = 棱镜.元素总数();
let mut result: 线性化决策 = vec![Default::default(); radix * 最大元素编码长度];
for (元素, 安排) in 决策.元素.iter().enumerate() {
if 元素 < 棱镜.进制 as usize {
result[元素] = 元素 as 键;
continue;
}
match 安排 {
默认安排::归并(引用元素) => {
for i in 0..最大元素编码长度 {
result[元素 + i * radix] = result[*引用元素 + i * radix];
}
if let Some(纯移动字根) = 纯移动字根 {
if 纯移动字根.contains(引用元素) {
纯移动字根.push(元素);
}
}
continue;
}
默认安排::键位(列表) => {
for (i, (引用元素, 位置)) in 列表.iter().enumerate() {
result[元素 + i * radix] = result[*引用元素 + *位置 * radix];
if let Some(纯移动字根) = 纯移动字根 {
if 纯移动字根.contains(引用元素) {
纯移动字根.push(元素);
}
}
}
}
_ => {}
}
}
result
}
}
impl 编码器 for 默认编码器 {
type 决策 = 默认决策;
fn 编码(
&mut self, 决策: &默认决策, 决策变化: &Option<默认决策变化>, 输出: &mut [编码信息]
) {
self.重置();
let mut 纯移动字根 = if let Some(变化) = 决策变化 {
if 变化.增加元素.is_empty() && 变化.减少元素.is_empty() {
Some(变化.移动元素.clone())
} else {
None
}
} else {
None
};
let 线性化决策 = self.线性化(决策, &self.棱镜, &mut 纯移动字根);
if 纯移动字根.is_none() {
self.刷新元素序列表(&线性化决策);
}
self.输出全码(&线性化决策, &纯移动字根, 输出);
if self.编码配置.简码配置列表.is_none()
|| self.编码配置.简码配置列表.as_ref().unwrap().is_empty()
{
return;
}
self.输出简码(输出);
}
}