Merge "Add CompositionData to replace SlotTable for tooling API usage" into androidx-master-dev
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
index 7e58ce0..c21c5e6 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
@@ -126,7 +126,6 @@
fun makeComposer(): Composer<*> {
val container = LinearLayout(__context!!)
return Composer(
- SlotTable(),
UiApplier(container),
Recomposer.current()
)
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
index 1d8e90e..b544ab1 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
@@ -23,7 +23,6 @@
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.Providers
import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.SlotTable
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.dispatch.MonotonicFrameClock
import androidx.compose.runtime.withRunningRecomposer
@@ -302,7 +301,6 @@
block: @Composable () -> Unit
): Composer<Unit> {
return Composer(
- SlotTable(),
EmptyApplier(),
recomposer
).apply {
@@ -312,7 +310,7 @@
fn(this, 0)
}
applyChanges()
- slotTable.verifyWellFormed()
+ verifyConsistent()
}
}
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 34986e5..ebe4b82 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -34,13 +34,6 @@
method public static <T> androidx.compose.runtime.ProvidableAmbient<T> staticAmbientOf(optional kotlin.jvm.functions.Function0<? extends T>? defaultFactory);
}
- @androidx.compose.runtime.InternalComposeApi public final class Anchor {
- method public boolean getValid();
- method public int toIndexFor(androidx.compose.runtime.SlotTable slots);
- method public int toIndexFor(androidx.compose.runtime.SlotWriter writer);
- property public final boolean valid;
- }
-
public interface Applier<N> {
method public void clear();
method public void down(N? node);
@@ -85,7 +78,7 @@
}
public final class Composer<N> {
- ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
+ ctor public Composer(@kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -105,10 +98,10 @@
method @androidx.compose.runtime.ComposeCompilerApi public void endReplaceableGroup();
method @androidx.compose.runtime.ComposeCompilerApi public androidx.compose.runtime.ScopeUpdateScope? endRestartGroup();
method @org.jetbrains.annotations.TestOnly public kotlin.coroutines.CoroutineContext getApplyCoroutineContext();
+ method public androidx.compose.runtime.CompositionData getCompositionData();
method public int getCurrentCompoundKeyHash();
method public boolean getDefaultsInvalid();
method public boolean getSkipping();
- method public androidx.compose.runtime.SlotTable getSlotTable();
method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
method @androidx.compose.runtime.InternalComposeApi public boolean recompose();
method @androidx.compose.runtime.InternalComposeApi public void recordModificationsOf(java.util.Set<?> values);
@@ -123,11 +116,12 @@
method @androidx.compose.runtime.ComposeCompilerApi public void startReplaceableGroup(int key, String? sourceInformation);
method @androidx.compose.runtime.ComposeCompilerApi public void startRestartGroup(int key);
method @androidx.compose.runtime.ComposeCompilerApi public void startRestartGroup(int key, String? sourceInformation);
+ method @androidx.compose.runtime.InternalComposeApi public void verifyConsistent();
property @org.jetbrains.annotations.TestOnly public final kotlin.coroutines.CoroutineContext applyCoroutineContext;
+ property public final androidx.compose.runtime.CompositionData compositionData;
property public final int currentCompoundKeyHash;
property public final boolean defaultsInvalid;
property public final boolean skipping;
- property public final androidx.compose.runtime.SlotTable slotTable;
}
public final class ComposerKt {
@@ -140,6 +134,24 @@
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
+ public interface CompositionData {
+ method public Iterable<androidx.compose.runtime.CompositionGroup> getCompositionGroups();
+ method public boolean isEmpty();
+ property public abstract Iterable<androidx.compose.runtime.CompositionGroup> compositionGroups;
+ property public abstract boolean isEmpty;
+ }
+
+ public interface CompositionGroup extends androidx.compose.runtime.CompositionData {
+ method public Iterable<java.lang.Object> getData();
+ method public Object getKey();
+ method public Object? getNode();
+ method public String? getSourceInfo();
+ property public abstract Iterable<java.lang.Object> data;
+ property public abstract Object key;
+ property public abstract Object? node;
+ property public abstract String? sourceInfo;
+ }
+
public final class CompositionKt {
method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
}
@@ -341,150 +353,10 @@
method public inline void update(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.Updater<T>,kotlin.Unit> block);
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotReader {
- ctor public SlotReader(androidx.compose.runtime.SlotTable table);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public void beginEmpty();
- method public void close();
- method public void endEmpty();
- method public void endGroup();
- method public java.util.List<androidx.compose.runtime.KeyInfo> extractKeys();
- method public Object? get(int index);
- method public int getCurrentEnd();
- method public int getCurrentGroup();
- method public Object! getGroupAux();
- method public int getGroupEnd();
- method public int getGroupKey();
- method public Object! getGroupNode();
- method public Object! getGroupObjectKey();
- method public int getGroupSize();
- method public int getGroupSlotCount();
- method public int getGroupSlotIndex();
- method public boolean getInEmpty();
- method public int getNodeCount();
- method public int getParent();
- method public int getParentNodes();
- method public int getSize();
- method public int getSlot();
- method public Object? groupAux(int index);
- method public int groupEnd(int index);
- method public Object? groupGet(int index);
- method public int groupKey(int index);
- method public int groupKey(androidx.compose.runtime.Anchor anchor);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public boolean hasObjectKey(int index);
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public boolean isNode(int index);
- method public Object? next();
- method public Object? node(int index);
- method public int nodeCount(int index);
- method public int parent(int index);
- method public int parentOf(int index);
- method public void reposition(int index);
- method public void restoreParent(int index);
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startGroup();
- method public void startNode();
- property public final int currentEnd;
- property public final int currentGroup;
- property public final Object! groupAux;
- property public final int groupEnd;
- property public final int groupKey;
- property public final Object! groupNode;
- property public final Object! groupObjectKey;
- property public final int groupSize;
- property public final int groupSlotCount;
- property public final int groupSlotIndex;
- property public final boolean inEmpty;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int nodeCount;
- property public final int parent;
- property public final int parentNodes;
- property public final int size;
- property public final int slot;
- }
-
- @androidx.compose.runtime.InternalComposeApi public final class SlotTable {
- ctor public SlotTable();
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public String asString();
- method public int[] getGroups();
- method public int getGroupsSize();
- method public Object![] getSlots();
- method public int getSlotsSize();
- method public boolean isEmpty();
- method public androidx.compose.runtime.SlotReader openReader();
- method public androidx.compose.runtime.SlotWriter openWriter();
- method public boolean ownsAnchor(androidx.compose.runtime.Anchor anchor);
- method public inline <T> T! read(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotReader,? extends T> block);
- method public void verifyWellFormed();
- method public inline <T> T! write(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotWriter,? extends T> block);
- property public final int[] groups;
- property public final int groupsSize;
- property public final boolean isEmpty;
- property public final Object![] slots;
- property public final int slotsSize;
- }
-
public final class SlotTableKt {
method public static java.util.List<java.lang.Integer> slice(int[], Iterable<java.lang.Integer> indices);
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotWriter {
- method public void advanceBy(int amount);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public void beginInsert();
- method public void close();
- method public int endGroup();
- method public void endInsert();
- method public void ensureStarted(int index);
- method public void ensureStarted(androidx.compose.runtime.Anchor anchor);
- method public boolean getClosed();
- method public int getCurrentGroup();
- method public int getParent();
- method public Object? groupAux(int index);
- method public int groupKey(int index);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public java.util.Iterator<java.lang.Object> groupSlots();
- method public String groupsAsString();
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public java.util.List<androidx.compose.runtime.Anchor> moveFrom(androidx.compose.runtime.SlotTable table, int index);
- method public void moveGroup(int offset);
- method public Object? node(int index);
- method public int parent(int index);
- method public int parent(androidx.compose.runtime.Anchor anchor);
- method public boolean removeGroup();
- method public void seek(androidx.compose.runtime.Anchor anchor);
- method public void set(Object? value);
- method public Object? set(int index, Object? value);
- method public Object? skip();
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startData(int key, Object? objectKey, Object? aux);
- method public void startData(int key, Object? aux);
- method public void startGroup();
- method public void startGroup(int key);
- method public void startGroup(int key, Object? dataKey);
- method public void startNode(Object? key);
- method public void startNode(Object? key, Object? node);
- method public Object? update(Object? value);
- method public void updateAux(Object? value);
- method public void updateNode(Object? value);
- method public void updateParentNode(Object? value);
- property public final boolean closed;
- property public final int currentGroup;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int parent;
- }
-
public interface SnapshotMutationPolicy<T> {
method public boolean equivalent(T? a, T? b);
method @androidx.compose.runtime.ExperimentalComposeApi public default T? merge(T? previous, T? current, T? applied);
@@ -879,7 +751,7 @@
package androidx.compose.runtime.tooling {
public final class InspectionTablesKt {
- method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.SlotTable>> getInspectionTables();
+ method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.CompositionData>> getInspectionTables();
}
}
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index 34986e5..ebe4b82 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -34,13 +34,6 @@
method public static <T> androidx.compose.runtime.ProvidableAmbient<T> staticAmbientOf(optional kotlin.jvm.functions.Function0<? extends T>? defaultFactory);
}
- @androidx.compose.runtime.InternalComposeApi public final class Anchor {
- method public boolean getValid();
- method public int toIndexFor(androidx.compose.runtime.SlotTable slots);
- method public int toIndexFor(androidx.compose.runtime.SlotWriter writer);
- property public final boolean valid;
- }
-
public interface Applier<N> {
method public void clear();
method public void down(N? node);
@@ -85,7 +78,7 @@
}
public final class Composer<N> {
- ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
+ ctor public Composer(@kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -105,10 +98,10 @@
method @androidx.compose.runtime.ComposeCompilerApi public void endReplaceableGroup();
method @androidx.compose.runtime.ComposeCompilerApi public androidx.compose.runtime.ScopeUpdateScope? endRestartGroup();
method @org.jetbrains.annotations.TestOnly public kotlin.coroutines.CoroutineContext getApplyCoroutineContext();
+ method public androidx.compose.runtime.CompositionData getCompositionData();
method public int getCurrentCompoundKeyHash();
method public boolean getDefaultsInvalid();
method public boolean getSkipping();
- method public androidx.compose.runtime.SlotTable getSlotTable();
method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
method @androidx.compose.runtime.InternalComposeApi public boolean recompose();
method @androidx.compose.runtime.InternalComposeApi public void recordModificationsOf(java.util.Set<?> values);
@@ -123,11 +116,12 @@
method @androidx.compose.runtime.ComposeCompilerApi public void startReplaceableGroup(int key, String? sourceInformation);
method @androidx.compose.runtime.ComposeCompilerApi public void startRestartGroup(int key);
method @androidx.compose.runtime.ComposeCompilerApi public void startRestartGroup(int key, String? sourceInformation);
+ method @androidx.compose.runtime.InternalComposeApi public void verifyConsistent();
property @org.jetbrains.annotations.TestOnly public final kotlin.coroutines.CoroutineContext applyCoroutineContext;
+ property public final androidx.compose.runtime.CompositionData compositionData;
property public final int currentCompoundKeyHash;
property public final boolean defaultsInvalid;
property public final boolean skipping;
- property public final androidx.compose.runtime.SlotTable slotTable;
}
public final class ComposerKt {
@@ -140,6 +134,24 @@
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
+ public interface CompositionData {
+ method public Iterable<androidx.compose.runtime.CompositionGroup> getCompositionGroups();
+ method public boolean isEmpty();
+ property public abstract Iterable<androidx.compose.runtime.CompositionGroup> compositionGroups;
+ property public abstract boolean isEmpty;
+ }
+
+ public interface CompositionGroup extends androidx.compose.runtime.CompositionData {
+ method public Iterable<java.lang.Object> getData();
+ method public Object getKey();
+ method public Object? getNode();
+ method public String? getSourceInfo();
+ property public abstract Iterable<java.lang.Object> data;
+ property public abstract Object key;
+ property public abstract Object? node;
+ property public abstract String? sourceInfo;
+ }
+
public final class CompositionKt {
method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
}
@@ -341,150 +353,10 @@
method public inline void update(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.Updater<T>,kotlin.Unit> block);
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotReader {
- ctor public SlotReader(androidx.compose.runtime.SlotTable table);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public void beginEmpty();
- method public void close();
- method public void endEmpty();
- method public void endGroup();
- method public java.util.List<androidx.compose.runtime.KeyInfo> extractKeys();
- method public Object? get(int index);
- method public int getCurrentEnd();
- method public int getCurrentGroup();
- method public Object! getGroupAux();
- method public int getGroupEnd();
- method public int getGroupKey();
- method public Object! getGroupNode();
- method public Object! getGroupObjectKey();
- method public int getGroupSize();
- method public int getGroupSlotCount();
- method public int getGroupSlotIndex();
- method public boolean getInEmpty();
- method public int getNodeCount();
- method public int getParent();
- method public int getParentNodes();
- method public int getSize();
- method public int getSlot();
- method public Object? groupAux(int index);
- method public int groupEnd(int index);
- method public Object? groupGet(int index);
- method public int groupKey(int index);
- method public int groupKey(androidx.compose.runtime.Anchor anchor);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public boolean hasObjectKey(int index);
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public boolean isNode(int index);
- method public Object? next();
- method public Object? node(int index);
- method public int nodeCount(int index);
- method public int parent(int index);
- method public int parentOf(int index);
- method public void reposition(int index);
- method public void restoreParent(int index);
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startGroup();
- method public void startNode();
- property public final int currentEnd;
- property public final int currentGroup;
- property public final Object! groupAux;
- property public final int groupEnd;
- property public final int groupKey;
- property public final Object! groupNode;
- property public final Object! groupObjectKey;
- property public final int groupSize;
- property public final int groupSlotCount;
- property public final int groupSlotIndex;
- property public final boolean inEmpty;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int nodeCount;
- property public final int parent;
- property public final int parentNodes;
- property public final int size;
- property public final int slot;
- }
-
- @androidx.compose.runtime.InternalComposeApi public final class SlotTable {
- ctor public SlotTable();
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public String asString();
- method public int[] getGroups();
- method public int getGroupsSize();
- method public Object![] getSlots();
- method public int getSlotsSize();
- method public boolean isEmpty();
- method public androidx.compose.runtime.SlotReader openReader();
- method public androidx.compose.runtime.SlotWriter openWriter();
- method public boolean ownsAnchor(androidx.compose.runtime.Anchor anchor);
- method public inline <T> T! read(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotReader,? extends T> block);
- method public void verifyWellFormed();
- method public inline <T> T! write(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotWriter,? extends T> block);
- property public final int[] groups;
- property public final int groupsSize;
- property public final boolean isEmpty;
- property public final Object![] slots;
- property public final int slotsSize;
- }
-
public final class SlotTableKt {
method public static java.util.List<java.lang.Integer> slice(int[], Iterable<java.lang.Integer> indices);
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotWriter {
- method public void advanceBy(int amount);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public void beginInsert();
- method public void close();
- method public int endGroup();
- method public void endInsert();
- method public void ensureStarted(int index);
- method public void ensureStarted(androidx.compose.runtime.Anchor anchor);
- method public boolean getClosed();
- method public int getCurrentGroup();
- method public int getParent();
- method public Object? groupAux(int index);
- method public int groupKey(int index);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public java.util.Iterator<java.lang.Object> groupSlots();
- method public String groupsAsString();
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public java.util.List<androidx.compose.runtime.Anchor> moveFrom(androidx.compose.runtime.SlotTable table, int index);
- method public void moveGroup(int offset);
- method public Object? node(int index);
- method public int parent(int index);
- method public int parent(androidx.compose.runtime.Anchor anchor);
- method public boolean removeGroup();
- method public void seek(androidx.compose.runtime.Anchor anchor);
- method public void set(Object? value);
- method public Object? set(int index, Object? value);
- method public Object? skip();
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startData(int key, Object? objectKey, Object? aux);
- method public void startData(int key, Object? aux);
- method public void startGroup();
- method public void startGroup(int key);
- method public void startGroup(int key, Object? dataKey);
- method public void startNode(Object? key);
- method public void startNode(Object? key, Object? node);
- method public Object? update(Object? value);
- method public void updateAux(Object? value);
- method public void updateNode(Object? value);
- method public void updateParentNode(Object? value);
- property public final boolean closed;
- property public final int currentGroup;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int parent;
- }
-
public interface SnapshotMutationPolicy<T> {
method public boolean equivalent(T? a, T? b);
method @androidx.compose.runtime.ExperimentalComposeApi public default T? merge(T? previous, T? current, T? applied);
@@ -879,7 +751,7 @@
package androidx.compose.runtime.tooling {
public final class InspectionTablesKt {
- method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.SlotTable>> getInspectionTables();
+ method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.CompositionData>> getInspectionTables();
}
}
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index c0658ef..f0c99aa 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -34,13 +34,6 @@
method public static <T> androidx.compose.runtime.ProvidableAmbient<T> staticAmbientOf(optional kotlin.jvm.functions.Function0<? extends T>? defaultFactory);
}
- @androidx.compose.runtime.InternalComposeApi public final class Anchor {
- method public boolean getValid();
- method public int toIndexFor(androidx.compose.runtime.SlotTable slots);
- method public int toIndexFor(androidx.compose.runtime.SlotWriter writer);
- property public final boolean valid;
- }
-
public interface Applier<N> {
method public void clear();
method public void down(N? node);
@@ -85,7 +78,7 @@
}
public final class Composer<N> {
- ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
+ ctor public Composer(@kotlin.PublishedApi androidx.compose.runtime.Applier<N> applier, androidx.compose.runtime.CompositionReference parentReference);
method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -108,10 +101,10 @@
method @androidx.compose.runtime.ComposeCompilerApi public void endReplaceableGroup();
method @androidx.compose.runtime.ComposeCompilerApi public androidx.compose.runtime.ScopeUpdateScope? endRestartGroup();
method @org.jetbrains.annotations.TestOnly public kotlin.coroutines.CoroutineContext getApplyCoroutineContext();
+ method public androidx.compose.runtime.CompositionData getCompositionData();
method public int getCurrentCompoundKeyHash();
method public boolean getDefaultsInvalid();
method public boolean getSkipping();
- method public androidx.compose.runtime.SlotTable getSlotTable();
method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
method @kotlin.PublishedApi internal Object? nextSlot();
method @androidx.compose.runtime.InternalComposeApi public boolean recompose();
@@ -130,11 +123,12 @@
method @androidx.compose.runtime.ComposeCompilerApi public void startRestartGroup(int key, String? sourceInformation);
method @kotlin.PublishedApi internal void updateValue(Object? value);
method @kotlin.PublishedApi internal N! useNode();
+ method @androidx.compose.runtime.InternalComposeApi public void verifyConsistent();
property @org.jetbrains.annotations.TestOnly public final kotlin.coroutines.CoroutineContext applyCoroutineContext;
+ property public final androidx.compose.runtime.CompositionData compositionData;
property public final int currentCompoundKeyHash;
property public final boolean defaultsInvalid;
property public final boolean skipping;
- property public final androidx.compose.runtime.SlotTable slotTable;
field @kotlin.PublishedApi internal boolean inserting;
}
@@ -160,6 +154,24 @@
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
+ public interface CompositionData {
+ method public Iterable<androidx.compose.runtime.CompositionGroup> getCompositionGroups();
+ method public boolean isEmpty();
+ property public abstract Iterable<androidx.compose.runtime.CompositionGroup> compositionGroups;
+ property public abstract boolean isEmpty;
+ }
+
+ public interface CompositionGroup extends androidx.compose.runtime.CompositionData {
+ method public Iterable<java.lang.Object> getData();
+ method public Object getKey();
+ method public Object? getNode();
+ method public String? getSourceInfo();
+ property public abstract Iterable<java.lang.Object> data;
+ property public abstract Object key;
+ property public abstract Object? node;
+ property public abstract String? sourceInfo;
+ }
+
public final class CompositionKt {
method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
}
@@ -374,151 +386,11 @@
method public inline void update(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.Updater<T>,kotlin.Unit> block);
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotReader {
- ctor public SlotReader(androidx.compose.runtime.SlotTable table);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public void beginEmpty();
- method public void close();
- method public void endEmpty();
- method public void endGroup();
- method public java.util.List<androidx.compose.runtime.KeyInfo> extractKeys();
- method public Object? get(int index);
- method public int getCurrentEnd();
- method public int getCurrentGroup();
- method public Object! getGroupAux();
- method public int getGroupEnd();
- method public int getGroupKey();
- method public Object! getGroupNode();
- method public Object! getGroupObjectKey();
- method public int getGroupSize();
- method public int getGroupSlotCount();
- method public int getGroupSlotIndex();
- method public boolean getInEmpty();
- method public int getNodeCount();
- method public int getParent();
- method public int getParentNodes();
- method public int getSize();
- method public int getSlot();
- method public Object? groupAux(int index);
- method public int groupEnd(int index);
- method public Object? groupGet(int index);
- method public int groupKey(int index);
- method public int groupKey(androidx.compose.runtime.Anchor anchor);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public boolean hasObjectKey(int index);
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public boolean isNode(int index);
- method public Object? next();
- method public Object? node(int index);
- method public int nodeCount(int index);
- method public int parent(int index);
- method public int parentOf(int index);
- method public void reposition(int index);
- method public void restoreParent(int index);
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startGroup();
- method public void startNode();
- property public final int currentEnd;
- property public final int currentGroup;
- property public final Object! groupAux;
- property public final int groupEnd;
- property public final int groupKey;
- property public final Object! groupNode;
- property public final Object! groupObjectKey;
- property public final int groupSize;
- property public final int groupSlotCount;
- property public final int groupSlotIndex;
- property public final boolean inEmpty;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int nodeCount;
- property public final int parent;
- property public final int parentNodes;
- property public final int size;
- property public final int slot;
- }
-
- @androidx.compose.runtime.InternalComposeApi public final class SlotTable {
- ctor public SlotTable();
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public String asString();
- method public int[] getGroups();
- method public int getGroupsSize();
- method public Object![] getSlots();
- method public int getSlotsSize();
- method public boolean isEmpty();
- method public androidx.compose.runtime.SlotReader openReader();
- method public androidx.compose.runtime.SlotWriter openWriter();
- method public boolean ownsAnchor(androidx.compose.runtime.Anchor anchor);
- method public inline <T> T! read(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotReader,? extends T> block);
- method public void verifyWellFormed();
- method public inline <T> T! write(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.SlotWriter,? extends T> block);
- property public final int[] groups;
- property public final int groupsSize;
- property public final boolean isEmpty;
- property public final Object![] slots;
- property public final int slotsSize;
- }
-
public final class SlotTableKt {
method public static java.util.List<java.lang.Integer> slice(int[], Iterable<java.lang.Integer> indices);
field @kotlin.PublishedApi internal static final Object EMPTY;
}
- @androidx.compose.runtime.InternalComposeApi public final class SlotWriter {
- method public void advanceBy(int amount);
- method public androidx.compose.runtime.Anchor anchor(optional int index);
- method public int anchorIndex(androidx.compose.runtime.Anchor anchor);
- method public void beginInsert();
- method public void close();
- method public int endGroup();
- method public void endInsert();
- method public void ensureStarted(int index);
- method public void ensureStarted(androidx.compose.runtime.Anchor anchor);
- method public boolean getClosed();
- method public int getCurrentGroup();
- method public int getParent();
- method public Object? groupAux(int index);
- method public int groupKey(int index);
- method public Object? groupObjectKey(int index);
- method public int groupSize(int index);
- method public java.util.Iterator<java.lang.Object> groupSlots();
- method public String groupsAsString();
- method public boolean isGroupEnd();
- method public boolean isNode();
- method public java.util.List<androidx.compose.runtime.Anchor> moveFrom(androidx.compose.runtime.SlotTable table, int index);
- method public void moveGroup(int offset);
- method public Object? node(int index);
- method public int parent(int index);
- method public int parent(androidx.compose.runtime.Anchor anchor);
- method public boolean removeGroup();
- method public void seek(androidx.compose.runtime.Anchor anchor);
- method public void set(Object? value);
- method public Object? set(int index, Object? value);
- method public Object? skip();
- method public int skipGroup();
- method public void skipToGroupEnd();
- method public void startData(int key, Object? objectKey, Object? aux);
- method public void startData(int key, Object? aux);
- method public void startGroup();
- method public void startGroup(int key);
- method public void startGroup(int key, Object? dataKey);
- method public void startNode(Object? key);
- method public void startNode(Object? key, Object? node);
- method public Object? update(Object? value);
- method public void updateAux(Object? value);
- method public void updateNode(Object? value);
- method public void updateParentNode(Object? value);
- property public final boolean closed;
- property public final int currentGroup;
- property public final boolean isGroupEnd;
- property public final boolean isNode;
- property public final int parent;
- }
-
public interface SnapshotMutationPolicy<T> {
method public boolean equivalent(T? a, T? b);
method @androidx.compose.runtime.ExperimentalComposeApi public default T? merge(T? previous, T? current, T? applied);
@@ -927,7 +799,7 @@
package androidx.compose.runtime.tooling {
public final class InspectionTablesKt {
- method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.SlotTable>> getInspectionTables();
+ method public static androidx.compose.runtime.ProvidableAmbient<java.util.Set<androidx.compose.runtime.CompositionData>> getInspectionTables();
}
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index e39d965..f6d3736 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -351,11 +351,6 @@
*/
class Composer<N>(
/**
- * Backing storage for the composition
- */
- val slotTable: SlotTable,
-
- /**
* An adapter that applies changes to the tree using the Applier abstraction.
*/
@PublishedApi internal val applier: Applier<N>,
@@ -365,6 +360,7 @@
*/
private val parentReference: CompositionReference
) {
+ private val slotTable: SlotTable = SlotTable()
private val changes = mutableListOf<Change<N>>()
private val lifecycleObservers = HashMap<
CompositionLifecycleObserverHolder,
@@ -675,6 +671,31 @@
}
/**
+ * Throw a diagnostic exception if the internal tracking tables are inconsistent.
+ */
+ @InternalComposeApi
+ fun verifyConsistent() {
+ if (!isComposing) {
+ slotTable.verifyWellFormed()
+ insertTable.verifyWellFormed()
+ validateRecomposeScopeAnchors(slotTable)
+ }
+ }
+
+ private fun validateRecomposeScopeAnchors(slotTable: SlotTable) {
+ val scopes = slotTable.slots.map { it as? RecomposeScope }.filterNotNull()
+ for (scope in scopes) {
+ scope.anchor?.let { anchor ->
+ check(scope in slotTable.slotsOf(anchor.toIndexFor(slotTable))) {
+ val dataIndex = slotTable.slots.indexOf(scope)
+ "Misaligned anchor $anchor in scope $scope encountered, scope found at " +
+ "$dataIndex"
+ }
+ }
+ }
+ }
+
+ /**
* Record that the objects in [values] have been modified. This invalidates any recomposes
* scopes that were current when [recordReadOf] was called with an instance in [values].
*
@@ -1147,6 +1168,9 @@
}
}
+ @InternalComposeApi
+ val compositionData: CompositionData get() = slotTable
+
/**
* Schedule a side effect to run when we apply composition changes.
*/
@@ -2448,7 +2472,7 @@
override val collectingKeySources: Boolean,
override val collectingParameterInformation: Boolean
) : CompositionReference() {
- var inspectionTables: MutableSet<MutableSet<SlotTable>>? = null
+ var inspectionTables: MutableSet<MutableSet<CompositionData>>? = null
val composers = mutableSetOf<Composer<*>>()
fun dispose() {
@@ -2518,9 +2542,9 @@
return ambientScopeAt(scope.anchor?.toIndexFor(slotTable) ?: 0)
}
- override fun recordInspectionTable(table: MutableSet<SlotTable>) {
+ override fun recordInspectionTable(table: MutableSet<CompositionData>) {
(
- inspectionTables ?: HashSet<MutableSet<SlotTable>>().also {
+ inspectionTables ?: HashSet<MutableSet<CompositionData>>().also {
inspectionTables = it
}
).add(table)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
index 458e047..15b94e6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
@@ -73,7 +73,7 @@
): Composition = Compositions.findOrCreate(key) {
CompositionImpl(
parent,
- composerFactory = { slots, rcmpsr -> Composer(slots, applier, rcmpsr) },
+ composerFactory = { parent -> Composer(applier, parent) },
onDispose = { Compositions.onDisposed(key) }
).also {
onCreated()
@@ -87,11 +87,10 @@
*/
private class CompositionImpl(
private val parent: CompositionReference,
- composerFactory: (SlotTable, CompositionReference) -> Composer<*>,
+ composerFactory: (CompositionReference) -> Composer<*>,
private val onDispose: () -> Unit
) : Composition {
- private val slotTable: SlotTable = SlotTable()
- private val composer: Composer<*> = composerFactory(slotTable, parent).also {
+ private val composer: Composer<*> = composerFactory(parent).also {
parent.registerComposer(it)
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionData.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionData.kt
new file mode 100644
index 0000000..53aa673
--- /dev/null
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionData.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package androidx.compose.runtime
+
+/**
+ * A [CompositionData] is the data tracked by the composer during composition.
+ *
+ * This interface is not intended to be used directly and is provided to allow the tools API to
+ * have access to data tracked during composition. The tools API should be used instead which
+ * provides a more usable interpretation of the slot table.
+ */
+interface CompositionData {
+ /**
+ * Iterate the composition data in the group. The composition data is structured as a tree of
+ * values that corresponds to the call graph of the functions that produced the tree.
+ * Interspersed are groups that represents the nodes themselves.
+ */
+ val compositionGroups: Iterable<CompositionGroup>
+
+ /**
+ * Returns true if no composition data has been collected. This occurs when the first
+ * composition into this composition data has not completed yet or, if it is a group, it
+ * doesn't contain any child groups.
+ */
+ val isEmpty: Boolean
+}
+
+/**
+ * [CompositionGroup] is a group of data slots tracked independently by composition. These groups
+ * correspond to flow control branches (such as if statements and function calls) as well as
+ * emitting of a node to the tree.
+ *
+ * This interface is not intended to be used directly and is provided to allow the tools API to
+ * have access to data tracked during composition. The tools API should be used instead which
+ * provides a more usable interpretation of the slot table.
+ */
+interface CompositionGroup : CompositionData {
+ /**
+ * A value used to identify the group within its siblings and is typically a compiler
+ * generated integer but can be an object if the [key] composable is used.
+ */
+ val key: Any
+
+ /**
+ * Information recorded by the compiler to help tooling identify the source that generated
+ * the group. The format of this string is internal and is interpreted by the tools API which
+ * translates this information into source file name and offsets.
+ */
+ val sourceInfo: String?
+
+ /**
+ * If the group represents a node this returns a non-null value which is the node that was
+ * emitted for the group.
+ */
+ val node: Any?
+
+ /**
+ * The data stored in the slot table for this group. This information includes the values
+ * stored for parameters that are checked for change, any value passed as a parameter for
+ * [remember] and the last value returned by [remember], etc.
+ */
+ val data: Iterable<Any?>
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
index 26940dd..cdcb110 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
@@ -41,7 +41,7 @@
internal abstract fun composeInitial(composer: Composer<*>, composable: @Composable () -> Unit)
internal abstract fun invalidate(composer: Composer<*>)
- internal open fun recordInspectionTable(table: MutableSet<SlotTable>) {}
+ internal open fun recordInspectionTable(table: MutableSet<CompositionData>) {}
internal open fun registerComposer(composer: Composer<*>) {
registerComposerWithRoot(composer)
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
index 03bdc3d..7f5560c 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
@@ -437,7 +437,7 @@
internal override val collectingParameterInformation: Boolean
get() = false
- internal override fun recordInspectionTable(table: MutableSet<SlotTable>) {
+ internal override fun recordInspectionTable(table: MutableSet<CompositionData>) {
// TODO: The root recomposer might be a better place to set up inspection
// than the current configuration with an ambient
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
index b1f49c7..14e4ca6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
@@ -73,8 +73,7 @@
// The public API refers only to Index values. Address values are internal.
-@InternalComposeApi
-class SlotTable {
+internal class SlotTable : CompositionData, Iterable<CompositionGroup> {
/**
* An array to store group information that is stored as groups of [Group_Fields_Size]
* elements of the array. The [groups] array can be thought of as an array of an inline
@@ -113,7 +112,14 @@
/**
* Tracks whether there is an active writer.
*/
- private var writer = false
+ internal var writer = false
+ private set
+
+ /**
+ * An internal version that is incremented whenever a writer is created. This is used to
+ * detect when an iterator created by [CompositionData] is invalid.
+ */
+ internal var version = 0
/**
* A list of currently active anchors.
@@ -123,7 +129,7 @@
/**
* Returns true if the slot table is empty
*/
- val isEmpty get() = groupsSize == 0
+ override val isEmpty get() = groupsSize == 0
/**
* Read the slot table in [block]. Any number of readers can be created but a slot table cannot
@@ -178,6 +184,7 @@
check(!writer) { "Cannot start a writer when another writer is pending" }
check(readers <= 0) { "Cannot start a writer when a reader is pending" }
writer = true
+ version++
return SlotWriter(this)
}
@@ -438,6 +445,11 @@
val end = if (group + 1 < groupsSize) groups.dataAnchor(group + 1) else slots.size
return slots.toList().subList(start, end)
}
+
+ override val compositionGroups: Iterable<CompositionGroup> get() = this
+
+ override fun iterator(): Iterator<CompositionGroup> =
+ GroupIterator(this, 0, groupsSize)
}
/**
@@ -448,8 +460,7 @@
* instead of the [SlotTable] as the anchor index could have shifted due to operations performed
* on the writer.
*/
-@InternalComposeApi
-class Anchor internal constructor(loc: Int) {
+internal class Anchor(loc: Int) {
internal var location: Int = loc
val valid get() = location != Int.MIN_VALUE
fun toIndexFor(slots: SlotTable) = slots.anchorIndex(this)
@@ -459,8 +470,7 @@
/**
* A reader of a slot table. See [SlotTable]
*/
-@InternalComposeApi
-class SlotReader(
+internal class SlotReader(
/**
* The table for whom this is a reader.
*/
@@ -890,8 +900,7 @@
/**
* The writer for a slot table. See [SlotTable] for details.
*/
-@InternalComposeApi
-class SlotWriter internal constructor(
+internal class SlotWriter(
/**
* The [SlotTable] for whom this is writer.
*/
@@ -2350,6 +2359,79 @@
if (index > parentAnchorPivot) index else size + index - parentAnchorPivot
}
+private class GroupIterator(
+ val table: SlotTable,
+ start: Int,
+ val end: Int
+) : Iterator<CompositionGroup> {
+ private var index = start
+ private val version = table.version
+
+ init {
+ if (table.writer) throw ConcurrentModificationException()
+ }
+
+ override fun hasNext() = index < end
+
+ override fun next(): CompositionGroup {
+ validateRead()
+ val group = index
+ index += table.groups.groupSize(group)
+ return object : CompositionGroup, Iterable<CompositionGroup> {
+ override val isEmpty: Boolean get() = table.groups.groupSize(group) == 0
+
+ override val key: Any
+ get() = if (table.groups.hasObjectKey(group))
+ table.slots[table.groups.objectKeyIndex(group)]!!
+ else table.groups.key(group)
+
+ override val sourceInfo: String?
+ get() = if (table.groups.hasAux(group))
+ table.slots[table.groups.auxIndex(group)] as? String
+ else null
+
+ override val node: Any?
+ get() = if (table.groups.isNode(group))
+ table.slots[table.groups.nodeIndex(group)] else
+ null
+
+ override val data: Iterable<Any?> get() {
+ val start = table.groups.dataAnchor(group)
+ val end = if (group + 1 < table.groupsSize)
+ table.groups.dataAnchor(group + 1) else table.slotsSize
+ return object : Iterable<Any?>, Iterator<Any?> {
+ var index = start
+ override fun iterator(): Iterator<Any?> = this
+ override fun hasNext(): Boolean = index < end
+ override fun next(): Any? =
+ (
+ if (index >= 0 && index < table.slots.size)
+ table.slots[index]
+ else null
+ ).also { index++ }
+ }
+ }
+
+ override val compositionGroups: Iterable<CompositionGroup> get() = this
+
+ override fun iterator(): Iterator<CompositionGroup> {
+ validateRead()
+ return GroupIterator(
+ table,
+ group + 1,
+ group + table.groups.groupSize(group)
+ )
+ }
+ }
+ }
+
+ private fun validateRead() {
+ if (table.version != version) {
+ throw ConcurrentModificationException()
+ }
+ }
+}
+
// Parent -1 is reserved to be the root parent index so the anchor must pivot on -2.
private const val parentAnchorPivot = -2
@@ -2539,7 +2621,6 @@
/**
* This is inlined here instead to avoid allocating a lambda for the compare when this is used.
*/
-@OptIn(InternalComposeApi::class)
private fun ArrayList<Anchor>.search(location: Int, effectiveSize: Int): Int {
var low = 0
var high = size - 1
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
index 6a1b9db..e8e35cc 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
@@ -16,12 +16,12 @@
package androidx.compose.runtime.tooling
+import androidx.compose.runtime.CompositionData
import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.runtime.SlotTable
import androidx.compose.runtime.staticAmbientOf
/**
* A set of slot tables that where produced when in inspection mode.
*/
@InternalComposeApi
-val InspectionTables = staticAmbientOf<MutableSet<SlotTable>?> { null }
+val InspectionTables = staticAmbientOf<MutableSet<CompositionData>?> { null }
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionDataTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionDataTests.kt
new file mode 100644
index 0000000..20ee054
--- /dev/null
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionDataTests.kt
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package androidx.compose.runtime
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+@OptIn(InternalComposeApi::class)
+class CompositionDataTests {
+
+ @Test
+ fun canGetCompositionDataFromSlotTable() {
+ val slots = SlotTable()
+ val compositionData = slots as CompositionData
+ assertTrue(compositionData.compositionGroups.toList().isEmpty())
+ }
+
+ @Test
+ fun canIterateASlotTable() {
+ val slots = SlotTable().also {
+ it.write { writer ->
+ writer.insert {
+ writer.group(1) {
+ for (i in 1..5) {
+ writer.group(i * 10) {
+ for (j in 1..i) {
+ writer.update(i * 100 + j)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ slots.verifyWellFormed()
+
+ val list = mutableListOf<Int>()
+ fun iterate(compositionData: CompositionData) {
+ for (group in compositionData.compositionGroups) {
+ list.add(group.key as Int)
+ for (data in group.data) {
+ list.add(data as Int)
+ }
+ iterate(group)
+ }
+ }
+
+ iterate(slots)
+
+ assertEquals(
+ listOf(
+ 1, 10, 101,
+ 20, 201, 202,
+ 30, 301, 302, 303,
+ 40, 401, 402, 403, 404,
+ 50, 501, 502, 503, 504, 505
+ ),
+ list
+ )
+ }
+
+ @Test
+ fun canFindNodes() {
+ val data = List(26) { 'A' + it }
+ val slots = SlotTable().also {
+ it.write { writer ->
+ writer.insert {
+ writer.group(0) {
+ fun emit(a: List<Char>) {
+ if (a.isNotEmpty()) {
+ writer.group(1) {
+ val mid = (a.size - 1) / 2 + 1
+ writer.nodeGroup(10, a[0])
+ if (mid > 1)
+ emit(a.subList(1, mid))
+ if (mid < a.size)
+ emit(a.subList(mid, a.size))
+ }
+ }
+ }
+
+ emit(data)
+ }
+ }
+ }
+ }
+
+ val collected = mutableListOf<Char>()
+
+ fun collect(data: CompositionData) {
+ for (group in data.compositionGroups) {
+ if (group.node != null) {
+ collected.add(group.node as Char)
+ }
+ collect(group)
+ }
+ }
+
+ collect(slots)
+
+ assertEquals(data, collected)
+ }
+
+ @Test
+ fun canFindSourceInfo() {
+ val slots = SlotTable().also {
+ var data = 0
+ it.write { writer ->
+ writer.insert {
+ writer.group(0) {
+ fun emit(depth: Int) {
+ if (depth == 0) {
+ writer.startData(100, aux = "$data")
+ data++
+ writer.endGroup()
+ } else {
+ if (depth == 2) {
+ writer.startData(depth * 1000, aux = "$data")
+ data++
+ } else writer.startGroup(depth)
+ emit(depth - 1)
+ emit(depth - 1)
+ writer.endGroup()
+ }
+ }
+ emit(5)
+ }
+ }
+ }
+ }
+
+ val collected = mutableListOf<String>()
+
+ fun collect(data: CompositionData) {
+ for (group in data.compositionGroups) {
+ val sourceInfo = group.sourceInfo
+ if (sourceInfo != null) {
+ collected.add(sourceInfo)
+ }
+ collect(group)
+ }
+ }
+
+ collect(slots)
+
+ assertEquals(List(40) { "$it" }, collected)
+ }
+
+ @Test(expected = ConcurrentModificationException::class)
+ fun writeDuringIterationCausesException() {
+ val slots = SlotTable().also {
+ it.write { writer ->
+ writer.insert {
+ writer.group(0) {
+ repeat(10) { index ->
+ writer.group(100 + index) { }
+ }
+ }
+ }
+ }
+ }
+
+ fun insertAGroup() {
+ slots.write { writer ->
+ writer.group {
+ repeat(3) { writer.group { } }
+ writer.insert {
+ writer.group(200) { }
+ }
+ writer.skipToGroupEnd()
+ }
+ }
+ }
+
+ val groups = slots.compositionGroups.iterator()
+ insertAGroup()
+
+ // Expect this to cause an exception
+ groups.next()
+ }
+
+ @Test(expected = ConcurrentModificationException::class)
+ fun iterationDuringWriteCausesException() {
+ val slots = SlotTable().also {
+ it.write { writer ->
+ writer.insert {
+ writer.group(0) {
+ repeat(10) { index ->
+ writer.group(100 + index) { }
+ }
+ }
+ }
+ }
+ }
+
+ slots.write { writer ->
+ writer.group {
+ repeat(3) { writer.group { } }
+ writer.insert {
+ writer.group(200) { }
+ }
+ writer.skipToGroupEnd()
+
+ // Expect this to throw an exception
+ slots.compositionGroups.first()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
index fde53a01..84a2b9f 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -321,7 +321,7 @@
repeat(of = chars) { c -> textOf(c) }
}
- fun MockViewValidator.validatechars(chars: Iterable<Char>) {
+ fun MockViewValidator.validateChars(chars: Iterable<Char>) {
repeat(of = chars) { c -> textOf(c) }
}
@@ -333,9 +333,9 @@
}
result.validate {
- validatechars(chars)
- validatechars(chars)
- validatechars(chars)
+ validateChars(chars)
+ validateChars(chars)
+ validateChars(chars)
}
chars = listOf('a', 'b', 'x', 'c')
@@ -343,9 +343,9 @@
result.expectChanges()
result.validate {
- validatechars(chars)
- validatechars(chars)
- validatechars(chars)
+ validateChars(chars)
+ validateChars(chars)
+ validateChars(chars)
}
}
@@ -567,7 +567,7 @@
}
@Test
- fun testComponentWithVarCtorParameter() {
+ fun testComponentWithVarConstructorParameter() {
@Composable fun MockComposeScope.One(first: Int) {
text("$first")
}
@@ -601,7 +601,7 @@
}
@Test
- fun testComponentWithValCtorParameter() {
+ fun testComponentWithValConstructorParameter() {
@Composable fun MockComposeScope.One(first: Int) {
text("$first")
}
@@ -2516,7 +2516,7 @@
@Test
fun testComposableLambdaSubcompositionInvalidation() = runBlockingTest {
localRecomposerTest { recomposer ->
- val composer = Composer(SlotTable(), EmptyApplier(), recomposer)
+ val composer = Composer(EmptyApplier(), recomposer)
try {
var rootState by mutableStateOf(false)
val composedResults = mutableListOf<Boolean>()
@@ -2544,7 +2544,7 @@
@Test
fun testCompositionReferenceIsRemembered() = runBlockingTest {
localRecomposerTest { recomposer ->
- val composer = Composer(SlotTable(), EmptyApplier(), recomposer)
+ val composer = Composer(EmptyApplier(), recomposer)
try {
lateinit var invalidator: () -> Unit
val parentReferences = mutableListOf<CompositionReference>()
@@ -2569,7 +2569,7 @@
@Test
fun testParentCompositionRecomposesFirst() = runBlockingTest {
localRecomposerTest { recomposer ->
- val composer = Composer(SlotTable(), EmptyApplier(), recomposer)
+ val composer = Composer(EmptyApplier(), recomposer)
val results = mutableListOf<String>()
try {
var firstState by mutableStateOf("firstInitial")
@@ -2606,7 +2606,7 @@
val parentRef = compositionReference()
val currentContent by rememberUpdatedState(content)
DisposableEffect(parentRef) {
- val subcomposer = Composer(SlotTable(), EmptyApplier(), parentRef)
+ val subcomposer = Composer(EmptyApplier(), parentRef)
parentRef.composeInitial(subcomposer) {
currentContent()
}
@@ -2671,8 +2671,7 @@
assertTrue(changes, "Expected changes")
composer.applyChanges()
Snapshot.notifyObjectsInitialized()
- composer.slotTable.verifyWellFormed()
- composer.insertTable.verifyWellFormed()
+ composer.verifyConsistent()
}
fun recompose(): Boolean = doCompose(composer) { composer.recompose() }
@@ -2708,6 +2707,9 @@
}
}
+/**
+ * Composer the given block.
+ */
@OptIn(InternalComposeApi::class, ExperimentalComposeApi::class)
private fun compose(
block: @Composable MockComposeScope.() -> Unit
@@ -2727,7 +2729,6 @@
scope.launch(clock) { runRecomposeAndApplyChanges() }
}
Composer(
- SlotTable(),
ViewApplier(root),
recomposer
)
@@ -2741,26 +2742,11 @@
Snapshot.notifyObjectsInitialized()
composer.applyChanges()
}
- composer.slotTable.verifyWellFormed()
- validateRecomposeScopeAnchors(composer.slotTable)
+ composer.verifyConsistent()
return CompositionResult(composer, root)
}
-@OptIn(InternalComposeApi::class)
-fun validateRecomposeScopeAnchors(slotTable: SlotTable) {
- val scopes = slotTable.slots.map { it as? RecomposeScope }.filterNotNull()
- for (scope in scopes) {
- scope.anchor?.let { anchor ->
- check(scope in slotTable.slotsOf(anchor.toIndexFor(slotTable))) {
- val dataIndex = slotTable.slots.indexOf(scope)
- "Misaligned anchor $anchor in scope $scope encountered, scope found at " +
- "$dataIndex"
- }
- }
- }
-}
-
// Contact test data
private val bob = Contact("Bob Smith", email = "bob@smith.com")
private val jon = Contact(name = "Jon Alberton", email = "jon@alberton.com")
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
index 5910f88..d6d2f38 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
@@ -3070,34 +3070,34 @@
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotWriter.group(block: () -> Unit) {
+internal inline fun SlotWriter.group(block: () -> Unit) {
startGroup()
block()
endGroup()
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotWriter.group(key: Int, block: () -> Unit) {
+internal inline fun SlotWriter.group(key: Int, block: () -> Unit) {
startGroup(key)
block()
endGroup()
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotWriter.nodeGroup(key: Int, node: Any, block: () -> Unit = { }) {
+internal inline fun SlotWriter.nodeGroup(key: Int, node: Any, block: () -> Unit = { }) {
startNode(key, node)
block()
endGroup()
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotWriter.insert(block: () -> Unit) {
+internal inline fun SlotWriter.insert(block: () -> Unit) {
beginInsert()
block()
endInsert()
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotReader.group(key: Int, block: () -> Unit) {
+internal inline fun SlotReader.group(key: Int, block: () -> Unit) {
assertEquals(key, groupKey)
startGroup()
block()
@@ -3105,7 +3105,7 @@
}
@OptIn(InternalComposeApi::class)
-private inline fun SlotReader.group(block: () -> Unit) {
+internal inline fun SlotReader.group(block: () -> Unit) {
startGroup()
block()
endGroup()
@@ -3124,7 +3124,7 @@
private const val elementKey = 100
@OptIn(InternalComposeApi::class)
-fun testSlotsNumbered(): SlotTable {
+private fun testSlotsNumbered(): SlotTable {
val slotTable = SlotTable()
slotTable.write { writer ->
writer.beginInsert()
@@ -3141,7 +3141,7 @@
// Creates 0 until 10 items each with 10 elements numbered 0...n with 0..n slots
@OptIn(InternalComposeApi::class)
-fun testItems(): SlotTable {
+private fun testItems(): SlotTable {
val slots = SlotTable()
slots.write { writer ->
writer.beginInsert()
@@ -3178,7 +3178,7 @@
}
@OptIn(InternalComposeApi::class)
-fun validateItems(slots: SlotTable) {
+private fun validateItems(slots: SlotTable) {
slots.read { reader ->
check(reader.groupKey == treeRoot) { "Invalid root key" }
reader.startGroup()
@@ -3229,7 +3229,7 @@
}
@OptIn(InternalComposeApi::class)
-fun narrowTrees(): Pair<SlotTable, List<Anchor>> {
+private fun narrowTrees(): Pair<SlotTable, List<Anchor>> {
val slots = SlotTable()
val anchors = mutableListOf<Anchor>()
slots.write { writer ->
@@ -3278,13 +3278,13 @@
}
@OptIn(InternalComposeApi::class)
-fun SlotReader.expectGroup(key: Int): Int {
+private fun SlotReader.expectGroup(key: Int): Int {
assertEquals(key, groupKey)
return skipGroup()
}
@OptIn(InternalComposeApi::class)
-fun SlotReader.expectGroup(
+private fun SlotReader.expectGroup(
key: Int,
block: () -> Unit
) {
@@ -3295,12 +3295,12 @@
}
@OptIn(InternalComposeApi::class)
-fun SlotReader.expectData(value: Any) {
+private fun SlotReader.expectData(value: Any) {
assertEquals(value, next())
}
@OptIn(InternalComposeApi::class)
-fun SlotReader.expectGroup(
+private fun SlotReader.expectGroup(
key: Int,
objectKey: Any?,
block: () -> Unit = { skipToGroupEnd() }
diff --git a/compose/ui/ui-tooling/api/current.txt b/compose/ui/ui-tooling/api/current.txt
index ca0c914..2d94392 100644
--- a/compose/ui/ui-tooling/api/current.txt
+++ b/compose/ui/ui-tooling/api/current.txt
@@ -74,7 +74,7 @@
}
public final class SlotTreeKt {
- method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.SlotTable);
+ method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.CompositionData);
method public static String? getPosition(androidx.compose.ui.tooling.Group);
}
diff --git a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
index ca0c914..2d94392 100644
--- a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
@@ -74,7 +74,7 @@
}
public final class SlotTreeKt {
- method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.SlotTable);
+ method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.CompositionData);
method public static String? getPosition(androidx.compose.ui.tooling.Group);
}
diff --git a/compose/ui/ui-tooling/api/restricted_current.txt b/compose/ui/ui-tooling/api/restricted_current.txt
index ca0c914..2d94392 100644
--- a/compose/ui/ui-tooling/api/restricted_current.txt
+++ b/compose/ui/ui-tooling/api/restricted_current.txt
@@ -74,7 +74,7 @@
}
public final class SlotTreeKt {
- method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.SlotTable);
+ method public static androidx.compose.ui.tooling.Group asTree(androidx.compose.runtime.CompositionData);
method public static String? getPosition(androidx.compose.ui.tooling.Group);
}
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/BoundsTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/BoundsTest.kt
index 5317df3..30d1dd4 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/BoundsTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/BoundsTest.kt
@@ -55,7 +55,7 @@
@Test
fun testBounds() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
Box {
@@ -98,7 +98,7 @@
@Test
fun testBoundWithConstraints() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
WithConstraints {
@@ -131,7 +131,7 @@
@Test
@LargeTest
fun testDisposeWithComposeTables() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
var value by mutableStateOf(0)
var latch = CountDownLatch(1)
show {
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/InspectableTests.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/InspectableTests.kt
index 7f1b213..a1ea937 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/InspectableTests.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/InspectableTests.kt
@@ -25,7 +25,6 @@
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.runtime.SlotTable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
@@ -50,7 +49,7 @@
class InspectableTests : ToolingTest() {
@Test
fun simpleInspection() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
Column {
@@ -77,7 +76,7 @@
@Test
fun parametersTest() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
fun unknown(i: Int) = i
show {
@@ -116,8 +115,8 @@
val tree = slotTableRecord.store.first().asTree()
val list = tree.asList()
- val parameters = list.filter {
- it.parameters.isNotEmpty() && it.location.let {
+ val parameters = list.filter { group ->
+ group.parameters.isNotEmpty() && group.location.let {
it != null && it.sourceFile == "InspectableTests.kt"
}
}
@@ -295,7 +294,7 @@
fun inInspectionMode() {
var displayed = false
show {
- Inspectable(SlotTableRecord.create()) {
+ Inspectable(CompositionDataRecord.create()) {
Column {
InInspectionModeOnly {
Box(Modifier.preferredSize(100.dp).background(color = Color(0xFF)))
@@ -326,7 +325,7 @@
@InternalComposeApi
@Test // regression test for b/161839910
fun textParametersAreCorrect() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
Text("Test")
@@ -334,8 +333,8 @@
}
val tree = slotTableRecord.store.first().asTree()
val list = tree.asList()
- val parameters = list.filter {
- it.parameters.isNotEmpty() && it.location.let {
+ val parameters = list.filter { group ->
+ group.parameters.isNotEmpty() && group.location.let {
it != null && it.sourceFile == "InspectableTests.kt"
}
}
@@ -431,14 +430,3 @@
}
return result
}
-
-internal fun SlotTableRecord.findGroupForFile(fileName: String) =
- store.map { it.findGroupForFile(fileName) }.filterNotNull().firstOrNull()
-
-@OptIn(InternalComposeApi::class)
-fun SlotTable.findGroupForFile(fileName: String) = asTree().findGroupForFile(fileName)
-fun Group.findGroupForFile(fileName: String): Group? {
- val position = position
- if (position != null && position.contains(fileName)) return this
- return children.map { it.findGroupForFile(fileName) }.filterNotNull().firstOrNull()
-}
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ModifierInfoTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ModifierInfoTest.kt
index 6a7348f..a5070a6 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ModifierInfoTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ModifierInfoTest.kt
@@ -44,7 +44,7 @@
@Test
fun testBounds() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
with(AmbientDensity.current) {
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ToolingTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ToolingTest.kt
index d3d094f..f8c34a2 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ToolingTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/ToolingTest.kt
@@ -21,8 +21,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.runtime.SlotTable
+import androidx.compose.runtime.CompositionData
import androidx.compose.ui.Modifier
import androidx.compose.ui.R
import androidx.compose.ui.layout.onGloballyPositioned
@@ -73,12 +72,11 @@
activityTestRule.onUiThread { }
}
- @OptIn(InternalComposeApi::class)
- internal fun showAndRecord(content: @Composable () -> Unit): MutableSet<SlotTable>? {
+ internal fun showAndRecord(content: @Composable () -> Unit): MutableSet<CompositionData>? {
positionedLatch = CountDownLatch(1)
- val map: MutableSet<SlotTable> = Collections.newSetFromMap(
- WeakHashMap<SlotTable, Boolean>()
+ val map: MutableSet<CompositionData> = Collections.newSetFromMap(
+ WeakHashMap<CompositionData, Boolean>()
)
activityTestRule.onUiThread {
ViewRootForTest.onViewCreatedCallback = {
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt
index 1491a4c..6a035f6 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt
@@ -21,7 +21,7 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.Group
import androidx.compose.ui.tooling.Inspectable
-import androidx.compose.ui.tooling.SlotTableRecord
+import androidx.compose.ui.tooling.CompositionDataRecord
import androidx.compose.ui.tooling.ToolingTest
import androidx.compose.ui.tooling.asTree
import androidx.compose.ui.unit.Dp
@@ -38,7 +38,7 @@
@Test
fun parameterValueTest() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
Surface {
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
index 4ecf4eb..89c3db5 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
@@ -39,7 +39,7 @@
import androidx.compose.ui.tooling.Group
import androidx.compose.ui.tooling.Inspectable
import androidx.compose.ui.tooling.R
-import androidx.compose.ui.tooling.SlotTableRecord
+import androidx.compose.ui.tooling.CompositionDataRecord
import androidx.compose.ui.tooling.ToolingTest
import androidx.compose.ui.tooling.asTree
import androidx.compose.ui.tooling.position
@@ -76,7 +76,7 @@
@Ignore("Manual test")
@Test
fun buildTree() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
@@ -388,7 +388,7 @@
@Test
fun testStitchTreeFromModelDrawerLayout() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
@@ -442,7 +442,7 @@
@Test
fun testSpacer() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
@@ -466,7 +466,7 @@
@Test // regression test b/174855322
fun testBasicText() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
show {
@@ -492,7 +492,7 @@
@Test
@Ignore("b/174152464")
fun testTextId() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
@@ -664,7 +664,7 @@
else -> value?.toString() ?: "null"
}
- private fun dumpSlotTableSet(slotTableRecord: SlotTableRecord) {
+ private fun dumpSlotTableSet(slotTableRecord: CompositionDataRecord) {
@Suppress("ConstantConditionIf")
if (!DEBUG) {
return
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/OffsetInformationTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/OffsetInformationTest.kt
index 96c833c..7c85542 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/OffsetInformationTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/OffsetInformationTest.kt
@@ -18,7 +18,7 @@
import androidx.compose.ui.tooling.Group
import androidx.compose.ui.tooling.Inspectable
-import androidx.compose.ui.tooling.SlotTableRecord
+import androidx.compose.ui.tooling.CompositionDataRecord
import androidx.compose.ui.tooling.ToolingTest
import androidx.compose.ui.tooling.asTree
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -32,7 +32,7 @@
class OffsetInformationTest : ToolingTest() {
@Test
fun testOffset() {
- val slotTableRecord = SlotTableRecord.create()
+ val slotTableRecord = CompositionDataRecord.create()
show {
Inspectable(slotTableRecord) {
OffsetData()
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/Inspectable.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/Inspectable.kt
index 1f1b9d2..b0d5680 100644
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/Inspectable.kt
+++ b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/Inspectable.kt
@@ -17,9 +17,9 @@
package androidx.compose.ui.tooling
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionData
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.Providers
-import androidx.compose.runtime.SlotTable
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.tooling.InspectionTables
import androidx.compose.ui.platform.InspectionMode
@@ -27,20 +27,19 @@
import java.util.WeakHashMap
/**
- * Storage for the preview generated [SlotTable]s.
+ * Storage for the preview generated [CompositionData]s.
*/
-internal interface SlotTableRecord {
- @OptIn(InternalComposeApi::class)
- val store: Set<SlotTable>
+internal interface CompositionDataRecord {
+ val store: Set<CompositionData>
companion object {
- fun create(): SlotTableRecord = SlotTableRecordImpl()
+ fun create(): CompositionDataRecord = CompositionDataRecordImpl()
}
}
-private class SlotTableRecordImpl : SlotTableRecord {
+private class CompositionDataRecordImpl : CompositionDataRecord {
@OptIn(InternalComposeApi::class)
- override val store: MutableSet<SlotTable> =
+ override val store: MutableSet<CompositionData> =
Collections.newSetFromMap(WeakHashMap())
}
@@ -48,20 +47,21 @@
* A wrapper for compositions in inspection mode. The composition inside the Inspectable component
* is in inspection mode.
*
- * @param slotTableRecord [SlotTableRecord] to record the SlotTable used in the composition of [content]
+ * @param compositionDataRecord [CompositionDataRecord] to record the SlotTable used in the
+ * composition of [content]
*
* @suppress
*/
@Composable
@OptIn(InternalComposeApi::class)
internal fun Inspectable(
- slotTableRecord: SlotTableRecord,
+ compositionDataRecord: CompositionDataRecord,
content: @Composable () -> Unit
) {
currentComposer.collectKeySourceInformation()
currentComposer.collectParameterInformation()
- val store = (slotTableRecord as SlotTableRecordImpl).store
- store.add(currentComposer.slotTable)
+ val store = (compositionDataRecord as CompositionDataRecordImpl).store
+ store.add(currentComposer.compositionData)
Providers(
InspectionMode provides true,
InspectionTables provides store,
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/SlotTree.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/SlotTree.kt
index 265bcfc..f38aa50 100644
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/SlotTree.kt
+++ b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/SlotTree.kt
@@ -14,14 +14,10 @@
* limitations under the License.
*/
-@file:OptIn(InternalComposeApi::class)
-
package androidx.compose.ui.tooling
-import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.runtime.SlotReader
-import androidx.compose.runtime.SlotTable
-import androidx.compose.runtime.keySourceInfoOf
+import androidx.compose.runtime.CompositionData
+import androidx.compose.runtime.CompositionGroup
import androidx.compose.ui.layout.globalPosition
import androidx.compose.ui.layout.LayoutInfo
import androidx.compose.ui.layout.ModifierInfo
@@ -160,9 +156,6 @@
*/
data class JoinedKey(val left: Any?, val right: Any?)
-@OptIn(InternalComposeApi::class)
-private fun convertKey(key: Int): Any? = keySourceInfoOf(key)
-
internal val emptyBox = IntBounds(0, 0, 0, 0)
private val tokenizer = Regex("(\\d+)|([,])|([*])|([:])|L|(P\\([^)]*\\))|(C(\\(([^)]*)\\))?)|@")
@@ -432,28 +425,15 @@
/**
* Iterate the slot table and extract a group tree that corresponds to the content of the table.
*/
-@OptIn(InternalComposeApi::class)
-private fun SlotReader.getGroup(parentContext: SourceInformationContext?): Group {
- val key = convertKey(groupKey)
- val groupData = groupAux
- val context = if (groupData != null && groupData is String) {
- sourceInformationContextOf(groupData, parentContext)
- } else null
- val nodeGroup = isNode
- val end = currentGroup + groupSize
- val node = if (nodeGroup) groupNode else null
+private fun CompositionGroup.getGroup(parentContext: SourceInformationContext?): Group {
+ val key = key
+ val context = sourceInfo?.let { sourceInformationContextOf(it, parentContext) }
+ val node = node
val data = mutableListOf<Any?>()
val children = mutableListOf<Group>()
- for (index in 0 until groupSlotCount) {
- data.add(groupGet(index))
- }
-
- reposition(currentGroup + 1)
-
- // A group ends with a list of groups
- while (currentGroup < end) {
- children.add(getGroup(context))
- }
+ data.addAll(this.data)
+ for (child in compositionGroups)
+ children.add(child.getGroup(context))
val modifierInfo = if (node is LayoutInfo) {
node.getModifierInfo()
@@ -468,9 +448,9 @@
if (children.isEmpty()) emptyBox else
children.map { g -> g.box }.reduce { acc, box -> box.union(acc) }
}
- return if (nodeGroup) NodeGroup(
+ return if (node != null) NodeGroup(
key,
- node as Any,
+ node,
box,
data,
modifierInfo,
@@ -513,8 +493,7 @@
* Return a group tree for for the slot table that represents the entire content of the slot
* table.
*/
-@OptIn(InternalComposeApi::class)
-fun SlotTable.asTree(): Group = read { it.getGroup(null) }
+fun CompositionData.asTree(): Group = compositionGroups.first().getGroup(null)
internal fun IntBounds.union(other: IntBounds): IntBounds {
if (this == emptyBox) return other else if (other == emptyBox) return this
@@ -547,62 +526,61 @@
context: SourceInformationContext?
): List<ParameterInformation> {
if (data.isNotEmpty()) {
- val recomposeScope = data[0]
+ val recomposeScope = data.firstOrNull {
+ it != null && it.javaClass.name.endsWith(recomposeScopeNameSuffix)
+ }
if (recomposeScope != null) {
- val scopeClass = recomposeScope.javaClass
- if (scopeClass.name.endsWith(recomposeScopeNameSuffix)) {
- try {
- val blockField = scopeClass.accessibleField("block")
- if (blockField != null) {
- val block = blockField.get(recomposeScope)
- if (block != null) {
- val blockClass = block.javaClass
- val defaultsField = blockClass.accessibleField(defaultFieldName)
- val changedField = blockClass.accessibleField(changedFieldName)
- val default =
- if (defaultsField != null) defaultsField.get(block) as Int else 0
- val changed =
- if (changedField != null) changedField.get(block) as Int else 0
- val fields = blockClass.declaredFields
- .filter {
- it.name.startsWith(parameterPrefix) &&
- !it.name.startsWith(internalFieldPrefix) &&
- !it.name.startsWith(jacocoDataField)
- }.sortedBy { it.name }
- val parameters = mutableListOf<ParameterInformation>()
- val parametersMetadata = context?.parameters ?: emptyList()
- repeat(fields.size) { index ->
- val metadata = if (index < parametersMetadata.size)
- parametersMetadata[index] else Parameter(index)
- if (metadata.sortedIndex >= fields.size) return@repeat
- val field = fields[metadata.sortedIndex]
- field.isAccessible = true
- val value = field.get(block)
- val fromDefault = (1 shl index) and default != 0
- val changedOffset = index * BITS_PER_SLOT + 1
- val parameterChanged = (
- (SLOT_MASK shl changedOffset) and changed
- ) shr changedOffset
- val static = parameterChanged and STATIC_BITS == STATIC_BITS
- val compared = parameterChanged and STATIC_BITS == 0
- val stable = parameterChanged and STABLE_BITS == 0
- parameters.add(
- ParameterInformation(
- name = field.name.substring(1),
- value = value,
- fromDefault = fromDefault,
- static = static,
- compared = compared && !fromDefault,
- inlineClass = metadata.inlineClass,
- stable = stable
- )
+ try {
+ val blockField = recomposeScope.javaClass.accessibleField("block")
+ if (blockField != null) {
+ val block = blockField.get(recomposeScope)
+ if (block != null) {
+ val blockClass = block.javaClass
+ val defaultsField = blockClass.accessibleField(defaultFieldName)
+ val changedField = blockClass.accessibleField(changedFieldName)
+ val default =
+ if (defaultsField != null) defaultsField.get(block) as Int else 0
+ val changed =
+ if (changedField != null) changedField.get(block) as Int else 0
+ val fields = blockClass.declaredFields
+ .filter {
+ it.name.startsWith(parameterPrefix) &&
+ !it.name.startsWith(internalFieldPrefix) &&
+ !it.name.startsWith(jacocoDataField)
+ }.sortedBy { it.name }
+ val parameters = mutableListOf<ParameterInformation>()
+ val parametersMetadata = context?.parameters ?: emptyList()
+ repeat(fields.size) { index ->
+ val metadata = if (index < parametersMetadata.size)
+ parametersMetadata[index] else Parameter(index)
+ if (metadata.sortedIndex >= fields.size) return@repeat
+ val field = fields[metadata.sortedIndex]
+ field.isAccessible = true
+ val value = field.get(block)
+ val fromDefault = (1 shl index) and default != 0
+ val changedOffset = index * BITS_PER_SLOT + 1
+ val parameterChanged = (
+ (SLOT_MASK shl changedOffset) and changed
+ ) shr changedOffset
+ val static = parameterChanged and STATIC_BITS == STATIC_BITS
+ val compared = parameterChanged and STATIC_BITS == 0
+ val stable = parameterChanged and STABLE_BITS == 0
+ parameters.add(
+ ParameterInformation(
+ name = field.name.substring(1),
+ value = value,
+ fromDefault = fromDefault,
+ static = static,
+ compared = compared && !fromDefault,
+ inlineClass = metadata.inlineClass,
+ stable = stable
)
- }
- return parameters
+ )
}
+ return parameters
}
- } catch (_: Throwable) {
}
+ } catch (_: Throwable) {
}
}
}
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt
index b831653..f2acc87 100644
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt
+++ b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt
@@ -17,9 +17,10 @@
package androidx.compose.ui.tooling.inspector
import android.view.View
+import androidx.compose.runtime.CompositionData
import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.runtime.SlotTable
import androidx.compose.ui.layout.LayoutInfo
+import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.OwnedLayer
import androidx.compose.ui.tooling.Group
import androidx.compose.ui.tooling.NodeGroup
@@ -73,13 +74,13 @@
Collections.newSetFromMap(IdentityHashMap<MutableInspectorNode, Boolean>())
/**
- * Converts the [SlotTable] set held by [view] into a list of root nodes.
+ * Converts the [CompositionData] set held by [view] into a list of root nodes.
*/
@OptIn(InternalComposeApi::class)
fun convert(view: View): List<InspectorNode> {
parameterFactory.density = Density(view.context)
@Suppress("UNCHECKED_CAST")
- val tables = view.getTag(R.id.inspection_slot_table_set) as? Set<SlotTable>
+ val tables = view.getTag(R.id.inspection_slot_table_set) as? Set<CompositionData>
?: return emptyList()
clear()
val result = convert(tables)
@@ -111,7 +112,7 @@
}
@OptIn(InternalComposeApi::class)
- private fun convert(tables: Set<SlotTable>): List<InspectorNode> {
+ private fun convert(tables: Set<CompositionData>): List<InspectorNode> {
val trees = tables.map { convert(it) }
return when (trees.size) {
0 -> listOf()
@@ -121,11 +122,12 @@
}
/**
- * Stitch separate trees together using the [LayoutInfo]s found in the [SlotTable]s.
+ * Stitch separate trees together using the [LayoutNode]s found in the [CompositionData]s.
*
- * Some constructs in Compose (e.g. ModalDrawerLayout) will result is multiple [SlotTable]s.
- * This code will attempt to stitch the resulting [InspectorNode] trees together by looking
- * at the parent of each [LayoutInfo].
+ * Some constructs in Compose (e.g. ModalDrawerLayout) will result is multiple
+ * [CompositionData]s. This code will attempt to stitch the resulting [InspectorNode] trees
+ * together by looking at the parent of each [LayoutNode].
+ *
* If this algorithm is successful the result of this function will be a list with a single
* tree.
*/
@@ -199,7 +201,7 @@
}
@OptIn(InternalComposeApi::class)
- private fun convert(table: SlotTable): MutableInspectorNode {
+ private fun convert(table: CompositionData): MutableInspectorNode {
val fakeParent = newNode()
addToParent(fakeParent, listOf(convert(table.asTree())))
return fakeParent
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
index e25b4ae..99eb764 100644
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
+++ b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
@@ -45,7 +45,7 @@
import androidx.compose.ui.platform.ViewRootForTest
import androidx.compose.ui.tooling.Group
import androidx.compose.ui.tooling.Inspectable
-import androidx.compose.ui.tooling.SlotTableRecord
+import androidx.compose.ui.tooling.CompositionDataRecord
import androidx.compose.ui.tooling.SourceLocation
import androidx.compose.ui.tooling.asTree
import androidx.compose.ui.tooling.preview.animation.PreviewAnimationClock
@@ -126,7 +126,7 @@
*/
private var debugPaintBounds = false
internal var viewInfos: List<ViewInfo> = emptyList()
- private val slotTableRecord = SlotTableRecord.create()
+ private val slotTableRecord = CompositionDataRecord.create()
/**
* Simple function name of the Composable being previewed.
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
index 0e2b0e2..2728ac1 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
@@ -24,13 +24,13 @@
import androidx.annotation.MainThread
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
+import androidx.compose.runtime.CompositionData
import androidx.compose.runtime.CompositionReference
import androidx.compose.runtime.ExperimentalComposeApi
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Providers
import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.SlotTable
import androidx.compose.runtime.compositionFor
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.emptyContent
@@ -185,7 +185,7 @@
if (inspectionWanted(owner)) {
owner.setTag(
R.id.inspection_slot_table_set,
- Collections.newSetFromMap(WeakHashMap<SlotTable, Boolean>())
+ Collections.newSetFromMap(WeakHashMap<CompositionData, Boolean>())
)
enableDebugInspectorInfo()
}
@@ -236,11 +236,12 @@
@Suppress("UNCHECKED_CAST")
val inspectionTable =
owner.getTag(R.id.inspection_slot_table_set) as?
- MutableSet<SlotTable>
+ MutableSet<CompositionData>
?: (owner.parent as? View)?.getTag(R.id.inspection_slot_table_set)
- as? MutableSet<SlotTable>
+ as? MutableSet<CompositionData>
if (inspectionTable != null) {
- inspectionTable.add(currentComposer.slotTable)
+ @OptIn(InternalComposeApi::class)
+ inspectionTable.add(currentComposer.compositionData)
currentComposer.collectParameterInformation()
}
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
index 7485666..8b0058f 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
@@ -22,7 +22,6 @@
import androidx.compose.runtime.ExperimentalComposeApi
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.SlotTable
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.dispatch.MonotonicFrameClock
import androidx.compose.runtime.invalidate
@@ -211,7 +210,6 @@
block: @Composable () -> Unit
): Composer<Unit> {
return Composer(
- SlotTable(),
EmptyApplier(),
recomposer
).apply {
@@ -221,7 +219,7 @@
fn(this, 0)
}
applyChanges()
- slotTable.verifyWellFormed()
+ verifyConsistent()
}
}