1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.intentresolver.util
18 
19 import kotlinx.coroutines.async
20 import kotlinx.coroutines.awaitAll
21 import kotlinx.coroutines.coroutineScope
22 import kotlinx.coroutines.sync.withPermit
23 import kotlinx.coroutines.yield
24 
25 /** Like [Iterable.map] but executes each [block] invocation in a separate coroutine. */
26 suspend fun <A, B> Iterable<A>.mapParallel(
27     parallelism: Int? = null,
28     block: suspend (A) -> B,
29 ): List<B> =
30     parallelism?.let { permits ->
31         withSemaphore(permits = permits) { mapParallel { withPermit { block(it) } } }
32     }
33         ?: mapParallel(block)
34 
35 /** Like [Iterable.map] but executes each [block] invocation in a separate coroutine. */
mapParallelnull36 suspend fun <A, B> Sequence<A>.mapParallel(
37     parallelism: Int? = null,
38     block: suspend (A) -> B,
39 ): List<B> = asIterable().mapParallel(parallelism, block)
40 
41 private suspend fun <A, B> Iterable<A>.mapParallel(block: suspend (A) -> B): List<B> =
42     coroutineScope {
43         map {
44                 async {
45                     yield()
46                     block(it)
47                 }
48             }
49             .awaitAll()
50     }
51 
mapParallelIndexednull52 suspend fun <A, B> Iterable<A>.mapParallelIndexed(
53     parallelism: Int? = null,
54     block: suspend (Int, A) -> B,
55 ): List<B> =
56     parallelism?.let { permits ->
57         withSemaphore(permits = permits) {
58             mapParallelIndexed { idx, item -> withPermit { block(idx, item) } }
59         }
60     } ?: mapParallelIndexed(block)
61 
mapParallelIndexednull62 private suspend fun <A, B> Iterable<A>.mapParallelIndexed(block: suspend (Int, A) -> B): List<B> =
63     coroutineScope {
64         mapIndexed { index, item ->
65                 async {
66                     yield()
67                     block(index, item)
68                 }
69             }
70             .awaitAll()
71     }
72