use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use crate::Array;
use crate::array::ArrayRef;
pub mod rules;
pub trait ArrayOptimizer {
fn optimize(&self) -> VortexResult<ArrayRef>;
fn optimize_recursive(&self) -> VortexResult<ArrayRef>;
}
impl ArrayOptimizer for ArrayRef {
fn optimize(&self) -> VortexResult<ArrayRef> {
Ok(try_optimize(self)?.unwrap_or_else(|| self.clone()))
}
fn optimize_recursive(&self) -> VortexResult<ArrayRef> {
Ok(try_optimize_recursive(self)?.unwrap_or_else(|| self.clone()))
}
}
fn try_optimize(array: &ArrayRef) -> VortexResult<Option<ArrayRef>> {
let mut current_array = array.clone();
let mut any_optimizations = false;
let mut loop_counter = 0;
'outer: loop {
if loop_counter > 100 {
vortex_bail!("Exceeded maximum optimization iterations (possible infinite loop)");
}
loop_counter += 1;
if let Some(new_array) = current_array.vtable().reduce(¤t_array)? {
current_array = new_array;
any_optimizations = true;
continue;
}
for (idx, child) in current_array.children().iter().enumerate() {
if let Some(new_array) = child.vtable().reduce_parent(child, ¤t_array, idx)? {
current_array = new_array;
any_optimizations = true;
continue 'outer;
}
}
break;
}
if any_optimizations {
Ok(Some(current_array))
} else {
Ok(None)
}
}
fn try_optimize_recursive(array: &ArrayRef) -> VortexResult<Option<ArrayRef>> {
let mut current_array = array.clone();
let mut any_optimizations = false;
if let Some(new_array) = try_optimize(¤t_array)? {
current_array = new_array;
any_optimizations = true;
}
let mut new_children = Vec::with_capacity(current_array.nchildren());
let mut any_child_optimized = false;
for child in current_array.children() {
if let Some(new_child) = try_optimize_recursive(&child)? {
new_children.push(new_child);
any_child_optimized = true;
} else {
new_children.push(child.clone());
}
}
if any_child_optimized {
current_array = current_array.with_children(new_children)?;
any_optimizations = true;
}
if any_optimizations {
Ok(Some(current_array))
} else {
Ok(None)
}
}