1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-02-25 02:46:01 +01:00

Avoid generation of the huge amount of sets during regex search

The tests shows that the depth of `epsilonVisited` is usually around 0-3, so there is no need to use the set. However, when the set is used, we have to make a new copy everytime we create a new `SimulationStackFrame`.
Now, the previous stack is reused.
This commit is contained in:
Alex Plate 2024-03-11 18:51:46 +02:00
parent 629e4e7053
commit 1f1a8f3395
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F

View File

@ -68,8 +68,8 @@ internal class BacktrackingStrategy : SimulationStrategy {
possibleCursors: MutableList<VimCaret>,
maxIndex: Int = editor.text().length
): NFASimulationResult {
val stack = emptyList<SimulationStackFrame>().toMutableList()
stack.add(SimulationStackFrame(index, state, emptySet()))
val stack = mutableListOf<SimulationStackFrame>()
stack.add(SimulationStackFrame(index, state, NfaStateList.empty))
while (stack.isNotEmpty()) {
val currFrame = stack.removeLast()
@ -78,16 +78,18 @@ internal class BacktrackingStrategy : SimulationStrategy {
if (currFrame.currentState === targetState) return NFASimulationResult(true, currFrame.currentIndex)
currFrame.currentState.assertion?.let {
val assertionResult = handleAssertion(editor, currFrame.currentIndex, isCaseInsensitive, it, possibleCursors)
if (assertionResult.simulationResult) stack.add(SimulationStackFrame(assertionResult.index, currFrame.currentState.assertion!!.jumpTo, emptySet()))
if (assertionResult.simulationResult) stack.add(SimulationStackFrame(assertionResult.index, currFrame.currentState.assertion!!.jumpTo, NfaStateList.empty))
}
for (transition in currFrame.currentState.transitions.reversed()) {
for (i in currFrame.currentState.transitions.lastIndex downTo 0) {
val transition = currFrame.currentState.transitions[i]
val transitionMatcherResult = transition.matcher.matches(editor, currFrame.currentIndex, groups, isCaseInsensitive, possibleCursors)
if (transitionMatcherResult !is MatcherResult.Success) continue
val destState = transition.destState
if (transitionMatcherResult.consumed == 0 && currFrame.epsilonVisited.contains(destState)) continue
val nextIndex = currFrame.currentIndex + transitionMatcherResult.consumed
val epsilonVisitedCopy = if (transitionMatcherResult.consumed == 0 && !currFrame.epsilonVisited.contains(destState)) currFrame.epsilonVisited.plusElement(currFrame.currentState) else HashSet()
val epsilonVisitedCopy = if (transitionMatcherResult.consumed == 0 && !currFrame.epsilonVisited.contains(destState)) NfaStateList(currFrame.currentState, currFrame.epsilonVisited) else NfaStateList.empty
stack.add(SimulationStackFrame(nextIndex, destState, epsilonVisitedCopy))
}
}
@ -222,5 +224,18 @@ private data class NFASimulationResult(
private data class SimulationStackFrame(
val currentIndex: Int,
val currentState: NFAState,
val epsilonVisited: Set<NFAState>
)
val epsilonVisited: NfaStateList,
)
private class NfaStateList(
val item: NFAState,
val tail: NfaStateList?,
) {
fun contains(item: NFAState): Boolean {
return this.item == item || this.tail?.contains(item) == true
}
companion object {
val empty = NfaStateList(NFAState(), null)
}
}