@@ -779,6 +779,7 @@ impl<T> Transformed<T> {
779
779
}
780
780
}
781
781
782
+ /// Replaces recursion state with the given one
782
783
pub fn with_tnr ( mut self , tnr : TreeNodeRecursion ) -> Self {
783
784
self . tnr = tnr;
784
785
self
@@ -956,7 +957,8 @@ pub trait DynTreeNode {
956
957
) -> Result < Arc < Self > > ;
957
958
}
958
959
959
- pub struct LegacyRewriter <
960
+ /// Adapter from the old function-based rewriter to the new Transformer one
961
+ struct FuncRewriter <
960
962
FD : FnMut ( Node ) -> Result < Transformed < Node > > ,
961
963
FU : FnMut ( Node ) -> Result < Transformed < Node > > ,
962
964
Node : TreeNode ,
@@ -970,7 +972,7 @@ impl<
970
972
FD : FnMut ( Node ) -> Result < Transformed < Node > > ,
971
973
FU : FnMut ( Node ) -> Result < Transformed < Node > > ,
972
974
Node : TreeNode ,
973
- > LegacyRewriter < FD , FU , Node >
975
+ > FuncRewriter < FD , FU , Node >
974
976
{
975
977
pub fn new ( f_down_func : FD , f_up_func : FU ) -> Self {
976
978
Self {
@@ -984,7 +986,7 @@ impl<
984
986
FD : FnMut ( Node ) -> Result < Transformed < Node > > ,
985
987
FU : FnMut ( Node ) -> Result < Transformed < Node > > ,
986
988
Node : TreeNode ,
987
- > TreeNodeRewriter for LegacyRewriter < FD , FU , Node >
989
+ > TreeNodeRewriter for FuncRewriter < FD , FU , Node >
988
990
{
989
991
type Node = Node ;
990
992
@@ -997,7 +999,8 @@ impl<
997
999
}
998
1000
}
999
1001
1000
- macro_rules! update_rec_node {
1002
+ /// Replaces node's children and recomputes the state
1003
+ macro_rules! update_node_after_recursion {
1001
1004
( $NAME: ident, $CHILDREN: ident) => { {
1002
1005
$NAME. transformed |= $CHILDREN. iter( ) . any( |item| item. transformed) ;
1003
1006
@@ -1011,6 +1014,7 @@ macro_rules! update_rec_node {
1011
1014
1012
1015
/// Blanket implementation for any `Arc<T>` where `T` implements [`DynTreeNode`]
1013
1016
/// (such as [`Arc<dyn PhysicalExpr>`]).
1017
+ /// Unlike [`TreeNode`], performs node traversal iteratively rather than recursively to avoid stack overflow
1014
1018
impl < T : DynTreeNode + ?Sized > TreeNode for Arc < T > {
1015
1019
fn apply_children < ' n , F : FnMut ( & ' n Self ) -> Result < TreeNodeRecursion > > (
1016
1020
& ' n self ,
@@ -1051,41 +1055,36 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1051
1055
f_down : FD ,
1052
1056
f_up : FU ,
1053
1057
) -> Result < Transformed < Self > > {
1054
- self . rewrite ( & mut LegacyRewriter :: new ( f_down, f_up) )
1058
+ self . rewrite ( & mut FuncRewriter :: new ( f_down, f_up) )
1055
1059
}
1056
1060
1057
1061
fn transform_down < F : FnMut ( Self ) -> Result < Transformed < Self > > > (
1058
1062
self ,
1059
1063
f : F ,
1060
1064
) -> Result < Transformed < Self > > {
1061
- self . rewrite ( & mut LegacyRewriter :: new ( f, |node| {
1062
- Ok ( Transformed :: no ( node) )
1063
- } ) )
1065
+ self . rewrite ( & mut FuncRewriter :: new ( f, |node| Ok ( Transformed :: no ( node) ) ) )
1064
1066
}
1065
1067
1066
1068
fn transform_up < F : FnMut ( Self ) -> Result < Transformed < Self > > > (
1067
1069
self ,
1068
1070
f : F ,
1069
1071
) -> Result < Transformed < Self > > {
1070
- self . rewrite ( & mut LegacyRewriter :: new (
1071
- |node| Ok ( Transformed :: no ( node) ) ,
1072
- f,
1073
- ) )
1072
+ self . rewrite ( & mut FuncRewriter :: new ( |node| Ok ( Transformed :: no ( node) ) , f) )
1074
1073
}
1075
1074
fn rewrite < R : TreeNodeRewriter < Node = Self > > (
1076
1075
self ,
1077
1076
rewriter : & mut R ,
1078
1077
) -> Result < Transformed < Self > > {
1079
- let mut stack = vec ! [ ProcessingState :: NotStarted ( self ) ] ;
1078
+ let mut stack = vec ! [ TransformingState :: NotStarted ( self ) ] ;
1080
1079
1081
1080
while let Some ( item) = stack. pop ( ) {
1082
1081
match item {
1083
- ProcessingState :: NotStarted ( node) => {
1082
+ TransformingState :: NotStarted ( node) => {
1084
1083
let node = rewriter. f_down ( node) ?;
1085
1084
1086
1085
stack. push ( match node. tnr {
1087
1086
TreeNodeRecursion :: Continue => {
1088
- ProcessingState :: ProcessingChildren {
1087
+ TransformingState :: ProcessingChildren {
1089
1088
non_processed_children : node
1090
1089
. data
1091
1090
. arc_children ( )
@@ -1097,59 +1096,68 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1097
1096
processed_children : vec ! [ ] ,
1098
1097
}
1099
1098
}
1100
- TreeNodeRecursion :: Jump => ProcessingState :: ProcessedAllChildren (
1101
- node. with_tnr ( TreeNodeRecursion :: Continue ) ,
1102
- ) ,
1099
+ TreeNodeRecursion :: Jump => {
1100
+ TransformingState :: ProcessedAllChildren (
1101
+ // No need to process children, we can just this stage
1102
+ node. with_tnr ( TreeNodeRecursion :: Continue ) ,
1103
+ )
1104
+ }
1103
1105
TreeNodeRecursion :: Stop => {
1104
- ProcessingState :: ProcessedAllChildren ( node)
1106
+ TransformingState :: ProcessedAllChildren ( node)
1105
1107
}
1106
1108
} )
1107
1109
}
1108
- ProcessingState :: ProcessingChildren {
1110
+ TransformingState :: ProcessingChildren {
1109
1111
mut item,
1110
1112
mut non_processed_children,
1111
1113
mut processed_children,
1112
1114
} => match item. tnr {
1113
1115
TreeNodeRecursion :: Continue | TreeNodeRecursion :: Jump => {
1114
1116
if let Some ( non_processed_item) = non_processed_children. pop ( ) {
1115
- stack. push ( ProcessingState :: ProcessingChildren {
1116
- item,
1117
- non_processed_children,
1118
- processed_children,
1119
- } ) ;
1120
- stack. push ( ProcessingState :: NotStarted ( non_processed_item) ) ;
1117
+ stack. extend ( [
1118
+ // This node still has children, so put it back in the stack
1119
+ TransformingState :: ProcessingChildren {
1120
+ item,
1121
+ non_processed_children,
1122
+ processed_children,
1123
+ } ,
1124
+ // Also put the child which will be processed first
1125
+ TransformingState :: NotStarted ( non_processed_item) ,
1126
+ ] ) ;
1121
1127
} else {
1122
- stack. push ( ProcessingState :: ProcessedAllChildren (
1123
- update_rec_node ! ( item, processed_children) ,
1128
+ stack. push ( TransformingState :: ProcessedAllChildren (
1129
+ update_node_after_recursion ! ( item, processed_children) ,
1124
1130
) )
1125
1131
}
1126
1132
}
1127
1133
TreeNodeRecursion :: Stop => {
1134
+ // At this point, we might have some children we haven't yet processed
1128
1135
processed_children. extend (
1129
1136
non_processed_children
1130
1137
. into_iter ( )
1131
1138
. rev ( )
1132
1139
. map ( Transformed :: no) ,
1133
1140
) ;
1134
- stack. push ( ProcessingState :: ProcessedAllChildren (
1135
- update_rec_node ! ( item, processed_children) ,
1141
+ stack. push ( TransformingState :: ProcessedAllChildren (
1142
+ update_node_after_recursion ! ( item, processed_children) ,
1136
1143
) ) ;
1137
1144
}
1138
1145
} ,
1139
- ProcessingState :: ProcessedAllChildren ( node) => {
1146
+ TransformingState :: ProcessedAllChildren ( node) => {
1140
1147
let node = node. transform_parent ( |n| rewriter. f_up ( n) ) ?;
1141
1148
1142
- if let Some ( ProcessingState :: ProcessingChildren {
1149
+ if let Some ( TransformingState :: ProcessingChildren {
1143
1150
item : mut parent_node,
1144
1151
non_processed_children,
1145
1152
mut processed_children,
1146
1153
..
1147
1154
} ) = stack. pop ( )
1148
1155
{
1156
+ // We need use returned recursion state when processing the remaining children
1149
1157
parent_node. tnr = node. tnr ;
1150
1158
processed_children. push ( node) ;
1151
1159
1152
- stack. push ( ProcessingState :: ProcessingChildren {
1160
+ stack. push ( TransformingState :: ProcessingChildren {
1153
1161
item : parent_node,
1154
1162
non_processed_children,
1155
1163
processed_children,
@@ -1189,10 +1197,7 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1189
1197
item,
1190
1198
tnr : TreeNodeRecursion :: Continue ,
1191
1199
} ,
1192
- TreeNodeRecursion :: Stop => VisitingState :: VisitedAllChildren {
1193
- item,
1194
- tnr : TreeNodeRecursion :: Stop ,
1195
- } ,
1200
+ TreeNodeRecursion :: Stop => return Ok ( tnr) ,
1196
1201
} ) ;
1197
1202
}
1198
1203
VisitingState :: VisitingChildren {
@@ -1202,12 +1207,15 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1202
1207
} => match tnr {
1203
1208
TreeNodeRecursion :: Continue | TreeNodeRecursion :: Jump => {
1204
1209
if let Some ( non_processed_item) = non_processed_children. pop ( ) {
1205
- stack. push ( VisitingState :: VisitingChildren {
1206
- item,
1207
- non_processed_children,
1208
- tnr,
1209
- } ) ;
1210
- stack. push ( VisitingState :: NotStarted ( non_processed_item) ) ;
1210
+ stack. extend ( [
1211
+ // Returning the node on the stack because there are more children to process
1212
+ VisitingState :: VisitingChildren {
1213
+ item,
1214
+ non_processed_children,
1215
+ tnr,
1216
+ } ,
1217
+ VisitingState :: NotStarted ( non_processed_item) ,
1218
+ ] ) ;
1211
1219
} else {
1212
1220
stack. push ( VisitingState :: VisitedAllChildren { item, tnr } ) ;
1213
1221
}
@@ -1220,10 +1228,10 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1220
1228
let tnr = tnr. visit_parent ( || visitor. f_up ( item) ) ?;
1221
1229
1222
1230
if let Some ( VisitingState :: VisitingChildren {
1223
- item,
1224
- non_processed_children,
1225
- ..
1226
- } ) = stack. pop ( )
1231
+ item,
1232
+ non_processed_children,
1233
+ .. // we don't care about the parent recursion state, because it will be replaced with the current state anyway
1234
+ } ) = stack. pop ( )
1227
1235
{
1228
1236
stack. push ( VisitingState :: VisitingChildren {
1229
1237
item,
@@ -1242,35 +1250,32 @@ impl<T: DynTreeNode + ?Sized> TreeNode for Arc<T> {
1242
1250
}
1243
1251
}
1244
1252
1245
- #[ derive( Debug ) ]
1246
- enum ProcessingState < T > {
1253
+ /// Node iterative transformation state. Each node on the stack is visited several times, state determines the operation that is going to run next
1254
+ enum TransformingState < T > {
1255
+ /// Node was just created. When executed, f_down will be called.
1247
1256
NotStarted ( T ) ,
1248
- // ← at this point, f_down is called
1257
+ /// DFS over node's children
1249
1258
ProcessingChildren {
1250
1259
item : Transformed < T > ,
1251
1260
non_processed_children : Vec < T > ,
1252
1261
processed_children : Vec < Transformed < T > > ,
1253
1262
} ,
1254
- // ← at this point, all children are processed
1263
+ /// All children are processed (or jumped through). When executed, f_up may be called
1255
1264
ProcessedAllChildren ( Transformed < T > ) ,
1256
- // ← at this point, f_up is called
1257
1265
}
1258
1266
1259
- # [ derive ( Debug ) ]
1267
+ /// Node iterative visit state. Each node on the stack is visited several times, state determines the operation that is going to run next
1260
1268
enum VisitingState < ' a , T > {
1269
+ /// Node was just created. When executed, f_down will be called.
1261
1270
NotStarted ( & ' a T ) ,
1262
- // ← at this point, f_down is called
1271
+ /// DFS over node's children. During processing, reference to children are removed from the inner stack
1263
1272
VisitingChildren {
1264
1273
item : & ' a T ,
1265
1274
non_processed_children : Vec < & ' a T > ,
1266
1275
tnr : TreeNodeRecursion ,
1267
1276
} ,
1268
- // ← at this point, all children are visited
1269
- VisitedAllChildren {
1270
- item : & ' a T ,
1271
- tnr : TreeNodeRecursion ,
1272
- } ,
1273
- // ← at this point, f_up is called
1277
+ /// All children are processed (or jumped through). When executed, f_up may be called
1278
+ VisitedAllChildren { item : & ' a T , tnr : TreeNodeRecursion } ,
1274
1279
}
1275
1280
1276
1281
/// Instead of implementing [`TreeNode`], it's recommended to implement a [`ConcreteTreeNode`] for
@@ -1409,11 +1414,8 @@ pub(crate) mod tests {
1409
1414
. collect ( )
1410
1415
}
1411
1416
1412
- /// Implement this train in order for your struct to be supported in parametrisation
1413
- pub ( crate ) trait TestTree < T : PartialEq >
1414
- where
1415
- T : Sized ,
1416
- {
1417
+ /// [`node_tests`] uses methods when generating tests
1418
+ pub ( crate ) trait TestTree < T : PartialEq > {
1417
1419
fn new_with_children ( children : Vec < Self > , data : T ) -> Self
1418
1420
where
1419
1421
Self : Sized ;
@@ -1427,7 +1429,7 @@ pub(crate) mod tests {
1427
1429
fn with_children_from ( data : T , other : Self ) -> Self ;
1428
1430
}
1429
1431
1430
- macro_rules! gen_tests {
1432
+ macro_rules! node_tests {
1431
1433
( $TYPE: ident) => {
1432
1434
fn visit_continue<T : PartialEq >( _: & $TYPE<T >) -> Result <TreeNodeRecursion > {
1433
1435
Ok ( TreeNodeRecursion :: Continue )
@@ -2546,7 +2548,7 @@ pub(crate) mod tests {
2546
2548
}
2547
2549
}
2548
2550
2549
- gen_tests ! ( TestTreeNode ) ;
2551
+ node_tests ! ( TestTreeNode ) ;
2550
2552
}
2551
2553
2552
2554
pub mod test_dyn_tree_node {
@@ -2607,7 +2609,7 @@ pub(crate) mod tests {
2607
2609
2608
2610
type ArcTestNode < T > = Arc < DynTestNode < T > > ;
2609
2611
2610
- gen_tests ! ( ArcTestNode ) ;
2612
+ node_tests ! ( ArcTestNode ) ;
2611
2613
2612
2614
#[ test]
2613
2615
fn test_large_tree ( ) {
0 commit comments