@@ -93,15 +93,21 @@ struct AstNodeData {
9393 NodeKind node_kind;
9494 const AstMetadata* metadata;
9595 size_t index;
96- size_t weight;
96+ size_t tree_size;
97+ size_t height;
9798 std::vector<AstNode*> children;
9899};
99100
100101struct AstMetadata {
102+ // The nodes in the AST in preorder.
103+ //
104+ // unique_ptr is used to guarantee pointer stability in the other tables.
101105 std::vector<std::unique_ptr<AstNode>> nodes;
102- std::vector<const AstNode*> postorder;
103- absl::flat_hash_map<int64_t , size_t > id_to_node;
104- absl::flat_hash_map<const cel::expr::Expr*, size_t > expr_to_node;
106+ std::vector<const AstNode* absl_nonnull> postorder;
107+ absl::flat_hash_map<int64_t , const AstNode* absl_nonnull> id_to_node;
108+ absl::flat_hash_map<const cel::expr::Expr*,
109+ const AstNode* absl_nonnull>
110+ expr_to_node;
105111
106112 AstNodeData& NodeDataAt (size_t index);
107113 size_t AddNode ();
@@ -123,13 +129,19 @@ struct PreorderTraits {
123129
124130// Wrapper around a CEL AST node that exposes traversal information.
125131class AstNode {
126- private:
132+ public:
133+ // A const Span like type that provides pre-order traversal for a sub tree.
134+ // provides .begin() and .end() returning bidirectional iterators to
135+ // const AstNode&.
127136 using PreorderRange =
128- tools_internal::SpanRange<tools_internal::PreorderTraits>;
137+ tools_internal::NavigableAstRange<tools_internal::PreorderTraits>;
138+
139+ // A const Span like type that provides post-order traversal for a sub tree.
140+ // provides .begin() and .end() returning bidirectional iterators to
141+ // const AstNode&.
129142 using PostorderRange =
130- tools_internal::SpanRange <tools_internal::PostorderTraits>;
143+ tools_internal::NavigableAstRange <tools_internal::PostorderTraits>;
131144
132- public:
133145 // The parent of this node or nullptr if it is a root.
134146 const AstNode* absl_nullable parent () const { return data_.parent ; }
135147
@@ -146,6 +158,13 @@ class AstNode {
146158 // The type of this node, analogous to Expr::ExprKindCase.
147159 NodeKind node_kind () const { return data_.node_kind ; }
148160
161+ // The number of nodes in the tree rooted at this node (including self).
162+ size_t tree_size () const { return data_.tree_size ; }
163+
164+ // The height of this node in the tree (the number of descendants including
165+ // self on the longest path).
166+ size_t height () const { return data_.height ; }
167+
149168 absl::Span<const AstNode* const > children () const {
150169 return absl::MakeConstSpan (data_.children );
151170 }
@@ -164,9 +183,6 @@ class AstNode {
164183 // - maps are traversed in order (alternating key, value per entry)
165184 // - comprehensions are traversed in the order: range, accu_init, condition,
166185 // step, result
167- //
168- // Return type is an implementation detail, it should only be used with auto
169- // or in a range-for loop.
170186 PreorderRange DescendantsPreorder () const ;
171187
172188 // Range over the descendants of this node (including self) using postorder
@@ -184,12 +200,16 @@ class AstNode {
184200};
185201
186202// NavigableExpr provides a view over a CEL AST that allows for generalized
187- // traversal.
203+ // traversal. The traversal structures are eagerly built on construction,
204+ // requiring a full traversal of the AST. This is intended for use in tools that
205+ // might require random access or multiple passes over the AST, amortizing the
206+ // cost of building the traversal structures.
188207//
189208// Pointers to AstNodes are owned by this instance and must not outlive it.
190209//
191- // Note: Assumes ptr stability of the input Expr pb -- this is only guaranteed
192- // if no mutations take place on the input.
210+ // `NavigableAst` and Navigable nodes are independent of the input Expr and may
211+ // outlive it, but may contain dangling pointers if the input Expr is modified
212+ // or destroyed.
193213class NavigableAst {
194214 public:
195215 static NavigableAst Build (const cel::expr::Expr& expr);
@@ -217,7 +237,7 @@ class NavigableAst {
217237 if (it == metadata_->id_to_node .end ()) {
218238 return nullptr ;
219239 }
220- return metadata_-> nodes [ it->second ]. get () ;
240+ return it->second ;
221241 }
222242
223243 // Return ptr to the AST node representing the given Expr protobuf node.
@@ -227,7 +247,7 @@ class NavigableAst {
227247 if (it == metadata_->expr_to_node .end ()) {
228248 return nullptr ;
229249 }
230- return metadata_-> nodes [ it->second ]. get () ;
250+ return it->second ;
231251 }
232252
233253 // The root of the AST.
0 commit comments