Change a bit behavior of MatchJournal.reset* methods

Now after MatchJournal.reset(pos) cursor points before
the `pos`, not at it. So cursor.next will return 'pos'
It's required for MPSCR-67
This commit is contained in:
Grigorii Kirgizov 2020-12-17 19:45:21 +03:00
parent 2b46ab0413
commit 273d4dc4db
2 changed files with 44 additions and 22 deletions

View File

@ -76,15 +76,21 @@ interface MatchJournal : Iterable<MatchJournal.Chunk>, EvidenceSource {
val cursor: RemovingJournalIterator
/**
* Reset journal's position to the beginning, don't modify journal.
* Same as [resetCursor], moves [cursor] before [initialChunk].
*/
fun resetCursor()
fun resetCursor() = resetCursor(Pos(initialChunk(), 0))
/**
* Erase part of the journal between [currentPos] and [pastPos].
* Resets journal position to specified position.
* Moves [cursor] before [pastPos], so that [ChunkReader.next] is [pastPos].
* Doesn't modify journal contents, as opposed to [reset].
*/
fun resetCursor(pastPos: Pos)
/**
* Erase journal between [currentPos] (erased) and [pastPos] (not erased).
* Moves [cursor] at [pastPos], so that [ChunkReader.current] is [pastPos].
* @param pastPos position to reset to.
* @throws IllegalStateException when position is not from the past (relative to current pos).
* @throws IllegalStateException when position is not from the past (relative to [cursor]).
*/
fun reset(pastPos: Pos)
@ -92,7 +98,7 @@ interface MatchJournal : Iterable<MatchJournal.Chunk>, EvidenceSource {
* Replay activated and discarded occurrences logged in journal between current
* and provided positions. Advances journal position to specified position.
* Idempotent operation (can be called multiple times on same [Pos]]).
* @throws IllegalStateException when position is not from the future (relative to current pos).
* @throws IllegalStateException when [futurePos] is not from the future (relative to [cursor]).
*/
fun replay(futurePos: Pos)
@ -131,6 +137,12 @@ interface MatchJournal : Iterable<MatchJournal.Chunk>, EvidenceSource {
*/
fun isKnown(chunk: Chunk): Boolean
/**
* Same as [isKnown], but for [Occurrence].
* Returns [true] for indexed [Occurrence]s.
*/
fun isKnown(occ: Occurrence): Boolean = activatingChunkOf(occ) != null
/**
* Returns [Chunk] where [occ] was activated.
* Returns null for non-principal occurrences & those not from indexed session.

View File

@ -189,19 +189,25 @@ internal open class MatchJournalImpl(
override fun isFront(): Boolean = __cursor.atEnd()
override fun reset(pastPos: MatchJournal.Pos) = reset(pastPos, true)
override fun reset(pastPos: MatchJournal.Pos) {
reset(pastPos, true)
replay(pastPos)
}
override fun resetCursor() = reset(Pos(initialChunk(), 0), false)
override fun resetCursor(pastPos: Pos) {
reset(pastPos, false)
}
private fun reset(pastPos: MatchJournal.Pos, removing: Boolean) = with(__cursor) {
moveToPastRemoving(pastPos) {
private fun reset(pastPos: MatchJournal.Pos, removing: Boolean) {
__cursor.moveToPastRemoving(pastPos) {
popAncestor()
resetOccurrences(it.entries())
removing
removing && it !== pastPos.chunk
}
// drop occurrences at final chunk
if (removing) current.entries = current.entries.subList(0, pastPos.entriesCount)
resetOccurrences(current.entries.drop(pastPos.entriesCount))
if (removing) with(pastPos.chunk as ChunkImpl) {
entries = entries.subList(0, pastPos.entriesCount)
}
}
private fun popAncestor() {
@ -324,8 +330,9 @@ internal open class MatchJournalImpl(
/**
* Walk in journal in direct order ([from] -> [next])
* while applying [action] to each visited [Chunk].
* Walk in journal in direct order ([from] -> [current])
* while applying [action] to each visited [Chunk]
* (not including [from], but including [__current]).
* No journal state is changed, except by [action] effects
* (i.e. no reset or replay of occurrences is performed).
*/
@ -343,21 +350,24 @@ internal open class MatchJournalImpl(
}
/**
* Walk in journal in inverse order ([next] -> [pastPos])
* while applying [action] to each visited [Chunk]
* and removing it if [action] return [true] for it.
* Walk in journal in inverse order ([pastPos] <- [current]) while
* applying [action] to each [Chunk] (including [pastPos])
* and removing it if [action] returns true for it.
*
* Contract: after the call [__next] points to [pastPos].
*/
inline fun moveToPastRemoving(pastPos: Pos, action: (Chunk) -> Boolean) {
while (!atStart()) {
__current = it.previous()
if (action(__current)) {
it.remove()
}
if (this at pastPos) {
it.next() // make it point right after _previous_
__current = it.previous()
it.next() // make it point right after __current
updateNext()
return
}
if (action(current)) {
it.remove()
}
}
this assertAt pastPos
}