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 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]. * Moves [cursor] before [pastPos], so that [ChunkReader.next] is [pastPos].
* Resets journal position to specified position. * 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. * @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) fun reset(pastPos: Pos)
@ -92,7 +98,7 @@ interface MatchJournal : Iterable<MatchJournal.Chunk>, EvidenceSource {
* Replay activated and discarded occurrences logged in journal between current * Replay activated and discarded occurrences logged in journal between current
* and provided positions. Advances journal position to specified position. * and provided positions. Advances journal position to specified position.
* Idempotent operation (can be called multiple times on same [Pos]]). * 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) fun replay(futurePos: Pos)
@ -131,6 +137,12 @@ interface MatchJournal : Iterable<MatchJournal.Chunk>, EvidenceSource {
*/ */
fun isKnown(chunk: Chunk): Boolean 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 [Chunk] where [occ] was activated.
* Returns null for non-principal occurrences & those not from indexed session. * 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 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) { private fun reset(pastPos: MatchJournal.Pos, removing: Boolean) {
moveToPastRemoving(pastPos) { __cursor.moveToPastRemoving(pastPos) {
popAncestor() popAncestor()
resetOccurrences(it.entries()) resetOccurrences(it.entries())
removing removing && it !== pastPos.chunk
} }
// drop occurrences at final chunk // drop occurrences at final chunk
if (removing) current.entries = current.entries.subList(0, pastPos.entriesCount) if (removing) with(pastPos.chunk as ChunkImpl) {
resetOccurrences(current.entries.drop(pastPos.entriesCount)) entries = entries.subList(0, pastPos.entriesCount)
}
} }
private fun popAncestor() { private fun popAncestor() {
@ -324,8 +330,9 @@ internal open class MatchJournalImpl(
/** /**
* Walk in journal in direct order ([from] -> [next]) * Walk in journal in direct order ([from] -> [current])
* while applying [action] to each visited [Chunk]. * while applying [action] to each visited [Chunk]
* (not including [from], but including [__current]).
* No journal state is changed, except by [action] effects * No journal state is changed, except by [action] effects
* (i.e. no reset or replay of occurrences is performed). * (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]) * Walk in journal in inverse order ([pastPos] <- [current]) while
* while applying [action] to each visited [Chunk] * applying [action] to each [Chunk] (including [pastPos])
* and removing it if [action] return [true] for it. * 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) { inline fun moveToPastRemoving(pastPos: Pos, action: (Chunk) -> Boolean) {
while (!atStart()) { while (!atStart()) {
__current = it.previous() __current = it.previous()
if (action(__current)) {
it.remove()
}
if (this at pastPos) { if (this at pastPos) {
it.next() // make it point right after _previous_ __current = it.previous()
it.next() // make it point right after __current
updateNext() updateNext()
return return
} }
if (action(current)) {
it.remove()
}
} }
this assertAt pastPos this assertAt pastPos
} }