MCPcopy Create free account
hub / github.com/argumentcomputer/ix / analyze_block

Function analyze_block

crates/ixon/src/sharing.rs:221–329  ·  view source on GitHub ↗

Analyze expressions for sharing opportunities within a block. Returns a map from content hash to SubtermInfo, and a map from pointer to hash. Uses a two-phase algorithm: 1. Build DAG structure via post-order traversal with Merkle-tree hashing 2. Propagate usage counts structurally from roots to leaves (O(n) total) If `track_hash_consed_size` is true, computes the hash-consed size for each subter

(
  exprs: &[Arc<Expr>],
  track_hash_consed_size: bool,
)

Source from the content-addressed store, hash-verified

219/// subterm (32-byte key + value). This adds overhead and can be disabled when
220/// only sharing analysis is needed.
221pub fn analyze_block(
222 exprs: &[Arc<Expr>],
223 track_hash_consed_size: bool,
224) -> (
225 HashMap<blake3::Hash, SubtermInfo>,
226 FxHashMap<*const Expr, blake3::Hash>,
227 Vec<blake3::Hash>,
228) {
229 let mut info_map: HashMap<blake3::Hash, SubtermInfo> = HashMap::new();
230 let mut ptr_to_hash: FxHashMap<*const Expr, blake3::Hash> =
231 FxHashMap::default();
232 let mut hash_buf: Vec<u8> = Vec::with_capacity(128);
233
234 // Phase 1: Build DAG structure via post-order traversal
235 // Don't compute usage counts here - just build the hash→children mapping
236 enum Frame<'a> {
237 Visit(&'a Arc<Expr>),
238 Process(&'a Arc<Expr>),
239 }
240
241 for root in exprs {
242 let mut stack: Vec<Frame<'_>> = vec![Frame::Visit(root)];
243
244 while let Some(frame) = stack.pop() {
245 match frame {
246 Frame::Visit(arc_expr) => {
247 let ptr = arc_expr.as_ref() as *const Expr;
248
249 // Already processed this pointer - just skip
250 // Usage counts will be computed in phase 2
251 if ptr_to_hash.contains_key(&ptr) {
252 continue;
253 }
254
255 // Push process frame, then children (in reverse for correct order)
256 stack.push(Frame::Process(arc_expr));
257 for child in get_children(arc_expr).into_iter().rev() {
258 stack.push(Frame::Visit(child));
259 }
260 },
261 Frame::Process(arc_expr) => {
262 let ptr = arc_expr.as_ref() as *const Expr;
263 if ptr_to_hash.contains_key(&ptr) {
264 continue;
265 }
266
267 let (hash, children, value_size) =
268 hash_node(arc_expr.as_ref(), &ptr_to_hash, &mut hash_buf);
269
270 // Add to ptr_to_hash cache
271 ptr_to_hash.insert(ptr, hash);
272
273 // Add to info_map if not already present (same content hash from different pointer)
274 info_map.entry(hash).or_insert_with(|| {
275 let base_size = compute_base_size(arc_expr.as_ref());
276 let hash_consed_size =
277 if track_hash_consed_size { 32 + value_size } else { 0 };
278 SubtermInfo {

Callers 11

apply_sharing_with_statsFunction · 0.85
rs_analyze_sharing_countFunction · 0.85
rs_run_sharing_analysisFunction · 0.85
hash_exprFunction · 0.85
test_early_break_bugFunction · 0.85
test_analyze_simpleFunction · 0.85
test_topological_sortFunction · 0.85
test_build_sharing_vecFunction · 0.85

Calls 12

get_childrenFunction · 0.85
hash_nodeFunction · 0.85
compute_base_sizeFunction · 0.85
topological_sortFunction · 0.85
pushMethod · 0.80
entryMethod · 0.80
contains_keyMethod · 0.45
insertMethod · 0.45
cloneMethod · 0.45
getMethod · 0.45
get_mutMethod · 0.45
iterMethod · 0.45

Tested by 5

test_early_break_bugFunction · 0.68
test_analyze_simpleFunction · 0.68
test_topological_sortFunction · 0.68
test_build_sharing_vecFunction · 0.68