use std::collections::BTreeMap;
use csv::StringRecord;
use daachorse::DoubleArrayAhoCorasickBuilder;
use lindera_dictionary::{
error::LinderaErrorKind,
viterbi::{LexType, WordEntry, WordId},
LinderaResult,
};
use super::parser::CSVParser;
pub fn build_word_entry_map<P: CSVParser>(
parser: &P,
rows: &[StringRecord],
lex_type: LexType,
) -> LinderaResult<BTreeMap<String, Vec<WordEntry>>> {
let mut word_entry_map: BTreeMap<String, Vec<WordEntry>> = BTreeMap::new();
for (row_id, row) in rows.iter().enumerate() {
let surface = parser.surface(row);
let word_cost = parser.cost(row);
let left_id = parser.left_context_id(row);
let right_id = parser.right_context_id(row);
let (Ok(surface), Ok(word_cost), Ok(left_id), Ok(right_id)) =
(surface, word_cost, left_id, right_id)
else {
continue;
};
word_entry_map.entry(surface).or_default().push(WordEntry {
word_id: WordId::new(lex_type, row_id as u32),
word_cost,
left_id,
right_id,
});
}
Ok(word_entry_map)
}
pub fn generate_double_array(
word_entry_map: &BTreeMap<String, Vec<WordEntry>>,
is_system: bool,
) -> LinderaResult<Vec<u8>> {
let mut id = 0u32;
let mut keyset: Vec<(&[u8], u32)> = vec![];
for (key, word_entries) in word_entry_map {
let len = word_entries.len() as u32;
let val = if is_system {
(id << 8) | len
} else {
(id << 5) | len
};
keyset.push((key.as_bytes(), val));
id += len;
}
let keyset_len = keyset.len();
let dict_da = DoubleArrayAhoCorasickBuilder::new()
.build_with_values(keyset)
.map_err(|err| {
LinderaErrorKind::Build
.with_error(anyhow::anyhow!(err))
.add_context(format!(
"Failed to build DoubleArray with {} keys for prefix dictionary",
keyset_len
))
})?;
let dict_da_buffer = dict_da.serialize();
Ok(dict_da_buffer)
}
pub fn generate_values(
word_entry_map: &BTreeMap<String, Vec<WordEntry>>,
) -> LinderaResult<Vec<u8>> {
let mut dict_vals_buffer = Vec::new();
for word_entries in word_entry_map.values() {
for word_entry in word_entries.iter().rev() {
word_entry.serialize(&mut dict_vals_buffer).map_err(|err| {
LinderaErrorKind::Serialize
.with_error(anyhow::anyhow!(err))
.add_context(format!(
"Failed to serialize word entry (id: {})",
word_entry.word_id.id
))
})?;
}
}
Ok(dict_vals_buffer)
}