Replace tag() method in rule with uniqueTag() returning Object. This

allows for further memory optimization.
This commit is contained in:
Fedor Isakov 2019-05-17 14:58:01 +02:00
parent 0697437ec7
commit 0e02bab768
10 changed files with 47 additions and 48 deletions

View File

@ -27,12 +27,12 @@ import com.github.andrewoma.dexx.collection.Map as PersMap
*/
class Dispatcher (val ruleIndex: RuleIndex) {
private val ruletag2matcher = HashMap<String, RuleMatcher>()
private val ruletag2matcher = HashMap<Any, RuleMatcher>()
init {
ruleIndex.forEach { rule ->
val matcher = createRuleMatcher(ruleIndex, rule.tag())
ruletag2matcher.put(rule.tag(), matcher);
val matcher = createRuleMatcher(ruleIndex, rule.uniqueTag())
ruletag2matcher.put(rule.uniqueTag(), matcher);
}
}
@ -43,7 +43,7 @@ class Dispatcher (val ruleIndex: RuleIndex) {
inner class DispatchingFront {
private var ruletag2probe: PersMap<String, RuleMatchingProbe>
private var ruletag2probe: PersMap<Any, RuleMatchingProbe>
private val allMatches = arrayListOf<RuleMatchImpl>()
@ -57,15 +57,15 @@ class Dispatcher (val ruleIndex: RuleIndex) {
private constructor(pred: DispatchingFront, matching: Iterable<RuleMatchingProbe>) {
this.ruletag2probe = pred.ruletag2probe
matching.forEach { probe ->
this.ruletag2probe = ruletag2probe.put(probe.rule().tag(), probe)
this.ruletag2probe = ruletag2probe.put(probe.rule().uniqueTag(), probe)
allMatches.addAll(probe.matches() as Collection<RuleMatchImpl>)
}
}
private constructor(pred: DispatchingFront, consumedMatch: RuleMatchEx) {
this.ruletag2probe = pred.ruletag2probe
pred.ruletag2probe[consumedMatch.rule().tag()]?.let {
this.ruletag2probe = ruletag2probe.put(consumedMatch.rule().tag(), it.consume(consumedMatch))
pred.ruletag2probe[consumedMatch.rule().uniqueTag()]?.let {
this.ruletag2probe = ruletag2probe.put(consumedMatch.rule().uniqueTag(), it.consume(consumedMatch))
}
}
@ -80,8 +80,8 @@ class Dispatcher (val ruleIndex: RuleIndex) {
*/
fun expand(activated: Occurrence) = DispatchingFront(this,
ruleIndex.forOccurrenceWithMask(activated).mapNotNull { (rule, mask) ->
ruletag2probe[rule.tag()]?.expand(activated, mask)
ruletag2probe[rule.tag()]?.expand(activated, mask)
ruletag2probe[rule.uniqueTag()]?.expand(activated, mask)
ruletag2probe[rule.uniqueTag()]?.expand(activated, mask)
})
/**
@ -90,7 +90,7 @@ class Dispatcher (val ruleIndex: RuleIndex) {
*/
fun contract(discarded: Occurrence) = DispatchingFront(this,
ruleIndex.forOccurrence(discarded).mapNotNull { rule ->
ruletag2probe[rule.tag()]
ruletag2probe[rule.uniqueTag()]
}.map { probe ->
probe.contract(discarded)
})

View File

@ -29,14 +29,13 @@ import kotlin.collections.HashMap
/**
* A container for [Rule] instances with the ability to look up by [ConstraintOccurrence].
*
* FIXME handler to be renamed to RulesList
* @author Fedor Isakov
*/
class RuleIndex(handlers: Iterable<RulesList>) : Iterable<Rule>, RuleLookup {
private val symbol2index = HashMap<ConstraintSymbol, ArgumentRuleIndex>()
private val tag2rule = LinkedHashMap<String, Rule>()
private val tag2rule = LinkedHashMap<Any, Rule>()
// rule's index is rule's position in this list
private val rulesList = ArrayList<Rule>()
@ -55,7 +54,7 @@ class RuleIndex(handlers: Iterable<RulesList>) : Iterable<Rule>, RuleLookup {
buildIndex(handlers)
}
override fun lookupRuleByTag(tag: String): Rule? = tag2rule[tag]
override fun lookupRuleByTag(tag: Any): Rule? = tag2rule[tag]
/**
* Returns instances of [Rule] that can potentially match the specified [ConstraintOccurrence].
@ -88,8 +87,8 @@ class RuleIndex(handlers: Iterable<RulesList>) : Iterable<Rule>, RuleLookup {
var ruleBit = 0
for (h in handlers) {
for (rule in h.rules()) {
if (tag2rule.containsKey(rule.tag())) throw IllegalStateException("duplicate rule tag ${rule.tag()}")
tag2rule[rule.tag()] = rule
if (tag2rule.containsKey(rule.uniqueTag())) throw IllegalStateException("duplicate rule tag ${rule.uniqueTag()}")
tag2rule[rule.uniqueTag()] = rule
rulesList.add(rule)
val head = rule.headKept() + rule.headReplaced()

View File

@ -26,6 +26,6 @@ import jetbrains.mps.logic.reactor.program.Rule
interface RuleLookup {
fun lookupRuleByTag(tag: String): Rule?
fun lookupRuleByTag(tag: Any): Rule?
}

View File

@ -30,5 +30,5 @@ interface RuleMatcher {
}
fun createRuleMatcher(lookup: RuleLookup, tag: String): RuleMatcher = RuleMatcherImpl(lookup, tag)
fun createRuleMatcher(lookup: RuleLookup, tag: Any): RuleMatcher = RuleMatcherImpl(lookup, tag)

View File

@ -33,7 +33,7 @@ import com.github.andrewoma.dexx.collection.Vector as PersVector
* @author Fedor Isakov
*/
internal class RuleMatcherImpl(private val ruleLookup: RuleLookup,
private val tag: String) : RuleMatcher
private val tag: Any) : RuleMatcher
{
val head = lookupRule().run { ArrayList(headKept() + headReplaced()) }

View File

@ -29,7 +29,7 @@ public abstract class Rule {
/**
* A tag uniquely identifies the rule.
*/
public abstract String tag();
public abstract Object uniqueTag();
/**
* An origin serves as justification for all constraints affected by this rule.

View File

@ -26,7 +26,7 @@ class ProgramBuilder(val registry: MockConstraintRegistry) {
class HandlerBuilder(val name: String) {
val rules = LinkedHashMap<String, Rule>()
val rules = LinkedHashMap<Any, Rule>()
constructor(name: String, rulesList: RulesList) : this(name) {
for (r in rulesList.rules()) {
@ -35,7 +35,7 @@ class HandlerBuilder(val name: String) {
}
fun appendRule(rule: Rule) {
rules[rule.tag()] = rule
rules[rule.uniqueTag()] = rule
}
fun toHandler(): RulesList = MockHandler(name, rules.values.toList())
@ -80,8 +80,8 @@ class MockRule(
val body: Collection<Collection<AndItem>>) : Rule() {
override fun kind(): Kind = TODO()
override fun tag(): String = tag
override fun uniqueTag() = tag
override fun headKept(): Iterable<Constraint> = kept

View File

@ -15,22 +15,22 @@ import kotlin.collections.HashMap
class Builder(var rulesLists: List<RulesList>) : RuleLookup {
val tag2rule = HashMap<String, Rule>()
val tag2rule = HashMap<Any, Rule>()
val programBuilder = ProgramBuilder(MockConstraintRegistry())
init {
rulesLists
.flatMap { it.rules() }
.forEach { r -> tag2rule[r.tag()] = r }
.forEach { r -> tag2rule[r.uniqueTag()] = r }
}
val rules: List<Rule>
get() = tag2rule.values.toList()
override fun lookupRuleByTag(tag: String): Rule? = tag2rule[tag]
override fun lookupRuleByTag(tag: Any): Rule? = tag2rule[tag]
fun ruleMatcher(): RuleMatcher = createRuleMatcher(this, rules.first().tag())
fun ruleMatcher(): RuleMatcher = createRuleMatcher(this, rules.first().uniqueTag())
fun program(name: String): Program = programBuilder.program(name, rulesLists)

View File

@ -509,8 +509,8 @@ class TestController {
constraint("foo", Z, "a{c}")), body(constraint("done")))
).controller().evaluate(occurrence("main")).run {
assertEquals(setOf(ConstraintSymbol("done", 0)), constraintSymbols())
assertEquals(1, occurrences(ConstraintSymbol.symbol("done", 0)).count())
constraintSymbols() shouldBe setOf(sym0("done"))
occurrences(sym0("done")).count() shouldBe 1
}
}
@ -820,10 +820,10 @@ class TestController {
@Test(expected = EvaluationFailureException::class)
fun failureHandler() {
val failures = ArrayList<Pair<EvaluationFailure, String>>()
val failures = ArrayList<Pair<EvaluationFailure, Any>>()
val failureHandler = { rule: Rule, feedback: EvaluationFeedback ->
if (feedback is EvaluationFailure) {
failures.add(feedback to rule.tag())
failures.add(feedback to rule.uniqueTag())
}
false
}
@ -862,11 +862,11 @@ class TestController {
@Test
fun failureHandlerRecover() {
val failures = ArrayList<Pair<EvaluationFailure, String>>()
val failures = ArrayList<Pair<EvaluationFailure, Any>>()
val failureHandler = { rule: Rule, feedback: EvaluationFeedback ->
if (feedback is EvaluationFailure) {
failures.add(feedback to rule.tag())
(rule.tag()?.startsWith("recoverable") == true)
failures.add(feedback to rule.uniqueTag())
(rule.uniqueTag().toString().startsWith("recoverable"))
} else false
}
@ -916,9 +916,9 @@ class TestController {
@Test
fun detailsFeedbackHandler() {
val feedbacks = arrayListOf<Pair<EvaluationFeedback, String>>()
val feedbacks = arrayListOf<Pair<EvaluationFeedback, Any>>()
val feedbackHandler = { rule: Rule, feedback: EvaluationFeedback ->
feedbacks.add(feedback to rule.tag())
feedbacks.add(feedback to rule.uniqueTag())
feedback.message.startsWith("catchme")
}

View File

@ -522,7 +522,7 @@ class TestRuleMatcher {
matches().size shouldBe 1
with(matches().first()) {
rule().tag() shouldBe "rule1"
rule().uniqueTag().toString() shouldBe "rule1"
with(logicalContext()) {
variable(X).findRoot().value() shouldBe parseTerm("h")
@ -555,7 +555,7 @@ class TestRuleMatcher {
with(matches().first()) {
rule().tag() shouldBe "main"
rule().uniqueTag().toString() shouldBe "main"
matchHeadKept().count() shouldBe 0
matchHeadReplaced().count() shouldBe 2
@ -597,7 +597,7 @@ class TestRuleMatcher {
with(matches().first()) {
rule().tag() shouldBe "rule1"
rule().uniqueTag().toString() shouldBe "rule1"
}
}.run {
@ -606,7 +606,7 @@ class TestRuleMatcher {
with(matches().first()) {
rule().tag() shouldBe "rule2"
rule().uniqueTag().toString() shouldBe "rule2"
logicalContext().variable(X).value() shouldBe "a"
}
@ -616,7 +616,7 @@ class TestRuleMatcher {
with(matches().drop(1).first()) {
rule().tag() shouldBe "rule2"
rule().uniqueTag().toString() shouldBe "rule2"
logicalContext().variable(X).value() shouldBe "b"
}
@ -670,7 +670,7 @@ class TestRuleMatcher {
expand(occurrence("foo")) }.apply {
matches().count() shouldBe 3 }.run {
matches().map { it.rule().tag() }.toList() shouldBe listOf("rule1", "rule2", "rule3")
matches().map { it.rule().uniqueTag().toString() }.toList() shouldBe listOf("rule1", "rule2", "rule3")
}
}
}
@ -713,15 +713,15 @@ class TestRuleMatcher {
expand(occurrence("bar")) }.apply {
matches().count() shouldBe 1
matches().first().rule().tag() shouldBe "rule2" }.run {
matches().first().rule().uniqueTag().toString() shouldBe "rule2" }.run {
expand(occurrence("bazz")) }.apply {
matches().count() shouldBe 1
matches().first().rule().tag() shouldBe "rule1" }.run {
matches().first().rule().uniqueTag().toString() shouldBe "rule1" }.run {
expand(occurrence("blin")) }.apply {
matches().count() shouldBe 1
matches().first().rule().tag() shouldBe "rule3"
matches().first().rule().uniqueTag().toString() shouldBe "rule3"
}
}
}
@ -766,11 +766,11 @@ class TestRuleMatcher {
expand(bar) }.apply {
matches().count() shouldBe 1
matches().first().rule().tag() shouldBe "rule2" }.run {
matches().first().rule().uniqueTag().toString() shouldBe "rule2" }.run {
expand(occurrence("bazz")) }.apply {
matches().count() shouldBe 1
matches().first().rule().tag() shouldBe "rule1" }.run {
matches().first().rule().uniqueTag().toString() shouldBe "rule1" }.run {
contract(bar) }.apply {
matches().count() shouldBe 0 }.run {
@ -780,7 +780,7 @@ class TestRuleMatcher {
}.run {
expand(bar) }.apply {
matches().count() shouldBe 3
matches().map { it.rule().tag() }.toList() shouldBe listOf("rule1", "rule2", "rule3")
matches().map { it.rule().uniqueTag().toString() }.toList() shouldBe listOf("rule1", "rule2", "rule3")
}
}
}