@@ -31,7 +31,7 @@ import (
31
31
// Call [Root] to obtain a valid cursor.
32
32
type Cursor struct {
33
33
in * inspector.Inspector
34
- index int // index of push node; -1 for virtual root node
34
+ index int32 // index of push node; -1 for virtual root node
35
35
}
36
36
37
37
// Root returns a cursor for the virtual root node,
@@ -63,9 +63,9 @@ func (c Cursor) String() string {
63
63
}
64
64
65
65
// indices return the [start, end) half-open interval of event indices.
66
- func (c Cursor ) indices () (int , int ) {
66
+ func (c Cursor ) indices () (int32 , int32 ) {
67
67
if c .index < 0 {
68
- return 0 , len (c .events ()) // root: all events
68
+ return 0 , int32 ( len (c .events () )) // root: all events
69
69
} else {
70
70
return c .index , c .events ()[c .index ].index + 1 // just one subtree
71
71
}
@@ -154,10 +154,7 @@ func (c Cursor) Inspect(types []ast.Node, f func(c Cursor, push bool) (descend b
154
154
// from the [ast.File] down to the current cursor's node.
155
155
//
156
156
// To amortize allocation, it appends to the provided slice, which
157
- // must be empty. Even so, a traversal that frequently calls Stack on
158
- // a Cursor may be slower than using [Inspector.WithStack].
159
- // For best performance, call Stack selectively, or use
160
- // [Cursor.Parent] instead where practical.
157
+ // must be empty.
161
158
//
162
159
// Stack must not be called on the Root node.
163
160
func (c Cursor ) Stack (stack []Cursor ) []Cursor {
@@ -168,30 +165,9 @@ func (c Cursor) Stack(stack []Cursor) []Cursor {
168
165
panic ("Cursor.Stack called on Root node" )
169
166
}
170
167
171
- // The events[i] operation is a hotspot due to the bounds
172
- // check, unpredictable load, and high cache miss rate.
173
- // This could be mitigated two ways:
174
- //
175
- // 1. Reducing the size of the event struct by 25% by changing
176
- // event.node to just the value portion (unsafe.Pointer) of
177
- // the interface. (The ast.Node itab can be reconstructed
178
- // from the event.typ bitmask.) This was measured in CL 637740
179
- // but found to deliver disappointing gains (<10%).
180
- //
181
- // 2. Change event.index to uint32 (which is plenty). Though this
182
- // wouldn't change the size of the table, it would create
183
- // space for an explicit parent index, making Parent and
184
- // Stack optimal.
185
-
186
168
events := c .events ()
187
- for i := c .index ; i >= 0 ; i -- {
188
- if j := events [i ].index ; j > i {
189
- // push
190
- stack = append (stack , Cursor {c .in , i })
191
- } else {
192
- // pop: skip to before corresponding push
193
- i = j
194
- }
169
+ for i := c .index ; i >= 0 ; i = events [i ].parent {
170
+ stack = append (stack , Cursor {c .in , i })
195
171
}
196
172
slices .Reverse (stack )
197
173
return stack
@@ -200,25 +176,12 @@ func (c Cursor) Stack(stack []Cursor) []Cursor {
200
176
// Parent returns the parent of the current node.
201
177
//
202
178
// Parent must not be called on the Root node (whose [Cursor.Node] returns nil).
203
- //
204
- // The cost of this operation is proportional to the number of the
205
- // node's preceding siblings.
206
179
func (c Cursor ) Parent () Cursor {
207
180
if c .index < 0 {
208
181
panic ("Cursor.Parent called on Root node" )
209
182
}
210
183
211
- events := c .events ()
212
- i := c .index - 1
213
- for i >= 0 {
214
- if j := events [i ].index ; j > i { // push?
215
- break
216
- } else {
217
- // pop: skip to before corresponding push
218
- i = j - 1
219
- }
220
- }
221
- return Cursor {c .in , i }
184
+ return Cursor {c .in , c .events ()[c .index ].parent }
222
185
}
223
186
224
187
// NextSibling returns the cursor for the next sibling node in the
@@ -234,7 +197,7 @@ func (c Cursor) NextSibling() (Cursor, bool) {
234
197
235
198
events := c .events ()
236
199
i := events [c .index ].index + 1 // after corresponding pop
237
- if i < len (events ) {
200
+ if i < int32 ( len (events ) ) {
238
201
if events [i ].index > i { // push?
239
202
return Cursor {c .in , i }, true
240
203
}
@@ -267,8 +230,8 @@ func (c Cursor) PrevSibling() (Cursor, bool) {
267
230
// or zero if it has no children.
268
231
func (c Cursor ) FirstChild () (Cursor , bool ) {
269
232
events := c .events ()
270
- i := c .index + 1 // i=0 if c is root
271
- if i < len (events ) && events [i ].index > i { // push?
233
+ i := c .index + 1 // i=0 if c is root
234
+ if i < int32 ( len (events ) ) && events [i ].index > i { // push?
272
235
return Cursor {c .in , i }, true
273
236
}
274
237
return Cursor {}, false
@@ -359,7 +322,7 @@ func (c Cursor) FindPos(start, end token.Pos) (Cursor, bool) {
359
322
// This algorithm could be implemented using c.Inspect,
360
323
// but it is about 2.5x slower.
361
324
362
- best := - 1 // push index of latest (=innermost) node containing range
325
+ best := int32 ( - 1 ) // push index of latest (=innermost) node containing range
363
326
for i , limit := c .indices (); i < limit ; i ++ {
364
327
ev := events [i ]
365
328
if ev .index > i { // push?
0 commit comments