Skip to content

Commit e2b971c

Browse files
committed
Optimizes ViewEnvironment and ViewRegistry operators
Take care to use the existing instances when combining with empty ones, and add tests to preserve that optimization.
1 parent 55fcc3b commit e2b971c

File tree

5 files changed

+87
-19
lines changed

5 files changed

+87
-19
lines changed

workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/ViewEnvironment.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ constructor(
2727
ViewEnvironment(map + pair)
2828

2929
@Suppress("DEPRECATION")
30-
public operator fun plus(other: ViewEnvironment): ViewEnvironment =
31-
ViewEnvironment(map + other.map)
30+
public operator fun plus(other: ViewEnvironment): ViewEnvironment {
31+
if (other.map.isEmpty()) return this
32+
if (this.map.isEmpty()) return other
33+
return ViewEnvironment(map + other.map)
34+
}
3235

3336
override fun toString(): String = "ViewEnvironment($map)"
3437

workflow-ui/core-common/src/main/java/com/squareup/workflow1/ui/ViewRegistry.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,19 @@ public operator fun ViewRegistry.plus(entry: Entry<*>): ViewRegistry =
113113

114114
/** @throws IllegalArgumentException if other has redundant entries. */
115115
@WorkflowUiExperimentalApi
116-
public operator fun ViewRegistry.plus(other: ViewRegistry): ViewRegistry =
117-
CompositeViewRegistry(this, other)
116+
public operator fun ViewRegistry.plus(other: ViewRegistry): ViewRegistry {
117+
if (other.keys.isEmpty()) return this
118+
if (this.keys.isEmpty()) return other
119+
return CompositeViewRegistry(this, other)
120+
}
118121

119122
/**
120123
* Replaces the existing [ViewRegistry] of the receiver with [registry]. Use
121124
* [ViewEnvironment.merge] to combine them instead.
122125
*/
123126
@WorkflowUiExperimentalApi
124127
public operator fun ViewEnvironment.plus(registry: ViewRegistry): ViewEnvironment {
128+
if (registry.keys.isEmpty()) return this
125129
return this + (ViewRegistry to registry)
126130
}
127131

@@ -147,6 +151,8 @@ public infix fun ViewRegistry.merge(other: ViewRegistry): ViewRegistry {
147151
*/
148152
@WorkflowUiExperimentalApi
149153
public infix fun ViewEnvironment.merge(registry: ViewRegistry): ViewEnvironment {
154+
if (registry.keys.isEmpty()) return this
155+
150156
val merged = this[ViewRegistry] merge registry
151157
return this + merged
152158
}
@@ -159,6 +165,7 @@ public infix fun ViewEnvironment.merge(registry: ViewRegistry): ViewEnvironment
159165
@WorkflowUiExperimentalApi
160166
public infix fun ViewEnvironment.merge(other: ViewEnvironment): ViewEnvironment {
161167
if (other.map.isEmpty()) return this
168+
if (this.map.isEmpty()) return other
162169

163170
val oldReg = this[ViewRegistry]
164171
val newReg = other[ViewRegistry]

workflow-ui/core-common/src/test/java/com/squareup/workflow1/ui/ViewEnvironmentTest.kt

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.squareup.workflow1.ui
22

33
import com.google.common.truth.Truth.assertThat
4+
import com.squareup.workflow1.ui.ViewEnvironment.Companion.EMPTY
45
import org.junit.Test
56

67
@OptIn(WorkflowUiExperimentalApi::class)
@@ -23,11 +24,11 @@ internal class ViewEnvironmentTest {
2324
}
2425

2526
@Test fun defaults() {
26-
assertThat(ViewEnvironment.EMPTY[DataHint]).isEqualTo(DataHint())
27+
assertThat(EMPTY[DataHint]).isEqualTo(DataHint())
2728
}
2829

2930
@Test fun put() {
30-
val environment = ViewEnvironment.EMPTY +
31+
val environment = EMPTY +
3132
(StringHint to "fnord") +
3233
(DataHint to DataHint(42, "foo"))
3334

@@ -36,23 +37,23 @@ internal class ViewEnvironmentTest {
3637
}
3738

3839
@Test fun `map equality`() {
39-
val env1 = ViewEnvironment.EMPTY +
40+
val env1 = EMPTY +
4041
(StringHint to "fnord") +
4142
(DataHint to DataHint(42, "foo"))
4243

43-
val env2 = ViewEnvironment.EMPTY +
44+
val env2 = EMPTY +
4445
(StringHint to "fnord") +
4546
(DataHint to DataHint(42, "foo"))
4647

4748
assertThat(env1).isEqualTo(env2)
4849
}
4950

5051
@Test fun `map inequality`() {
51-
val env1 = ViewEnvironment.EMPTY +
52+
val env1 = EMPTY +
5253
(StringHint to "fnord") +
5354
(DataHint to DataHint(42, "foo"))
5455

55-
val env2 = ViewEnvironment.EMPTY +
56+
val env2 = EMPTY +
5657
(StringHint to "fnord") +
5758
(DataHint to DataHint(43, "foo"))
5859

@@ -68,19 +69,29 @@ internal class ViewEnvironmentTest {
6869
}
6970

7071
@Test fun override() {
71-
val environment = ViewEnvironment.EMPTY +
72+
val environment = EMPTY +
7273
(StringHint to "able") +
7374
(StringHint to "baker")
7475

7576
assertThat(environment[StringHint]).isEqualTo("baker")
7677
}
7778

7879
@Test fun `keys of the same type`() {
79-
val environment = ViewEnvironment.EMPTY +
80+
val environment = EMPTY +
8081
(StringHint to "able") +
8182
(OtherStringHint to "baker")
8283

8384
assertThat(environment[StringHint]).isEqualTo("able")
8485
assertThat(environment[OtherStringHint]).isEqualTo("baker")
8586
}
87+
88+
@Test fun `preserve this when merging empty`() {
89+
val environment = EMPTY + (StringHint to "able")
90+
assertThat(environment + EMPTY).isSameInstanceAs(environment)
91+
}
92+
93+
@Test fun `preserve other when merging to empty`() {
94+
val environment = EMPTY + (StringHint to "able")
95+
assertThat(EMPTY + environment).isSameInstanceAs(environment)
96+
}
8697
}

workflow-ui/core-common/src/test/java/com/squareup/workflow1/ui/TypedViewRegistryTest.kt renamed to workflow-ui/core-common/src/test/java/com/squareup/workflow1/ui/ViewRegistryTest.kt

+45-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package com.squareup.workflow1.ui
22

33
import com.google.common.truth.Truth.assertThat
4+
import com.squareup.workflow1.ui.ViewEnvironment.Companion.EMPTY
45
import com.squareup.workflow1.ui.ViewRegistry.Entry
56
import org.junit.Test
67
import kotlin.reflect.KClass
78
import kotlin.test.assertFailsWith
89
import kotlin.test.assertTrue
910

1011
@OptIn(WorkflowUiExperimentalApi::class)
11-
internal class TypedViewRegistryTest {
12+
internal class ViewRegistryTest {
1213

1314
@Test fun `keys from bindings`() {
1415
val factory1 = TestEntry(FooRendering::class)
@@ -62,21 +63,61 @@ internal class TypedViewRegistryTest {
6263
@Test fun `merge into ViewEnvironment prefers right side`() {
6364
val factory1 = TestEntry(FooRendering::class)
6465
val factory2 = TestEntry(FooRendering::class)
65-
val merged = (ViewEnvironment.EMPTY + ViewRegistry(factory1)) merge ViewRegistry(factory2)
66+
val merged = (EMPTY + ViewRegistry(factory1)) merge ViewRegistry(factory2)
6667

6768
assertThat(merged[ViewRegistry][FooRendering::class]).isSameInstanceAs(factory2)
6869
}
6970

7071
@Test fun `merge of ViewEnvironments prefers right side`() {
7172
val factory1 = TestEntry(FooRendering::class)
7273
val factory2 = TestEntry(FooRendering::class)
73-
val e1 = ViewEnvironment.EMPTY + ViewRegistry(factory1)
74-
val e2 = ViewEnvironment.EMPTY + ViewRegistry(factory2)
74+
val e1 = EMPTY + ViewRegistry(factory1)
75+
val e2 = EMPTY + ViewRegistry(factory2)
7576
val merged = e1 + e2
7677

7778
assertThat(merged[ViewRegistry][FooRendering::class]).isSameInstanceAs(factory2)
7879
}
7980

81+
@Test fun `plus of empty returns this`() {
82+
val reg = ViewRegistry(TestEntry(FooRendering::class))
83+
assertThat(reg + ViewRegistry()).isSameInstanceAs(reg)
84+
}
85+
86+
@Test fun `plus to empty returns other`() {
87+
val reg = ViewRegistry(TestEntry(FooRendering::class))
88+
assertThat(ViewRegistry() + reg).isSameInstanceAs(reg)
89+
}
90+
91+
@Test fun `merge of empty reg returns this`() {
92+
val reg = ViewRegistry(TestEntry(FooRendering::class))
93+
assertThat(reg merge ViewRegistry()).isSameInstanceAs(reg)
94+
}
95+
96+
@Test fun `merge to empty reg returns other`() {
97+
val reg = ViewRegistry(TestEntry(FooRendering::class))
98+
assertThat(ViewRegistry() merge reg).isSameInstanceAs(reg)
99+
}
100+
101+
@Test fun `env merge of empty reg returns this env`() {
102+
val env = EMPTY + ViewRegistry(TestEntry(FooRendering::class))
103+
assertThat(env merge ViewRegistry()).isSameInstanceAs(env)
104+
}
105+
106+
@Test fun `env merge of empty env returns other env`() {
107+
val env = EMPTY + ViewRegistry(TestEntry(FooRendering::class))
108+
assertThat(env merge EMPTY).isSameInstanceAs(env)
109+
}
110+
111+
@Test fun `env merge to empty env returns other env`() {
112+
val env = EMPTY + ViewRegistry(TestEntry(FooRendering::class))
113+
assertThat(EMPTY merge env).isSameInstanceAs(env)
114+
}
115+
116+
@Test fun `env plus empty reg returns env`() {
117+
val env = EMPTY + ViewRegistry(TestEntry(FooRendering::class))
118+
assertThat(env + ViewRegistry()).isSameInstanceAs(env)
119+
}
120+
80121
private class TestEntry<T : Any>(
81122
override val type: KClass<in T>
82123
) : Entry<T>

workflow-ui/core-common/src/test/java/com/squareup/workflow1/ui/container/EnvironmentScreenTest.kt

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.squareup.workflow1.ui.container
33
import com.google.common.truth.Truth.assertThat
44
import com.squareup.workflow1.ui.Screen
55
import com.squareup.workflow1.ui.ViewEnvironment
6+
import com.squareup.workflow1.ui.ViewEnvironment.Companion.EMPTY
67
import com.squareup.workflow1.ui.ViewEnvironmentKey
78
import com.squareup.workflow1.ui.ViewRegistry
89
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
@@ -46,7 +47,7 @@ internal class EnvironmentScreenTest {
4647
val fooFactory = TestFactory(FooScreen::class)
4748
val viewRegistry = ViewRegistry(fooFactory)
4849
val envScreen = FooScreen.withEnvironment(
49-
ViewEnvironment.EMPTY + viewRegistry + TestValue("foo")
50+
EMPTY + viewRegistry + TestValue("foo")
5051
)
5152

5253
assertThat(envScreen.viewEnvironment[ViewRegistry][FooScreen::class])
@@ -78,11 +79,11 @@ internal class EnvironmentScreenTest {
7879
val barFactory = TestFactory(BarScreen::class)
7980

8081
val left = FooScreen.withEnvironment(
81-
ViewEnvironment.EMPTY + ViewRegistry(fooFactory1, barFactory) + TestValue("left")
82+
EMPTY + ViewRegistry(fooFactory1, barFactory) + TestValue("left")
8283
)
8384

8485
val union = left.withEnvironment(
85-
ViewEnvironment.EMPTY + ViewRegistry(fooFactory2) + TestValue("right")
86+
EMPTY + ViewRegistry(fooFactory2) + TestValue("right")
8687
)
8788

8889
assertThat(union.viewEnvironment[ViewRegistry][FooScreen::class])
@@ -92,4 +93,9 @@ internal class EnvironmentScreenTest {
9293
assertThat(union.viewEnvironment[TestValue])
9394
.isEqualTo(TestValue("right"))
9495
}
96+
97+
@Test fun `keep existing instance on vacuous merge`() {
98+
val left = FooScreen.withEnvironment(EMPTY + TestValue("whatever"))
99+
assertThat(left.withEnvironment()).isSameInstanceAs(left)
100+
}
95101
}

0 commit comments

Comments
 (0)