1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 18:24:05 +02:00

string table history while writing

This commit is contained in:
Robin Appelman 2021-07-21 18:13:27 +02:00
commit a6ba0c20ec

View file

@ -351,6 +351,31 @@ impl<'a> TableEntries<'a> {
pub fn into_entries(self) -> Vec<(u16, StringTableEntry<'a>)> { pub fn into_entries(self) -> Vec<(u16, StringTableEntry<'a>)> {
self.entries self.entries
} }
pub fn find_best_history(&self, text: &str) -> Option<(usize, usize)> {
let mut best_index = None;
let mut best_count = 0;
for (history_index, entry_index) in self.history.iter().enumerate() {
if let Some((_, entry)) = self.entries.get(*entry_index as usize) {
let similar = min(31, count_similar_characters(entry.text(), text));
if similar >= 3 && similar > best_count {
best_index = Some(history_index);
best_count = similar;
}
}
}
best_index.map(|index| (index, best_count))
}
}
fn count_similar_characters(a: &str, b: &str) -> usize {
for (i, (a, b)) in a.bytes().zip(b.bytes()).enumerate() {
if a != b {
return i;
}
}
min(a.len(), b.len())
} }
fn parse_string_table_update<'a>( fn parse_string_table_update<'a>(
@ -387,6 +412,7 @@ fn write_string_table_update<'a>(
let entry_bits = log_base2(table_meta.max_entries); let entry_bits = log_base2(table_meta.max_entries);
let mut last_entry: i16 = -1; let mut last_entry: i16 = -1;
let mut history = TableEntries::new(entries.len());
for (index, entry) in entries.iter() { for (index, entry) in entries.iter() {
let index = *index as i16; let index = *index as i16;
@ -398,7 +424,8 @@ fn write_string_table_update<'a>(
} }
last_entry = index; last_entry = index;
write_table_entry(entry, stream, table_meta)?; write_table_entry(entry, stream, table_meta, &history)?;
history.push((index as u16, entry.clone()));
} }
Ok(()) Ok(())
@ -499,7 +526,7 @@ fn test_table_update_roundtrip() {
); );
} }
fn parse_string_table_list<'a>( pub fn parse_string_table_list<'a>(
stream: &mut Stream<'a>, stream: &mut Stream<'a>,
table_meta: &StringTableMeta, table_meta: &StringTableMeta,
entry_count: u16, entry_count: u16,
@ -520,14 +547,16 @@ fn parse_string_table_list<'a>(
Ok(entries.into_entries()) Ok(entries.into_entries())
} }
fn write_string_table_list( pub fn write_string_table_list(
entries: &[(u16, StringTableEntry)], entries: &[(u16, StringTableEntry)],
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
table_meta: &StringTableMeta, table_meta: &StringTableMeta,
) -> Result<()> { ) -> Result<()> {
for (_, entry) in entries.iter() { let mut history = TableEntries::new(entries.len() as usize);
for (index, entry) in entries.iter() {
true.write(stream)?; true.write(stream)?;
write_table_entry(entry, stream, table_meta)?; write_table_entry(entry, stream, table_meta, &history)?;
history.push((*index, entry.clone()));
} }
Ok(()) Ok(())
@ -638,12 +667,21 @@ fn write_table_entry(
entry: &StringTableEntry, entry: &StringTableEntry,
stream: &mut BitWriteStream<LittleEndian>, stream: &mut BitWriteStream<LittleEndian>,
table_meta: &StringTableMeta, table_meta: &StringTableMeta,
history: &TableEntries,
) -> ReadResult<()> { ) -> ReadResult<()> {
entry.text.is_some().write(stream)?; entry.text.is_some().write(stream)?;
if let Some(text) = entry.text.as_deref() { if let Some(text) = entry.text.as_deref() {
// dont want to deal with history let history_item = history.find_best_history(text);
false.write(stream)?; history_item.is_some().write(stream)?;
text.write(stream)?; if let Some((history_index, history_count)) = history_item {
history_index.write_sized(stream, 5)?;
history_count.write_sized(stream, 5)?;
let diff_bytes = &text.as_bytes()[history_count..];
stream.write_bytes(diff_bytes)?;
0u8.write(stream)?; // writing the string as bytes doesn't add the null terminator
} else {
text.write(stream)?;
}
} }
entry.extra_data.is_some().write(stream)?; entry.extra_data.is_some().write(stream)?;
@ -673,8 +711,9 @@ fn test_table_entry_roundtrip() {
}; };
let mut data = Vec::new(); let mut data = Vec::new();
let pos = { let pos = {
let history = TableEntries::new(1);
let mut write = BitWriteStream::new(&mut data, LittleEndian); let mut write = BitWriteStream::new(&mut data, LittleEndian);
write_table_entry(&entry, &mut write, &table_meta).unwrap(); write_table_entry(&entry, &mut write, &table_meta, &history).unwrap();
write.bit_len() write.bit_len()
}; };
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));