Skip to content

Commit 1f14edb

Browse files
committed
Parallel operations on Arrays
1 parent 9432873 commit 1f14edb

19 files changed

+1080
-54
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ suspend fun <T, R> Iterable<T>.mapParallel(transform: (T) -> R): List<R> = corou
1111
Example of using the parallel *map* operation.
1212
```kotlin
1313
fun showCase() {
14-
var list = listOf(1,2,3)
14+
val list = listOf(1,2,3)
1515
runBlocking(Dispatchers.Default) {
1616
var mappedList = list.mapParallel { it * 2 } // Results in [2,4,6]
1717
}
@@ -47,7 +47,7 @@ allprojects {
4747
After that, include this line in your module build.gradle.
4848
```gradle
4949
dependencies {
50-
implementation 'com.github.cvb941:kotlin-parallel-collection-operations:1.1'
50+
implementation 'com.github.cvb941:kotlin-parallel-operations:1.2'
5151
}
5252
```
5353

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.lukaskusik.coroutines.transformations
2+
3+
fun <T> Array<T>.mapInPlace(transform: (T) -> T): Array<T> {
4+
for (i in this.indices) this[i] = transform(this[i])
5+
return this
6+
}
7+
8+
fun ByteArray.mapInPlace(transform: (Byte) -> Byte): ByteArray {
9+
for (i in this.indices) this[i] = transform(this[i])
10+
return this
11+
}
12+
13+
fun ShortArray.mapInPlace(transform: (Short) -> Short): ShortArray {
14+
for (i in this.indices) this[i] = transform(this[i])
15+
return this
16+
}
17+
18+
fun IntArray.mapInPlace(transform: (Int) -> Int): IntArray {
19+
for (i in this.indices) this[i] = transform(this[i])
20+
return this
21+
}
22+
23+
fun LongArray.mapInPlace(transform: (Long) -> Long): LongArray {
24+
for (i in this.indices) this[i] = transform(this[i])
25+
return this
26+
}
27+
28+
fun FloatArray.mapInPlace(transform: (Float) -> Float): FloatArray {
29+
for (i in this.indices) this[i] = transform(this[i])
30+
return this
31+
}
32+
33+
fun DoubleArray.mapInPlace(transform: (Double) -> Double): DoubleArray {
34+
for (i in this.indices) this[i] = transform(this[i])
35+
return this
36+
}
37+
38+
fun BooleanArray.mapInPlace(transform: (Boolean) -> Boolean): BooleanArray {
39+
for (i in this.indices) this[i] = transform(this[i])
40+
return this
41+
}

transformations/src/main/kotlin/com/lukaskusik/coroutines/transformations/ParallelMap.kt

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,76 @@ suspend fun <T, R> Iterable<T>.mapParallel(
1212
map { async { transform(it) } }.map { it.await() }
1313
}
1414

15+
//region Arrays
1516
/**
16-
* Performs map transformation on the iterable using coroutines.
17-
* The chunkSize parameter is used to run multiple transformations on a single coroutine.
18-
*
19-
* @param chunkSize Size of each sub-collection that will be reduced in each coroutine.
17+
* Performs map transformation on the array using coroutines.
2018
*/
21-
suspend fun <T, R> Iterable<T>.mapParallelChunked(
22-
chunkSize: Int,
19+
suspend fun <T, R> Array<out T>.mapParallel(
2320
transform: (T) -> R
2421
): List<R> = coroutineScope {
25-
chunked(chunkSize).map { subChunk ->
26-
async {
27-
subChunk.map(transform)
28-
}
29-
}.flatMap {
30-
it.await()
31-
}
22+
map { async { transform(it) } }.map { it.await() }
3223
}
3324

3425
/**
35-
* Performs map transformation on the iterable using coroutines.
36-
*
37-
* It can split the collection into multiple chunks using the chunksCount parameter.
38-
* Each chunk will then run on a single coroutine, minimizing thread management, etc.
39-
* The default and recommended chunksCount for multithreading is the number of CPU threads, e.g. 4 or 8.
40-
*
41-
* @param chunksCount How many chunks should the collection be split into. Defaults to the number of available processors.
42-
*
43-
*/
44-
suspend fun <T, E> Collection<T>.mapParallelChunked(
45-
chunksCount: Int = Runtime.getRuntime().availableProcessors(),
46-
transform: (T) -> E
47-
): List<E> {
48-
val chunkSize = Math.ceil(size / chunksCount.toDouble()).toInt()
49-
return asIterable().mapParallelChunked(chunkSize, transform)
50-
}
26+
* Performs map transformation on the array using coroutines.
27+
*/
28+
suspend fun <R> ByteArray.mapParallel(
29+
transform: (Byte) -> R
30+
): List<R> = coroutineScope {
31+
map { async { transform(it) } }.map { it.await() }
32+
}
33+
34+
/**
35+
* Performs map transformation on the array using coroutines.
36+
*/
37+
suspend fun <R> ShortArray.mapParallel(
38+
transform: (Short) -> R
39+
): List<R> = coroutineScope {
40+
map { async { transform(it) } }.map { it.await() }
41+
}
42+
43+
/**
44+
* Performs map transformation on the array using coroutines.
45+
*/
46+
suspend fun <R> IntArray.mapParallel(
47+
transform: (Int) -> R
48+
): List<R> = coroutineScope {
49+
map { async { transform(it) } }.map { it.await() }
50+
}
51+
52+
/**
53+
* Performs map transformation on the array using coroutines.
54+
*/
55+
suspend fun <R> LongArray.mapParallel(
56+
transform: (Long) -> R
57+
): List<R> = coroutineScope {
58+
map { async { transform(it) } }.map { it.await() }
59+
}
60+
61+
/**
62+
* Performs map transformation on the array using coroutines.
63+
*/
64+
suspend fun <R> FloatArray.mapParallel(
65+
transform: (Float) -> R
66+
): List<R> = coroutineScope {
67+
map { async { transform(it) } }.map { it.await() }
68+
}
69+
70+
/**
71+
* Performs map transformation on the array using coroutines.
72+
*/
73+
suspend fun <R> DoubleArray.mapParallel(
74+
transform: (Double) -> R
75+
): List<R> = coroutineScope {
76+
map { async { transform(it) } }.map { it.await() }
77+
}
78+
79+
/**
80+
* Performs map transformation on the array using coroutines.
81+
*/
82+
suspend fun <R> BooleanArray.mapParallel(
83+
transform: (Boolean) -> R
84+
): List<R> = coroutineScope {
85+
map { async { transform(it) } }.map { it.await() }
86+
}
87+
//endregion
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.lukaskusik.coroutines.transformations
2+
3+
import kotlinx.coroutines.async
4+
import kotlinx.coroutines.coroutineScope
5+
6+
/**
7+
* Performs map transformation on the iterable using coroutines.
8+
* The chunkSize parameter is used to run multiple transformations on a single coroutine.
9+
*
10+
* @param chunkSize Size of each sub-collection that will be reduced in each coroutine.
11+
*/
12+
suspend fun <T, R> Iterable<T>.mapParallelChunked(
13+
chunkSize: Int,
14+
transform: (T) -> R
15+
): List<R> = coroutineScope {
16+
chunked(chunkSize).map { subChunk ->
17+
async {
18+
subChunk.map(transform)
19+
}
20+
}.flatMap {
21+
it.await()
22+
}
23+
}
24+
25+
/**
26+
* Performs map transformation on the collection using coroutines.
27+
*
28+
* It can split the collection into multiple chunks using the chunksCount parameter.
29+
* Each chunk will then run on a single coroutine, minimizing thread management, etc.
30+
* The default and recommended chunksCount for multithreading is the number of CPU threads, e.g. 4 or 8.
31+
*
32+
* @param chunksCount How many chunks should the collection be split into. Defaults to the number of available processors.
33+
*
34+
*/
35+
suspend fun <T, E> Collection<T>.mapParallelChunked(
36+
chunksCount: Int = Runtime.getRuntime().availableProcessors(),
37+
transform: (T) -> E
38+
): List<E> {
39+
val chunkSize = Math.ceil(size / chunksCount.toDouble()).toInt()
40+
return asIterable().mapParallelChunked(chunkSize, transform)
41+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.lukaskusik.coroutines.transformations
2+
3+
import kotlinx.coroutines.async
4+
import kotlinx.coroutines.coroutineScope
5+
import kotlinx.coroutines.launch
6+
7+
8+
/**
9+
* Performs in place map transformation on the array using coroutines.
10+
*/
11+
suspend fun <T> Array<T>.mapInPlaceParallel(
12+
transform: (T) -> T
13+
): Array<T> = coroutineScope {
14+
for (i in indices) {
15+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
16+
}
17+
this@mapInPlaceParallel
18+
}
19+
20+
21+
/**
22+
* Performs in place map transformation on the array using coroutines.
23+
*/
24+
suspend fun ByteArray.mapInPlaceParallel(
25+
transform: (Byte) -> Byte
26+
): ByteArray = coroutineScope {
27+
for (i in indices) {
28+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
29+
}
30+
this@mapInPlaceParallel
31+
}
32+
33+
34+
/**
35+
* Performs in place map transformation on the array using coroutines.
36+
*/
37+
suspend fun ShortArray.mapInPlaceParallel(
38+
transform: (Short) -> Short
39+
): ShortArray = coroutineScope {
40+
for (i in indices) {
41+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
42+
}
43+
this@mapInPlaceParallel
44+
}
45+
46+
/**
47+
* Performs in place map transformation on the array using coroutines.
48+
*/
49+
suspend fun IntArray.mapInPlaceParallel(
50+
transform: (Int) -> Int
51+
): IntArray = coroutineScope {
52+
for (i in indices) {
53+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
54+
}
55+
this@mapInPlaceParallel
56+
}
57+
58+
/**
59+
* Performs in place map transformation on the array using coroutines.
60+
*/
61+
suspend fun LongArray.mapInPlaceParallel(
62+
transform: (Long) -> Long
63+
): LongArray = coroutineScope {
64+
for (i in indices) {
65+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
66+
}
67+
this@mapInPlaceParallel
68+
}
69+
70+
/**
71+
* Performs in place map transformation on the array using coroutines.
72+
*/
73+
suspend fun FloatArray.mapInPlaceParallel(
74+
transform: (Float) -> Float
75+
): FloatArray = coroutineScope {
76+
for (i in indices) {
77+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
78+
}
79+
this@mapInPlaceParallel
80+
}
81+
82+
/**
83+
* Performs in place map transformation on the array using coroutines.
84+
*/
85+
suspend fun DoubleArray.mapInPlaceParallel(
86+
transform: (Double) -> Double
87+
): DoubleArray = coroutineScope {
88+
for (i in indices) {
89+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
90+
}
91+
this@mapInPlaceParallel
92+
}
93+
94+
/**
95+
* Performs in place map transformation on the array using coroutines.
96+
*/
97+
suspend fun BooleanArray.mapInPlaceParallel(
98+
transform: (Boolean) -> Boolean
99+
): BooleanArray = coroutineScope {
100+
for (i in indices) {
101+
launch { this@mapInPlaceParallel[i] = transform(this@mapInPlaceParallel[i]) }
102+
}
103+
this@mapInPlaceParallel
104+
}

0 commit comments

Comments
 (0)