Add `toList()` and `toMap()` to the respective snapshot collections

Relnote: """`SnapshotStateList` and `SnapshotStateMap` now have
explicit implementaions of `toList()` and `toMap()`, respectfully.
These  methods returns their current content without peforming a
copy as they return the internal immutable data used to store their
content. This value can be used, for example, to produce a flow
of values using `snapshotFlow` without requiring copying of the data."""

Test: ./gradlew :composer:r:r:tDUT
Fixes: 245791884

Change-Id: Ica2bd64be73862b8497bf756c5b0537987d691e5
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 8b0cc2a..f4bfd21 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -907,6 +907,7 @@
     method public boolean retainAll(java.util.Collection<E!> elements);
     method public T! set(int index, T? element);
     method public java.util.List<T> subList(int fromIndex, int toIndex);
+    method public java.util.List<T> toList();
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public int size;
   }
@@ -930,6 +931,7 @@
     method public V? put(K? key, V? value);
     method public void putAll(java.util.Map<? extends K,? extends V> from);
     method public V? remove(Object? key);
+    method public java.util.Map<K,V> toMap();
     property public java.util.Set<java.util.Map.Entry<K,V>> entries;
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public java.util.Set<K> keys;
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index be29da0..6dca9cb 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -983,6 +983,7 @@
     method public boolean retainAll(java.util.Collection<E!> elements);
     method public T! set(int index, T? element);
     method public java.util.List<T> subList(int fromIndex, int toIndex);
+    method public java.util.List<T> toList();
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public int size;
   }
@@ -1006,6 +1007,7 @@
     method public V? put(K? key, V? value);
     method public void putAll(java.util.Map<? extends K,? extends V> from);
     method public V? remove(Object? key);
+    method public java.util.Map<K,V> toMap();
     property public java.util.Set<java.util.Map.Entry<K,V>> entries;
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public java.util.Set<K> keys;
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 684ac84..d9a5576 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -947,6 +947,7 @@
     method public boolean retainAll(java.util.Collection<E!> elements);
     method public T! set(int index, T? element);
     method public java.util.List<T> subList(int fromIndex, int toIndex);
+    method public java.util.List<T> toList();
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public int size;
   }
@@ -970,6 +971,7 @@
     method public V? put(K? key, V? value);
     method public void putAll(java.util.Map<? extends K,? extends V> from);
     method public V? remove(Object? key);
+    method public java.util.Map<K,V> toMap();
     property public java.util.Set<java.util.Map.Entry<K,V>> entries;
     property public androidx.compose.runtime.snapshots.StateRecord firstStateRecord;
     property public java.util.Set<K> keys;
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
index 12d0ca2..cf562db 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
@@ -42,6 +42,23 @@
         firstStateRecord = value as StateListStateRecord<T>
     }
 
+    /**
+     * Return a list containing all the elements of this list.
+     *
+     * The list returned is immutable and returned will not change even if the content of the list
+     * is changed in the same snapshot. It also will be the same instance until the content is
+     * changed. It is not, however, guaranteed to be the same instance for the same list as adding
+     * and removing the same item from the this list might produce a different instance with the
+     * same content.
+     *
+     * This operation is O(1) and does not involve a physically copying the list. It instead
+     * returns the underlying immutable list used internally to store the content of the list.
+     *
+     * It is recommended to use [toList] when using returning the value of this list from
+     * [androidx.compose.runtime.snapshotFlow].
+     */
+    fun toList(): List<T> = readable.list
+
     internal val modification: Int get() = withCurrent { modification }
 
     @Suppress("UNCHECKED_CAST")
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
index 2b14ca4..aceccb7 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
@@ -41,6 +41,22 @@
         firstStateRecord = value as StateMapStateRecord<K, V>
     }
 
+    /**
+     * Returns an immutable map containing all key-value pairs from the original map.
+     *
+     * The content of the map returned will not change even if the content of the map is changed in
+     * the same snapshot. It also will be the same instance until the content is changed. It is not,
+     * however, guaranteed to be the same instance for the same content as adding and removing the
+     * same item from the this map might produce a different instance with the same content.
+     *
+     * This operation is O(1) and does not involve a physically copying the map. It instead
+     * returns the underlying immutable map used internally to store the content of the map.
+     *
+     * It is recommended to use [toMap] when using returning the value of this map from
+     * [androidx.compose.runtime.snapshotFlow].
+     */
+    fun toMap(): Map<K, V> = readable.map
+
     override val size get() = readable.map.size
     override fun containsKey(key: K) = readable.map.containsKey(key)
     override fun containsValue(value: V) = readable.map.containsValue(value)
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
index b3cb799..d03fa3f 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
@@ -600,6 +600,25 @@
         }
     }
 
+    @Test
+    fun currentValueOfTheList() {
+        val list = mutableStateListOf<Int>()
+        val lists = mutableListOf<List<Int>>()
+        repeat(100) {
+            Snapshot.withMutableSnapshot {
+                list.add(it)
+                lists.add(list.toList())
+            }
+        }
+        repeat(100) { index ->
+            val current = lists[index]
+            assertEquals(index + 1, current.size)
+            current.forEachIndexed { i, value ->
+                assertEquals(i, value)
+            }
+        }
+    }
+
     private fun <T> validate(list: MutableList<T>, block: (list: MutableList<T>) -> Unit) {
         val normalList = list.toMutableList()
         block(normalList)
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
index 5e51bb1..70d93d7 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
@@ -494,6 +494,25 @@
     }
 
     @Test
+    fun currentValueOfTheMap() {
+        val map = mutableStateMapOf<Int, String>()
+        val maps = mutableListOf<Map<Int, String>>()
+        repeat(100) {
+            Snapshot.withMutableSnapshot {
+                map[it] = it.toString()
+                maps.add(map.toMap())
+            }
+        }
+        repeat(100) { index ->
+            val current = maps[index]
+            assertEquals(index + 1, current.size)
+            repeat(index) {
+                assertEquals(current[it], it.toString())
+            }
+        }
+    }
+
+    @Test
     @IgnoreJsTarget
     @OptIn(ExperimentalCoroutinesApi::class)
     fun concurrentModificationInGlobal_put_new() = runTest {