Logical with assigned value has higher rank. Notifications are to be dispatched accordingly.

This commit is contained in:
Fedor Isakov 2019-01-25 13:52:10 +01:00
parent e645ac8a70
commit 5771d78b24
3 changed files with 125 additions and 3 deletions

View File

@ -119,16 +119,24 @@ class LogicalImpl<T> : JoinableLogical<T> {
val otherRepr = (other as LogicalImpl<T>).find()
if (thisRepr === otherRepr) {
throw IllegalStateException("cannnot unite logical with itself")
// nothing to do
return
}
// invariant: thisRepr.rank > otherRepr.rank
if (thisRepr.rank() < otherRepr.rank()) {
otherRepr.union(thisRepr, reconciler);
return;
return
} else if (thisRepr.rank() == otherRepr.rank()) {
thisRepr.incRank();
if (thisRepr._value == null && otherRepr._value != null) {
otherRepr.union(thisRepr, reconciler);
return
} else {
thisRepr.incRank();
}
}
val thisVal = thisRepr.value();

View File

@ -22,3 +22,7 @@ import org.junit.Assert
infix fun <A, B> A.shouldBe(that: B) = Assert.assertEquals(that, this)
infix fun <A, B> A.shouldBeSame(that: B) = Assert.assertSame(that, this)
infix fun <A, B> A.shouldNotBeSame(that: B) = Assert.assertNotSame(that, this)

View File

@ -0,0 +1,110 @@
import jetbrains.mps.logic.reactor.core.LogicalImpl
import jetbrains.mps.logic.reactor.core.LogicalObserver
import jetbrains.mps.logic.reactor.core.addObserver
import jetbrains.mps.logic.reactor.logical.JoinableLogical
import jetbrains.mps.logic.reactor.logical.Logical
import org.junit.Test
import kotlin.math.log
/*
* Copyright 2014-2019 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Fedor Isakov
*/
class TestLogical {
inline fun <reified T> logical(name: String): JoinableLogical<T> = LogicalImpl<T>(name)
class Observer(logical: Logical<*>): LogicalObserver {
var parentUpdated: Pair<Logical<*>, Logical<*>>? = null
var valueUpdated: Pair<Logical<*>, Any>? = null
init {
logical.addObserver(this)
}
override fun valueUpdated(logical: Logical<*>) {
if (valueUpdated != null)
throw IllegalStateException("value already assigned")
else
valueUpdated = logical to logical.findRoot().value()
}
override fun parentUpdated(logical: Logical<*>) {
parentUpdated = logical to logical.findRoot()
}
}
@Test
fun union_notifies_observers () {
val xLogical = logical<String>("X")
val yLogical = logical<String>("Y")
val zLogical = logical<String>("Z")
val observerX = Observer(xLogical)
val observerY = Observer(yLogical)
val observerZ = Observer(zLogical)
// the logical on the left has higher rank
yLogical.union(xLogical)
observerX.parentUpdated shouldBe (xLogical to yLogical)
observerY.parentUpdated shouldBe (null)
// now logical on the right has higher rank
zLogical.union(xLogical)
observerZ.parentUpdated shouldBe (zLogical to yLogical)
observerY.parentUpdated shouldBe (null)
// should not fail
yLogical.union(zLogical)
}
@Test
fun assigned_logical_has_higher_rank() {
val xLogical = logical<String>("X")
val yLogical = logical<String>("Y")
val observerX = Observer(xLogical)
val observerY = Observer(yLogical)
xLogical.union(yLogical)
observerY.parentUpdated shouldBe (yLogical to xLogical)
observerX.parentUpdated shouldBe (null)
yLogical.findRoot() shouldBeSame xLogical
yLogical.findRoot().setValue("foobar")
observerX.valueUpdated shouldBe (xLogical to "foobar")
observerY.valueUpdated shouldBe (yLogical to "foobar")
val zLogical = logical<String>("Z")
val wLogical = logical<String>("W")
val observerZ = Observer(zLogical)
val observerW = Observer(wLogical)
zLogical.union(wLogical)
observerW.parentUpdated shouldBe (wLogical to zLogical)
observerZ.parentUpdated shouldBe (null)
zLogical.union(yLogical)
zLogical.findRoot() shouldBeSame xLogical
observerZ.parentUpdated shouldBe (zLogical to xLogical)
observerW.parentUpdated shouldBe (wLogical to xLogical)
observerZ.valueUpdated shouldBe (zLogical to "foobar")
observerW.valueUpdated shouldBe (wLogical to "foobar")
}
}