<commit_before>/*
 * Copyright 2019 Poly Forest, LLC
 *
 * 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.acornui.asset

import com.acornui.Disposable
import com.acornui.collection.MutableListIteratorImpl
import com.acornui.collection.stringMapOf
import com.acornui.di.Context
import com.acornui.di.ContextImpl
import com.acornui.di.DKey
import com.acornui.recycle.Clearable
import com.acornui.time.tick
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.jvm.Synchronized

/**
 * Cache is a map with reference counting. When the reference counter on a cached element reaches zero, if it remains
 * at zero for a certain number of frames, it will be removed and disposed.
 */
interface Cache : Clearable {

	fun containsKey(key: String): Boolean

	/**
	 * Retrieves the cache value for the given key.
	 * When cache items are retrieved, [refInc] should be used to indicate that it's in use.
	 */
	operator fun <T : Any> get(key: String): T?

	operator fun <T : Any> set(key: String, value: T)

	/**
	 * Retrieves the cache value for the given key if it exists. Otherwise, constructs a new value via the [factory]
	 * and adds the new value to the cache.
	 * @param key The key to use for the cache index.
	 * @return Returns the cached value.
	 */
	fun <T : Any> getOrPut(key: String, factory: () -> T): T {
		if (containsKey(key)) return get(key)!!
		val value = factory()
		set(key, value)
		return value
	}

	/**
	 * Decrements the use count for the cache value with the given key.
	 * If the use count reaches zero, and remains at zero for a certain number of frames, the cache value will be
	 * removed and disposed if the value implements [Disposable].
	 */
	fun refDec(key: String)

	/**
	 * Increments the reference count for the cache value. This should be paired with [refDec]
	 * @param key The cache key used in the lookup. If the key is not found, an exception is thrown.
	 *
	 * @see containsKey
	 */
	fun refInc(key: String)

	companion object : DKey<Cache> {

		override fun factory(context: Context): Cache? = CacheImpl()
	}
}

/**
 * A key-value store that keeps track of references. When references reach zero, and stay at zero for a certain number
 * of frames, the cached asset will be disposed.
 */
open class CacheImpl(

		/**
		 * The number of frames before an unreferenced cache item is removed and destroyed.
		 */
		private val gcFrames: Int = 500) : Cache {

	private val cache = stringMapOf<CacheValue>()

	private val deathPool = ArrayList<String>()<commit_msg>CacheImpl no longer open<commit_after>/*
 * Copyright 2019 Poly Forest, LLC
 *
 * 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.acornui.asset

import com.acornui.Disposable
import com.acornui.collection.MutableListIteratorImpl
import com.acornui.collection.stringMapOf
import com.acornui.di.Context
import com.acornui.di.ContextImpl
import com.acornui.di.DKey
import com.acornui.recycle.Clearable
import com.acornui.time.tick
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.jvm.Synchronized

/**
 * Cache is a map with reference counting. When the reference counter on a cached element reaches zero, if it remains
 * at zero for a certain number of frames, it will be removed and disposed.
 */
interface Cache : Clearable {

	fun containsKey(key: String): Boolean

	/**
	 * Retrieves the cache value for the given key.
	 * When cache items are retrieved, [refInc] should be used to indicate that it's in use.
	 */
	operator fun <T : Any> get(key: String): T?

	operator fun <T : Any> set(key: String, value: T)

	/**
	 * Retrieves the cache value for the given key if it exists. Otherwise, constructs a new value via the [factory]
	 * and adds the new value to the cache.
	 * @param key The key to use for the cache index.
	 * @return Returns the cached value.
	 */
	fun <T : Any> getOrPut(key: String, factory: () -> T): T {
		if (containsKey(key)) return get(key)!!
		val value = factory()
		set(key, value)
		return value
	}

	/**
	 * Decrements the use count for the cache value with the given key.
	 * If the use count reaches zero, and remains at zero for a certain number of frames, the cache value will be
	 * removed and disposed if the value implements [Disposable].
	 */
	fun refDec(key: String)

	/**
	 * Increments the reference count for the cache value. This should be paired with [refDec]
	 * @param key The cache key used in the lookup. If the key is not found, an exception is thrown.
	 *
	 * @see containsKey
	 */
	fun refInc(key: String)

	companion object : DKey<Cache> {

		override fun factory(context: Context): Cache? = CacheImpl()
	}
}

/**
 * A key-value store that keeps track of references. When references reach zero, and stay at zero for a certain number
 * of frames, the cached asset will be disposed.
 */
class CacheImpl(

		/**
		 * The number of frames before an unreferenced cache item is removed and destroyed.
		 */
		private val gcFrames: Int = 500
) : Cache {

	private val cache = stringMapOf<CacheValue>()

	private val deathPool = ArrayList<String>()
{'fraction_non_alphanumeric': 0.0839481882275783, 'fraction_numerical': 0.003607148712903755, 'mean_word_length': 3.699537750385208, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, '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': '3226043', 'n_tokens_mistral': 1817, 'n_tokens_neox': 1694, 'n_words': 795}