/*
* 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.intentresolver.util
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.yield
/** Like [Iterable.map] but executes each [block] invocation in a separate coroutine. */
suspend fun Iterable.mapParallel(
parallelism: Int? = null,
block: suspend (A) -> B,
): List =
parallelism?.let { permits ->
withSemaphore(permits = permits) { mapParallel { withPermit { block(it) } } }
}
?: mapParallel(block)
/** Like [Iterable.map] but executes each [block] invocation in a separate coroutine. */
suspend fun Sequence.mapParallel(
parallelism: Int? = null,
block: suspend (A) -> B,
): List = asIterable().mapParallel(parallelism, block)
private suspend fun Iterable.mapParallel(block: suspend (A) -> B): List =
coroutineScope {
map {
async {
yield()
block(it)
}
}
.awaitAll()
}
suspend fun Iterable.mapParallelIndexed(
parallelism: Int? = null,
block: suspend (Int, A) -> B,
): List =
parallelism?.let { permits ->
withSemaphore(permits = permits) {
mapParallelIndexed { idx, item -> withPermit { block(idx, item) } }
}
} ?: mapParallelIndexed(block)
private suspend fun Iterable.mapParallelIndexed(block: suspend (Int, A) -> B): List =
coroutineScope {
mapIndexed { index, item ->
async {
yield()
block(index, item)
}
}
.awaitAll()
}