@@ -11,7 +11,7 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
1111
1212/// The coverage counter or counter expression associated with a particular
1313/// BCB node or BCB edge.
14- #[ derive( Clone , Copy ) ]
14+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
1515pub ( super ) enum BcbCounter {
1616 Counter { id : CounterId } ,
1717 Expression { id : ExpressionId } ,
@@ -35,7 +35,7 @@ impl Debug for BcbCounter {
3535 }
3636}
3737
38- #[ derive( Debug ) ]
38+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
3939struct BcbExpression {
4040 lhs : BcbCounter ,
4141 op : Op ,
@@ -63,9 +63,13 @@ pub(super) struct CoverageCounters {
6363 /// We currently don't iterate over this map, but if we do in the future,
6464 /// switch it back to `FxIndexMap` to avoid query stability hazards.
6565 bcb_edge_counters : FxHashMap < ( BasicCoverageBlock , BasicCoverageBlock ) , BcbCounter > ,
66+
6667 /// Table of expression data, associating each expression ID with its
6768 /// corresponding operator (+ or -) and its LHS/RHS operands.
6869 expressions : IndexVec < ExpressionId , BcbExpression > ,
70+ /// Remember expressions that have already been created (or simplified),
71+ /// so that we don't create unnecessary duplicates.
72+ expressions_memo : FxHashMap < BcbExpression , BcbCounter > ,
6973}
7074
7175impl CoverageCounters {
@@ -83,6 +87,7 @@ impl CoverageCounters {
8387 bcb_counters : IndexVec :: from_elem_n ( None , num_bcbs) ,
8488 bcb_edge_counters : FxHashMap :: default ( ) ,
8589 expressions : IndexVec :: new ( ) ,
90+ expressions_memo : FxHashMap :: default ( ) ,
8691 } ;
8792
8893 MakeBcbCounters :: new ( & mut this, basic_coverage_blocks)
@@ -97,7 +102,20 @@ impl CoverageCounters {
97102 }
98103
99104 fn make_expression ( & mut self , lhs : BcbCounter , op : Op , rhs : BcbCounter ) -> BcbCounter {
100- let id = self . expressions . push ( BcbExpression { lhs, op, rhs } ) ;
105+ let new_expr = BcbExpression { lhs, op, rhs } ;
106+ * self
107+ . expressions_memo
108+ . entry ( new_expr)
109+ . or_insert_with ( || Self :: make_expression_inner ( & mut self . expressions , new_expr) )
110+ }
111+
112+ /// This is an associated function so that we can call it while borrowing
113+ /// `&mut self.expressions_memo`.
114+ fn make_expression_inner (
115+ expressions : & mut IndexVec < ExpressionId , BcbExpression > ,
116+ new_expr : BcbExpression ,
117+ ) -> BcbCounter {
118+ let id = expressions. push ( new_expr) ;
101119 BcbCounter :: Expression { id }
102120 }
103121
0 commit comments