-
Couldn't load subscription status.
- Fork 3
cache rewrite #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
HopeBaron
wants to merge
14
commits into
main
Choose a base branch
from
api
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
cache rewrite #11
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
1f38c59
cache rewrite? [Needs folder restructure]
HopeBaron 92006dd
yeet these suspends
HopeBaron aeee531
Add implementations
HopeBaron 01d98ad
Stately Concurrent Map
HopeBaron e5672d6
optimizations
HopeBaron 6b704e0
remove old discard logic
HopeBaron 4d569b2
apply factory and discard -> remove changes
HopeBaron c648eb5
rename get and remove toMap call
HopeBaron dbe4d50
restructure cache interfaces
HopeBaron e58e3a7
what about this?
HopeBaron c65823a
changes
HopeBaron ad761b5
no intermediate collections please.
HopeBaron 828be4c
Sequence Instead of Flow
HopeBaron 5187036
why call entries?
HopeBaron File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
api/src/commonMain/kotlin/dev/kord/cache/api/observables/BasicRelation.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package dev.kord.cache.api.observables | ||
|
|
||
| class BasicRelation<T: Any> : Relation<T> { | ||
| private val relations = mutableSetOf<RelationHandler<T, Any>>() | ||
| private val caches = mutableSetOf<Cache<*, *>>() | ||
|
|
||
| override suspend fun remove(value: T) { | ||
| relations.onEach { relatesTo -> | ||
| caches.onEach { other -> other.removeAny { friend -> relatesTo(value, friend) } } | ||
| } | ||
| } | ||
|
|
||
| override suspend fun <R : Any> to(cache: Cache<*, R>, handler: RelationHandler<T, R>) { | ||
| caches.add(cache) | ||
| relations.add(safe(handler)) | ||
| } | ||
|
|
||
| private fun <R: Any> safe(relationHandler: RelationHandler<T, R>): RelationHandler<T, Any> { | ||
| return obj@{ value: T, friend: Any -> | ||
| @Suppress("UNCHECKED_CAST") | ||
| val safeCast = friend as? R | ||
| safeCast != null && relationHandler(value, safeCast) | ||
| } | ||
| } | ||
| } |
59 changes: 59 additions & 0 deletions
59
api/src/commonMain/kotlin/dev/kord/cache/api/observables/Cache.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package dev.kord.cache.api.observables | ||
|
|
||
| import kotlinx.coroutines.flow.Flow | ||
|
|
||
| /** | ||
| * A cache for a map of entries where each [Value] is associated with a unique [Key]. | ||
| * */ | ||
| interface Cache<Key : Any, Value : Any> { | ||
|
|
||
| /** | ||
| * Returns the value associated with the given [key] in the cache, or null if no such entry exists. | ||
| */ | ||
| suspend fun get(key: Key): Value? | ||
|
|
||
| /** | ||
| * Removes the entry associated with the given [key] from the cache, if it exists. | ||
| */ | ||
| suspend fun remove(key: Key) | ||
|
|
||
| /** | ||
| * Filters [Value]s by the given [predicate] | ||
| * Returns a lazy [Flow] of [Value]s | ||
| */ | ||
| suspend fun filter(predicate: (Value) -> Boolean): Sequence<Value> | ||
|
|
||
| /** | ||
| * Sets the [value] into the cache associated with a [key]. | ||
| * @param key The key to associate the [value] with. | ||
| * @param value The value to be cached. | ||
| */ | ||
| suspend fun set(key: Key, value: Value) | ||
|
|
||
| /** | ||
| * Returns the first value that satisfies the given [predicate] function, or null if none is found. | ||
| * @param predicate A function that takes a [Value] and returns a boolean. | ||
| * @return The first value that satisfies the [predicate] function, or null if none is found. | ||
| */ | ||
| public suspend fun firstOrNull(predicate: (Value) -> Boolean): Value? | ||
|
|
||
| /** | ||
| * Removes any entry in the cache which matches the given [predicate]. | ||
| * @param predicate The predicate to match each [Value] against. | ||
| */ | ||
| public suspend fun removeAny(predicate: (Value) -> Boolean) | ||
|
|
||
| /** | ||
| * Removes all entries in the cache. | ||
| */ | ||
| public suspend fun removeAll() | ||
|
|
||
| /** | ||
| * Adds an observer cache to this cache. Whenever a value is removed from this cache, the | ||
| * observer cache will also remove any values that are related to it. | ||
| * @param other The observer cache. | ||
| * @param handler A [RelationHandler] that specifies how to remove related values from the observer cache. | ||
| */ | ||
| public suspend fun <R: Any> relatesTo(other: Cache<*, R>, handler: RelationHandler<Value, R>) | ||
|
|
||
| } |
85 changes: 85 additions & 0 deletions
85
api/src/commonMain/kotlin/dev/kord/cache/api/observables/ConcurrentCache.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| package dev.kord.cache.api.observables | ||
|
|
||
| import co.touchlab.stately.collections.ConcurrentMutableMap | ||
|
|
||
| /** | ||
| * An implementation of the [Cache] with [ConcurrentMutableMap]. | ||
| * This implementation is thread-safe. | ||
| * | ||
| * @param relation The relation between this cache and other caches, used to remove related entries. | ||
| */ | ||
| public class ConcurrentCache<Key: Any, Value : Any>( | ||
| public val relation: Relation<Value>, | ||
| ) : Cache<Key, Value> { | ||
|
|
||
| private val source: ConcurrentMutableMap<Key, Value> = ConcurrentMutableMap() | ||
|
|
||
| /** | ||
| * Gets the value associated with the given [key]. | ||
| * | ||
| * @return The value associated with the given [key], or `null` if not found. | ||
| */ | ||
| override suspend fun get(key: Key): Value? { | ||
| return source[key] | ||
| } | ||
|
|
||
| /** | ||
| * Gets the first value that matches the [predicate] function. | ||
| * | ||
| * @return The first value that matches the [predicate] function, or `null` if not found. | ||
| */ | ||
| override suspend fun firstOrNull(predicate: (Value) -> Boolean): Value? { | ||
| return source.values.firstOrNull(predicate) | ||
| } | ||
|
|
||
| /** | ||
| * removes all values that match the [predicate] function. | ||
| * | ||
| * @param predicate The function used to determine which values to remove. | ||
| */ | ||
| override suspend fun removeAny(predicate: (Value) -> Boolean) { | ||
| source.asSequence() | ||
| .filter { (_, value) -> predicate(value) } | ||
| .forEach { (key, _) -> remove(key) } | ||
| } | ||
|
|
||
| override suspend fun filter(predicate: (Value) -> Boolean): Sequence<Value> = | ||
| source.asSequence() | ||
| .filter { (_, value) -> predicate(value) } | ||
| .map { it.value } | ||
|
|
||
|
|
||
| /** | ||
| * removes the value associated with the given [key]. | ||
| * | ||
| * @return The value associated with the given [key], or `null` if not found. | ||
| */ | ||
| override suspend fun remove(key: Key) { | ||
| val value = source[key] ?: return | ||
| relation.remove(value) | ||
| source.remove(key) | ||
| } | ||
|
|
||
| override suspend fun set(key: Key, value: Value) { | ||
| source[key] = value | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * removes all entries from this cache. | ||
| */ | ||
| override suspend fun removeAll() { | ||
| val iterator = source.iterator() | ||
| while (iterator.hasNext()) { | ||
| val (_, value) = iterator.next() | ||
| relation.remove(value) | ||
| iterator.remove() | ||
| } | ||
| } | ||
|
|
||
|
|
||
| override suspend fun <R : Any> relatesTo(other: Cache<*, R>, handler: RelationHandler<Value, R>) { | ||
| relation.to(other, handler) | ||
| } | ||
|
|
||
| } |
35 changes: 35 additions & 0 deletions
35
api/src/commonMain/kotlin/dev/kord/cache/api/observables/Relation.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package dev.kord.cache.api.observables | ||
|
|
||
| /** | ||
| * A typealias for a function that determines the relationship between two entities of type `T` and `R` | ||
| * in a uni-directional link. | ||
| * The `value` parameter represents the entity of type `T` and the `friend` parameter represents the entity of type `R`. | ||
| * The function should return `true` if the two entities are related, or `false` otherwise. | ||
| */ | ||
| public typealias RelationHandler<T, R> = (value: T, friend: R) -> Boolean | ||
|
|
||
| /** | ||
| * A `Relation` is a uni-directional link between two entities of type `T` and `R`. | ||
| * A `Relation` is defined by a set of `RelationHandler`s which determine the relationship | ||
| * between two entities. | ||
| * | ||
| * @param T the type of the first entity in the relation. | ||
| */ | ||
| public interface Relation<T: Any> { | ||
|
|
||
| /** | ||
| * Removes the given [value] from all caches related to this relation. | ||
| * | ||
| * @param value the entity to remove from the relation. | ||
| */ | ||
| public suspend fun remove(value: T) | ||
|
|
||
|
|
||
| /** | ||
| * Associates an [Cache] of type `T` with this relation. | ||
| * | ||
| * @param cache the cache to associate with this relation. | ||
| * @param handler the `RelationHandler` that defines the relationship between entities of type `T` and `R`. | ||
| */ | ||
| public suspend fun <R: Any> to(cache: Cache<*, R>, handler: RelationHandler<T, R>) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to be a public interface now? it's no longer exposed by the other public interfaces so it could now just be an implementation detail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be provided to customize the deletion process.
I've already added it to the implementation
What do you suggest we do with this one?