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

optimize prop flattening cycle prevention

This commit is contained in:
Robin Appelman 2022-12-13 22:27:38 +01:00
commit 836e7718ce

View file

@ -319,11 +319,11 @@ fn test_parse_send_table_roundtrip() {
impl ParseSendTable { impl ParseSendTable {
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Result<Vec<SendPropDefinition>> { pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Result<Vec<SendPropDefinition>> {
let mut flat = Vec::with_capacity(32); let mut flat = Vec::with_capacity(32);
self.get_all_props( self.push_props_end(
tables, tables,
&self.get_excludes(tables, &mut Vec::with_capacity(8)), &self.get_excludes(tables),
&mut flat, &mut flat,
Vec::with_capacity(8), &mut Vec::with_capacity(16),
)?; )?;
// sort often changed props before the others // sort often changed props before the others
@ -340,13 +340,21 @@ impl ParseSendTable {
Ok(flat) Ok(flat)
} }
fn get_excludes<'a>( fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<SendPropIdentifier> {
let mut excludes = Vec::with_capacity(8);
self.build_excludes(tables, &mut Vec::with_capacity(8), &mut excludes);
excludes
}
fn build_excludes<'a>(
&'a self, &'a self,
tables: &'a [ParseSendTable], tables: &'a [ParseSendTable],
processed_tables: &mut Vec<SendTableName>, processed_tables: &mut Vec<&'a SendTableName>,
) -> Vec<SendPropIdentifier> { excludes: &mut Vec<SendPropIdentifier>,
processed_tables.push(self.name.clone()); ) {
let mut excludes = Vec::with_capacity(8); processed_tables.push(&self.name);
for prop in self.props.iter() { for prop in self.props.iter() {
if let Some(exclude_table) = prop.get_exclude_table() { if let Some(exclude_table) = prop.get_exclude_table() {
@ -355,73 +363,67 @@ impl ParseSendTable {
prop.name.as_str(), prop.name.as_str(),
)) ))
} else if let Some(table) = prop.get_data_table(tables) { } else if let Some(table) = prop.get_data_table(tables) {
if !processed_tables.contains(&table.name) { if !processed_tables.contains(&&table.name) {
excludes.extend_from_slice(&table.get_excludes(tables, processed_tables)); table.build_excludes(tables, processed_tables, excludes);
} }
} }
} }
excludes
} }
// TODO: below is a direct port from the js which is a direct port from C++ and not very optimal // TODO: below is a direct port from the js which is a direct port from C++ and not very optimal
fn get_all_props( fn push_props_end<'a>(
&self, &'a self,
tables: &[ParseSendTable], tables: &'a [ParseSendTable],
excludes: &[SendPropIdentifier], excludes: &[SendPropIdentifier],
props: &mut Vec<SendPropDefinition>, props: &mut Vec<SendPropDefinition>,
processed_tables: Vec<SendTableName>, table_stack: &mut Vec<&'a SendTableName>,
) -> Result<()> { ) -> Result<()> {
let mut local_props = Vec::new(); let mut local_props = Vec::new();
self.get_all_props_iterator_props( self.push_props_collapse(tables, excludes, &mut local_props, props, table_stack)?;
tables,
excludes,
&mut local_props,
props,
processed_tables,
)?;
props.extend_from_slice(&local_props); props.extend_from_slice(&local_props);
Ok(()) Ok(())
} }
fn get_all_props_iterator_props( fn push_props_collapse<'a>(
&self, &'a self,
tables: &[ParseSendTable], tables: &'a [ParseSendTable],
excludes: &[SendPropIdentifier], excludes: &[SendPropIdentifier],
local_props: &mut Vec<SendPropDefinition>, local_props: &mut Vec<SendPropDefinition>,
props: &mut Vec<SendPropDefinition>, props: &mut Vec<SendPropDefinition>,
processed_tables: Vec<SendTableName>, table_stack: &mut Vec<&'a SendTableName>,
) -> Result<()> { ) -> Result<()> {
let processed_tables = &processed_tables; table_stack.push(&self.name);
self.props
let result = self
.props
.iter() .iter()
.filter(|prop| !prop.is_exclude()) .filter(|prop| !prop.is_exclude())
.filter(|prop| !excludes.iter().any(|exclude| *exclude == prop.identifier())) .filter(|prop| !excludes.iter().any(|exclude| *exclude == prop.identifier()))
.try_for_each(|prop| { .try_for_each(|prop| {
let mut child_processed_tables = processed_tables.clone();
child_processed_tables.push(self.name.clone());
if let Some(table) = prop.get_data_table(tables) { if let Some(table) = prop.get_data_table(tables) {
if !processed_tables.contains(&table.name) { if !table_stack.contains(&&table.name) {
if prop.flags.contains(SendPropFlag::Collapsible) { if prop.flags.contains(SendPropFlag::Collapsible) {
table.get_all_props_iterator_props( table.push_props_collapse(
tables, tables,
excludes, excludes,
local_props, local_props,
props, props,
child_processed_tables, table_stack,
)?; )?;
} else { } else {
table.get_all_props(tables, excludes, props, child_processed_tables)?; table.push_props_end(tables, excludes, props, table_stack)?;
} }
} else {
dbg!(table.name.as_str());
} }
} else { } else {
local_props.push(SendPropDefinition::try_from(prop)?); local_props.push(SendPropDefinition::try_from(prop)?);
} }
Ok(()) Ok(())
}) });
table_stack.pop();
result
} }
} }