@@ -129,7 +129,7 @@ func (m *coreMatcher) deletePatterns(_ X) error {
129129// matchesForJSONEvent calls the flattener to pull the fields out of the event and
130130// hands over to MatchesForFields
131131// This is a leftover from previous times, is only used by tests, but it's used by a *lot*
132- // so removing it would require a lot of tedious work
132+ // and it's a convenient API for testing.
133133func (m * coreMatcher ) matchesForJSONEvent (event []byte ) ([]X , error ) {
134134 fields , err := newJSONFlattener ().Flatten (event , m .getSegmentsTreeTracker ())
135135 if err != nil {
@@ -178,20 +178,27 @@ func (m *coreMatcher) matchesForFields(fields []Field) ([]X, error) {
178178 }
179179 matches := newMatchSet ()
180180
181+ // pre-allocate a pair of buffers that will be used several levels down the call stack for efficiently
182+ // transversing NFAs
183+ bufs := & bufpair {
184+ buf1 : make ([]* faState , 0 ),
185+ buf2 : make ([]* faState , 0 ),
186+ }
187+
181188 // for each of the fields, we'll try to match the automaton start state to that field - the tryToMatch
182189 // routine will, in the case that there's a match, call itself to see if subsequent fields after the
183190 // first matched will transition through the machine and eventually achieve a match
184191 s := m .fields ()
185192 for i := 0 ; i < len (fields ); i ++ {
186- tryToMatch (fields , i , s .state , matches )
193+ tryToMatch (fields , i , s .state , matches , bufs )
187194 }
188195 return matches .matches (), nil
189196}
190197
191198// tryToMatch tries to match the field at fields[index] to the provided state. If it does match and generate
192199// 1 or more transitions to other states, it calls itself recursively to see if any of the remaining fields
193200// can continue the process by matching that state.
194- func tryToMatch (fields []Field , index int , state * fieldMatcher , matches * matchSet ) {
201+ func tryToMatch (fields []Field , index int , state * fieldMatcher , matches * matchSet , bufs * bufpair ) {
195202 stateFields := state .fields ()
196203
197204 // transition on exists:true?
@@ -200,16 +207,16 @@ func tryToMatch(fields []Field, index int, state *fieldMatcher, matches *matchSe
200207 matches = matches .addXSingleThreaded (existsTrans .fields ().matches ... )
201208 for nextIndex := index + 1 ; nextIndex < len (fields ); nextIndex ++ {
202209 if noArrayTrailConflict (fields [index ].ArrayTrail , fields [nextIndex ].ArrayTrail ) {
203- tryToMatch (fields , nextIndex , existsTrans , matches )
210+ tryToMatch (fields , nextIndex , existsTrans , matches , bufs )
204211 }
205212 }
206213 }
207214
208215 // an exists:false transition is possible if there is no matching field in the event
209- checkExistsFalse (stateFields , fields , index , matches )
216+ checkExistsFalse (stateFields , fields , index , matches , bufs )
210217
211218 // try to transition through the machine
212- nextStates := state .transitionOn (& fields [index ])
219+ nextStates := state .transitionOn (& fields [index ], bufs )
213220
214221 // for each state in the possibly-empty list of transitions from this state on fields[index]
215222 for _ , nextState := range nextStates {
@@ -221,17 +228,17 @@ func tryToMatch(fields []Field, index int, state *fieldMatcher, matches *matchSe
221228 // of the same array
222229 for nextIndex := index + 1 ; nextIndex < len (fields ); nextIndex ++ {
223230 if noArrayTrailConflict (fields [index ].ArrayTrail , fields [nextIndex ].ArrayTrail ) {
224- tryToMatch (fields , nextIndex , nextState , matches )
231+ tryToMatch (fields , nextIndex , nextState , matches , bufs )
225232 }
226233 }
227234 // now we've run out of fields to match this state against. But suppose it has an exists:false
228235 // transition, and it so happens that the exists:false pattern field is lexically larger than the other
229236 // fields and that in fact such a field does not exist. That state would be left hanging. So…
230- checkExistsFalse (nextStateFields , fields , index , matches )
237+ checkExistsFalse (nextStateFields , fields , index , matches , bufs )
231238 }
232239}
233240
234- func checkExistsFalse (stateFields * fmFields , fields []Field , index int , matches * matchSet ) {
241+ func checkExistsFalse (stateFields * fmFields , fields []Field , index int , matches * matchSet , bufs * bufpair ) {
235242 for existsFalsePath , existsFalseTrans := range stateFields .existsFalse {
236243 // it seems like there ought to be a more state-machine-idiomatic way to do this, but
237244 // I thought of a few and none of them worked. Quite likely someone will figure it out eventually.
@@ -250,9 +257,9 @@ func checkExistsFalse(stateFields *fmFields, fields []Field, index int, matches
250257 if i == len (fields ) {
251258 matches = matches .addXSingleThreaded (existsFalseTrans .fields ().matches ... )
252259 if thisFieldIsAnExistsFalse {
253- tryToMatch (fields , index + 1 , existsFalseTrans , matches )
260+ tryToMatch (fields , index + 1 , existsFalseTrans , matches , bufs )
254261 } else {
255- tryToMatch (fields , index , existsFalseTrans , matches )
262+ tryToMatch (fields , index , existsFalseTrans , matches , bufs )
256263 }
257264 }
258265 }
0 commit comments