Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec30de26 authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Add CopyOnLoopListenerSet which may be faster" into main

parents 25479482 315db32e
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 com.android.systemui.util

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class CopyOnLoopListenerSetTest : ListenerSetTest() {
    override fun makeRunnableListenerSet(): IListenerSet<Runnable> = CopyOnLoopListenerSet()
}
+21 −26
Original line number Diff line number Diff line
@@ -168,15 +168,14 @@ open class ListenerSetTest : SysuiTestCase() {
        // Setup and preconditions
        val runnablesCalled = mutableListOf<Int>()
        // runnable1 is configured to remove itself
        val runnable1 = object : Runnable {
        val runnable1 =
            object : Runnable {
                override fun run() {
                    runnableSet.remove(this)
                    runnablesCalled.add(1)
                }
            }
        val runnable2 = Runnable {
            runnablesCalled.add(2)
        }
        val runnable2 = Runnable { runnablesCalled.add(2) }
        assertThat(runnableSet).isEmpty()
        runnableSet.addIfAbsent(runnable1)
        runnableSet.addIfAbsent(runnable2)
@@ -194,17 +193,13 @@ open class ListenerSetTest : SysuiTestCase() {
    fun addIfAbsent_isReentrantSafe() {
        // Setup and preconditions
        val runnablesCalled = mutableListOf<Int>()
        val runnable99 = Runnable {
            runnablesCalled.add(99)
        }
        val runnable99 = Runnable { runnablesCalled.add(99) }
        // runnable1 is configured to add runnable99
        val runnable1 = Runnable {
            runnableSet.addIfAbsent(runnable99)
            runnablesCalled.add(1)
        }
        val runnable2 = Runnable {
            runnablesCalled.add(2)
        }
        val runnable2 = Runnable { runnablesCalled.add(2) }
        assertThat(runnableSet).isEmpty()
        runnableSet.addIfAbsent(runnable1)
        runnableSet.addIfAbsent(runnable2)
+0 −0

File moved.

+46 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 com.android.systemui.util

/**
 * A collection of listeners, observers, callbacks, etc.
 *
 * This container is optimized for frequent mutation and infrequent iteration, with reentrant-safety
 * guarantees but without thread-safety guarantees. Specifically, to ensure that
 * [ConcurrentModificationException] is not thrown when listeners mutate the set, this iterator will
 * not reflect changes made to the set after the iterator is constructed.
 */
class CopyOnLoopListenerSet<E : Any>
/** Private constructor takes the internal list so that we can use auto-delegation */
private constructor(private val listeners: ArrayList<E>) :
    Collection<E> by listeners, IListenerSet<E> {

    /** Create a new instance */
    constructor() : this(ArrayList())

    @Suppress("UNCHECKED_CAST")
    override fun iterator(): Iterator<E> = listeners.toArray().iterator() as Iterator<E>

    override fun addIfAbsent(element: E): Boolean =
        if (element in listeners) {
            false
        } else {
            listeners.add(element)
        }

    override fun remove(element: E): Boolean = listeners.remove(element)
}