<commit_before>/*
 * Copyright (c) 2018. <NAME>
 *
 * 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 splitties.lifecycle.coroutines

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import java.util.concurrent.ConcurrentHashMap

/**
 * Returns a [CoroutineScope] that uses [Dispatchers.Main] by default, and that is cancelled when
 * the [Lifecycle] reaches [Lifecycle.State.DESTROYED] state.
 *
 * Note that this value is cached until the Lifecycle reaches the destroyed state.
 */
val Lifecycle.coroutineScope: CoroutineScope
    get() = cachedLifecycleCoroutineScopes[this] ?: job.let { job ->
        val newScope = CoroutineScope(job + Dispatchers.Main)
        if (job.isActive) {
            cachedLifecycleCoroutineScopes[this] = newScope
            job.invokeOnCompletion { _ -> cachedLifecycleCoroutineScopes -= this }
        }
        newScope
    }

/**
 * Calls [Lifecycle.coroutineScope] for the [Lifecycle] of this [LifecycleOwner].
 *
 * This is an inline property, just there for convenient usage from any [LifecycleOwner],
 * like FragmentActivity, AppCompatActivity, Fragment and LifecycleService.
 */
inline val LifecycleOwner.coroutineScope get() = lifecycle.coroutineScope

/**
 * Returns a [SupervisorJob] that will be cancelled as soon as the [Lifecycle] reaches
 * [Lifecycle.State.DESTROYED] state.
 *
 * Note that this value is cached until the Lifecycle reaches the destroyed state.
 *
 * You can use this job for custom [CoroutineScope]s, or as a parent [Job].
 */
val Lifecycle.job: Job
    get() = cachedLifecycleJobs[this] ?: createJob().also {
        if (it.isActive) {
            cachedLifecycleJobs[this] = it
            it.invokeOnCompletion { _ -> cachedLifecycleJobs -= this }
        }
    }

private val cachedLifecycleJobs = ConcurrentHashMap<Lifecycle, Job>()
private val cachedLifecycleCoroutineScopes = ConcurrentHashMap<Lifecycle, CoroutineScope>()<commit_msg>Optimize coroutines scopes for main thread usage<commit_after>/*
 * Copyright (c) 2018. <NAME>
 *
 * 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 splitties.lifecycle.coroutines

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import splitties.mainthread.isMainThread
import java.util.concurrent.ConcurrentHashMap

/**
 * Returns a [CoroutineScope] that uses [Dispatchers.Main] by default, and that is cancelled when
 * the [Lifecycle] reaches [Lifecycle.State.DESTROYED] state.
 *
 * Note that this value is cached until the Lifecycle reaches the destroyed state.
 */
val Lifecycle.coroutineScope: CoroutineScope
    get() = cachedLifecycleCoroutineScopes.let { cache ->
        cache[this] ?: job.let { job ->
            val newScope = CoroutineScope(job + Dispatchers.Main)
            if (job.isActive) {
                cache[this] = newScope
                job.invokeOnCompletion { _ -> cache -= this }
            }
            newScope
        }
    }

/**
 * Calls [Lifecycle.coroutineScope] for the [Lifecycle] of this [LifecycleOwner].
 *
 * This is an inline property, just there for convenient usage from any [LifecycleOwner],
 * like FragmentActivity, AppCompatActivity, Fragment and LifecycleService.
 */
inline val LifecycleOwner.coroutineScope get() = lifecycle.coroutineScope

/**
 * Returns a [SupervisorJob] that will be cancelled as soon as the [Lifecycle] reaches
 * [Lifecycle.State.DESTROYED] state.
 *
 * Note that this value is cached until the Lifecycle reaches the destroyed state.
 *
 * You can use this job for custom [CoroutineScope]s, or as a parent [Job].
 */
val Lifecycle.job: Job
    get() = cachedLifecycleJobs.let { cache ->
        cache[this] ?: createJob().also {
            if (it.isActive) {
                cache[this] = it
                it.invokeOnCompletion { _ -> cache -= this }
            }
        }
    }

private inline val cachedLifecycleJobs: MutableMap<Lifecycle, Job>
    get() = if (isMainThread) mainThreadJobs else anyThreadJobs
private inline val cachedLifecycleCoroutineScopes: MutableMap<Lifecycle, CoroutineScope>
    get() = if (isMainThread) mainThreadScopes else anyThreadScopes

private val mainThreadJobs = mutableMapOf<Lifecycle, Job>()
private val mainThreadScopes = mutableMapOf<Lifecycle, CoroutineScope>()

private val anyThreadJobs = ConcurrentHashMap<Lifecycle, Job>()
private val anyThreadScopes = ConcurrentHashMap<Lifecycle, CoroutineScope>()
{'fraction_non_alphanumeric': 0.08429520811472543, 'fraction_numerical': 0.0027981811822315496, 'mean_word_length': 3.8018471872376156, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4674823', 'n_tokens_mistral': 1610, 'n_tokens_neox': 1612, 'n_words': 535}