Refactor: hide mutability of Chunk.entries (both as var and as MutableList). Add a bit of docs.

This commit is contained in:
Grigorii Kirgizov 2020-03-12 17:59:27 +03:00
parent 7c40295948
commit b10b69545e
3 changed files with 81 additions and 42 deletions

View File

@ -51,7 +51,10 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk>, EvidenceSource {
fun initialChunk(): MatchChunk
/**
* Current position at the journal.
* Returns current [Chunk] position in the journal.
* NB: returned [Pos] isn't granular: it doesn't take into account
* replayed position *inside* [Chunk], that is, [Pos.entriesCount]
* will return the count of all [Occurrence]s.
*/
fun currentPos(): Pos
@ -82,8 +85,9 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk>, EvidenceSource {
fun dropDescendantsWhile(ancestor: Chunk, dropIf: (Chunk) -> Boolean)
/**
* Replay activated and discarded occurrences logged in journal between current and provided positions.
* Advances journal position to specified position.
* 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).
*/
fun replay(futurePos: Pos)
@ -140,54 +144,71 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk>, EvidenceSource {
*/
data class View(val chunks: List<Chunk>, val evidenceSeed: Evidence) : MatchJournalView {
override fun getStoreView(): StoreView = StoreViewImpl(
chunks.flatMap { it.entriesLog() }.allOccurrences().asSequence()
chunks.flatMap { it.entries() }.allOccurrences().asSequence()
)
}
/**
* [MatchJournal] operates on [Chunk]s -- basic [Justified] entities.
* Each [Chunk] contains a number of entries, corresponding to events
* of activated and discarded [Occurrence]s, which happened before
* the next [Chunk] was logged.
*/
interface Chunk : Justified {
// fixme: hide rm-mutability
var entries: MutableList<Entry>
fun entriesLog(): List<Entry> = entries
/**
* Corresponds to event of activated or discarded [Occurrence]
*/
data class Entry(val occ: Occurrence, val discarded: Boolean = false) {
override fun toString() = (if (discarded) '-' else '+') + occ.toString()
}
fun isDescendantOf(chunk: Chunk): Boolean = this.justifiedBy(chunk)
fun isTopLevel(): Boolean = justifications().size() <= 1 // this condition implies that there're no ancestor chunks
/**
* Returns historically ordered list of activated and discarded [Occurrence]s.
*/
fun entries(): List<Entry>
fun activatedLog(): List<Occurrence> = entriesLog().filter { !it.discarded }.map { it.occ }
fun discardedLog(): List<Occurrence> = entriesLog().filter { it.discarded }.map { it.occ }
/**
* Check whether this [Chunk] depends on another, which is specified by justifications.
*/
fun isDescendantOf(chunk: Chunk): Boolean = this.justifiedBy(chunk)
/**
* Checks whether this [Chunk] has no ancestors (not counting [MatchJournal.initialChunk])
*/
fun isTopLevel(): Boolean = justifications().size() <= 1
/**
* Same as [entries], but returns only activated [Occurrence]s.
*/
fun activatedLog(): List<Occurrence> = entries().filter { !it.discarded }.map { it.occ }
/**
* Same as [entries], but returns only discarded [Occurrence]s.
*/
fun discardedLog(): List<Occurrence> = entries().filter { it.discarded }.map { it.occ }
/**
* Returns the resulting collection of activated occurrences
* without discarded (only in this chunk!) occurrences.
*/
fun activated(): List<Occurrence> = entriesLog().allOccurrences()
fun activated(): List<Occurrence> = entries().allOccurrences()
fun toPos(): Pos = Pos(this, entriesLog().size)
fun toPos(): Pos = Pos(this, entries().size)
}
class MatchChunk(override val evidence: Evidence, val match: RuleMatch) : Chunk {
private val justifications = match.justifications().apply { add(evidence) }
override fun justifications(): Justifications = justifications
override var entries: MutableList<Chunk.Entry> = mutableListOf()
override fun entriesLog(): List<Chunk.Entry> = entries
override fun toString() = "(id=$evidence, ${justifications()}, ${match.rule().tag()}, $entries)"
/**
* [Chunk] corresponding to a [RuleMatch] of a principal [Rule].
*/
interface MatchChunk : Chunk {
val match: RuleMatch
val ruleUniqueTag: Any get() = match.rule().uniqueTag()
}
class OccChunk(val occ: Occurrence) : Chunk, Justified by occ {
override var entries: MutableList<Chunk.Entry> = mutableListOf()
override fun toString() = "(id=$evidence, ${justifications()}, activation of $occ, $entries)"
/**
* [Chunk] corresponding to an activation of a principal [Occurrence].
*/
interface OccChunk : Chunk {
val occ: Occurrence
}
open class Pos(val chunk: Chunk, val entriesCount: Int) {

View File

@ -34,8 +34,26 @@ internal open class MatchJournalImpl(
view: MatchJournal.View? = null
) : MatchJournal {
private abstract class ChunkImpl : Chunk {
var entries: MutableList<Chunk.Entry> = mutableListOf()
override fun entries(): List<Chunk.Entry> = entries
}
private class MatchChunkImpl(override val evidence: Evidence, override val match: RuleMatch) : ChunkImpl(), MatchChunk {
override fun toString() = "(id=$evidence, ${justifications()}, ${match.rule().tag()}, $entries)"
override fun justifications(): Justifications = justifications
private val justifications = match.justifications().apply { add(evidence) }
}
private class OccChunkImpl(override val occ: Occurrence) : ChunkImpl(), Justified by occ, OccChunk {
override fun toString() = "(id=$evidence, ${justifications()}, activation of $occ, $entries)"
}
// invariant: never empty
private val hist: IteratorMutableList<Chunk>
private val hist: IteratorMutableList<ChunkImpl>
private var evidenceSeed: Evidence
@ -45,14 +63,14 @@ internal open class MatchJournalImpl(
init {
if (view == null) {
evidenceSeed = 0
val initChunk = MatchChunk(nextEvidence(), InitRuleMatch)
hist = IteratorMutableList(LinkedList<Chunk>().apply { add(initChunk) })
val initChunk = MatchChunkImpl(nextEvidence(), InitRuleMatch)
hist = IteratorMutableList(LinkedList<ChunkImpl>().apply { add(initChunk) })
} else {
// assert that initial chunk is present
with (view.chunks.first()) {
assert(this is MatchChunk && match is InitRuleMatch)
}
hist = IteratorMutableList(LinkedList(view.chunks as List<Chunk>))
hist = IteratorMutableList(LinkedList(view.chunks as List<ChunkImpl>))
evidenceSeed = view.evidenceSeed
}
}
@ -61,9 +79,9 @@ internal open class MatchJournalImpl(
// pointer to current position in history where logging (chunk additions) and log erasing (chunk removals) happens
private var posPtr: MutableListIterator<Chunk> = hist.listIterator()
private var posPtr: MutableListIterator<ChunkImpl> = hist.listIterator()
// invariant: always contains valid chunk
private var current: Chunk = posPtr.next() // take the initial chunk, move posPtr
private var current: ChunkImpl = posPtr.next() // take the initial chunk, move posPtr
override fun iterator(): MutableIterator<Chunk> = hist.iterator()
@ -73,7 +91,7 @@ internal open class MatchJournalImpl(
var added: MatchChunk? = null
if (ispec.isPrincipal(match.rule())) {
added = MatchChunk(nextEvidence(), match)
added = MatchChunkImpl(nextEvidence(), match)
current = added
posPtr.add(current)
}
@ -89,7 +107,7 @@ internal open class MatchJournalImpl(
var added: OccChunk? = null
if (ispec.isPrincipal(occ.constraint)) {
added = OccChunk(occ)
added = OccChunkImpl(occ)
current = added
posPtr.add(current)
}
@ -128,7 +146,7 @@ internal open class MatchJournalImpl(
posPtr = hist.listIterator(hist.size)
while (posPtr.hasPrevious()) {
current = posPtr.previous()
resetOccurrences(current.entries)
resetOccurrences(current.entries())
}
}
@ -242,7 +260,7 @@ internal open class MatchJournalImpl(
val set = HashSet<Id<Occurrence>>()
for (chunk in hist) { // initial chunk is counted too
chunk.entriesLog().forEach {
chunk.entries().forEach {
val idOcc = Id(it.occ)
if (it.discarded) set.remove(idOcc) else set.add(idOcc)
}

View File

@ -80,7 +80,7 @@ class TestIncrementalProgram {
(this.journalView as MatchJournal.View).chunks
private fun EvaluationResult.chunksSymbolView() = this.token().chunks().map {
it.entriesLog().map { entry -> !entry.discarded to entry.occ.constraint().symbol() }
it.entries().map { entry -> !entry.discarded to entry.occ.constraint().symbol() }
}
private fun EvaluationResult.lastChunk() = this.token().chunks().last() as MatchJournal.Chunk