use super::SectionEncoding;
use super::payload::maybe_zstd;
use crate::encoding::{
dedup, encode_dedup_map, encode_fsst, encode_txt_streams, encode_zstd_dict, train_dict,
};
use crate::layout::{
SECTION_CHUNKS_CANONICAL, SECTION_DEDUP_MAP, SECTION_DICTIONARY, SECTION_ENCODING_FSST,
SECTION_ENCODING_RAW, SECTION_ENCODING_TXT_STREAMS, SECTION_ENCODING_ZSTD_DICT,
};
use crate::sections::encode_chunks_canonical;
pub(super) struct TextChoice {
pub canonical: (u32, u32, Vec<u8>),
pub aux: Vec<(u32, u32, Vec<u8>)>,
}
pub(super) fn choose(texts: &[String]) -> crate::Result<TextChoice> {
let canonical_raw = encode_chunks_canonical(texts)?;
let mut best = Candidate::plain(maybe_zstd(
SECTION_CHUNKS_CANONICAL,
SectionEncoding::Zstd,
canonical_raw.clone(),
)?);
let streams = encode_txt_streams(texts)?;
best.consider(Candidate::plain((
SECTION_CHUNKS_CANONICAL,
SECTION_ENCODING_TXT_STREAMS,
streams,
)));
if let Some(dict) = train_dict(&sorted_unique(texts)) {
let framed = encode_zstd_dict(texts, &dict)?;
let total = framed.len() + dict.len();
best.consider(Candidate {
canonical: (SECTION_CHUNKS_CANONICAL, SECTION_ENCODING_ZSTD_DICT, framed),
aux: vec![(SECTION_DICTIONARY, SECTION_ENCODING_RAW, dict)],
total,
});
}
let fsst = encode_fsst(texts)?;
best.consider(Candidate::plain((
SECTION_CHUNKS_CANONICAL,
SECTION_ENCODING_FSST,
fsst,
)));
let d = dedup(texts);
if d.unique.len() < texts.len() {
let unique_raw = encode_chunks_canonical(&d.unique)?;
let (cid, cenc, cbytes) =
maybe_zstd(SECTION_CHUNKS_CANONICAL, SectionEncoding::Zstd, unique_raw)?;
let map = encode_dedup_map(&d.back_refs);
let total = cbytes.len() + map.len();
best.consider(Candidate {
canonical: (cid, cenc, cbytes),
aux: vec![(SECTION_DEDUP_MAP, SECTION_ENCODING_RAW, map)],
total,
});
}
Ok(TextChoice {
canonical: best.canonical,
aux: best.aux,
})
}
fn sorted_unique(texts: &[String]) -> Vec<String> {
let mut v: Vec<String> = texts.to_vec();
v.sort_unstable();
v.dedup();
v
}
struct Candidate {
canonical: (u32, u32, Vec<u8>),
aux: Vec<(u32, u32, Vec<u8>)>,
total: usize,
}
impl Candidate {
fn plain(canonical: (u32, u32, Vec<u8>)) -> Self {
let total = canonical.2.len();
Self {
canonical,
aux: Vec::new(),
total,
}
}
fn consider(&mut self, other: Candidate) {
if other.total < self.total {
*self = other;
}
}
}