use alloc::vec::Vec;
use super::blocks::pack;
use super::mutate::Arena;
use super::{Document, NodeId};
impl Document {
pub fn compact(&mut self) {
let mut fresh = Arenas::default();
let tops: Vec<NodeId> =
self.nodes().filter(|n| self.parent(*n).is_none()).collect();
for top in tops {
self.rebuild_subtree(top, &mut fresh);
}
self.child_ids = fresh.children;
self.attr_ids = fresh.attributes;
self.ns_ids = fresh.namespaces;
self.child_caps.clear();
self.attr_caps.clear();
self.ns_caps.clear();
self.scratch = Vec::new();
self.refresh_order();
}
fn rebuild_subtree(&mut self, top: NodeId, out: &mut Arenas) {
let mut stack = Vec::from([top]);
while let Some(id) = stack.pop() {
let start = out.children.len();
out.children.extend_from_slice(self.children(id));
let children = pack(start, out.children.len() - start);
let attributes =
copy_block(&mut out.attributes, self.attribute_nodes(id));
let namespaces =
copy_block(&mut out.namespaces, self.namespace_nodes(id));
self.set_block_range(id, Arena::Children, children);
self.set_block_range(id, Arena::Attributes, attributes);
self.set_block_range(id, Arena::Namespaces, namespaces);
stack.extend(out.children[start..].iter().rev());
}
}
}
#[derive(Default)]
struct Arenas {
children: Vec<NodeId>,
attributes: Vec<NodeId>,
namespaces: Vec<NodeId>,
}
fn copy_block(into: &mut Vec<NodeId>, block: &[NodeId]) -> (u32, u32) {
let start = into.len();
into.extend_from_slice(block);
pack(start, block.len())
}