diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt index a513bedc8..147c00dd7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentSkipListMap import java.util.function.BiConsumer class LargeSoftCache : CacheOperations { - private val cache = ConcurrentSkipListMap>() + protected val cache = ConcurrentSkipListMap>() fun keys() = cache.keys @@ -125,6 +125,14 @@ class LargeSoftCache : CacheOperations { cache.forEach(BiConsumerWrapper(this, consumer)) } + override fun forEach( + from: K, + to: K, + consumer: BiConsumer, + ) { + cache.subMap(from, to).forEach(BiConsumerWrapper(this, consumer)) + } + class BiConsumerWrapper( val cache: LargeSoftCache, val inner: BiConsumer, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCacheAddressExt.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCacheAddressExt.kt new file mode 100644 index 000000000..f60d69d8c --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCacheAddressExt.kt @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.model + +import com.vitorpamplona.quartz.nip01Core.core.Address +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.utils.cache.CacheCollectors + +const val START_KEY = "0000000000000000000000000000000000000000000000000000000000000000" + +fun kindStart( + kind: Int, + pubKey: HexKey, +) = Address(kind, pubKey, "") + +fun kindEnd( + kind: Int, + pubKey: HexKey, +) = Address(kind + 1, pubKey, "") + +fun kindStart(kind: Int) = kindStart(kind, START_KEY) + +fun kindEnd(kind: Int) = kindEnd(kind + 1, START_KEY) + +fun LargeSoftCache.filterIntoSet( + kind: Int, + consumer: CacheCollectors.BiFilter, +): Set = filterIntoSet(kindStart(kind), kindEnd(kind), consumer) + +fun LargeSoftCache.filterIntoSet( + kinds: List, + consumer: CacheCollectors.BiFilter, +): Set { + val set = mutableSetOf() + kinds.forEach { + set.addAll(filterIntoSet(kindStart(it), kindEnd(it), consumer)) + } + return set +} + +fun LargeSoftCache.filterIntoSet( + kind: Int, + pubKey: HexKey, + consumer: CacheCollectors.BiFilter, +): Set = filterIntoSet(kindStart(kind, pubKey), kindEnd(kind, pubKey), consumer) + +fun LargeSoftCache.mapNotNullIntoSet( + kind: Int, + consumer: CacheCollectors.BiMapper, +): Set = mapNotNullIntoSet(kindStart(kind), kindEnd(kind), consumer) + +fun LargeSoftCache.mapNotNullIntoSet( + kind: Int, + pubKey: HexKey, + consumer: CacheCollectors.BiMapper, +): Set = mapNotNullIntoSet(kindStart(kind, pubKey), kindEnd(kind, pubKey), consumer) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt index 3438293de..bff05caa9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt @@ -22,7 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.LocalCache.notes import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.FilterByListParams @@ -45,13 +47,11 @@ open class DiscoverLongFormFeedFilter( override fun feed(): List { val params = buildFilterParams(account) - val notes = - LocalCache.addressables.filterIntoSet { _, it -> + LocalCache.addressables.filterIntoSet(LongTextNoteEvent.KIND) { _, it -> val noteEvent = it.event noteEvent is LongTextNoteEvent && params.match(noteEvent) } - return sort(notes) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt index 01fc98a7e..a6fc6c050 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.FilterByListParams @@ -45,7 +46,7 @@ open class DiscoverFollowSetsFeedFilter( val params = buildFilterParams(account) val notes = - LocalCache.addressables.filterIntoSet { _, it -> + LocalCache.addressables.filterIntoSet(FollowListEvent.KIND) { _, it -> val noteEvent = it.event noteEvent is FollowListEvent && params.match(noteEvent) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt index eb649fe22..e0648c72f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.mapNotNullIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.FilterByListParams import com.vitorpamplona.quartz.nip01Core.core.Address @@ -54,7 +55,7 @@ open class DiscoverCommunityFeedFilter( // Here we only need to look for CommunityDefinition Events val notes = - LocalCache.addressables.mapNotNullIntoSet { key, note -> + LocalCache.addressables.mapNotNullIntoSet(CommunityDefinitionEvent.KIND) { key, note -> val noteEvent = note.event if (noteEvent == null && shouldInclude(key, filterParams, note.relays)) { // send unloaded communities to the screen diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt index 1731d7248..276a55743 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt @@ -24,6 +24,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ParticipantListBuilder +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsByProxyTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.author.AuthorsByOutboxTopNavFilter @@ -55,7 +56,7 @@ open class DiscoverNIP89FeedFilter( override fun feed(): List { val notes = - LocalCache.addressables.filterIntoSet { _, it -> + LocalCache.addressables.filterIntoSet(AppDefinitionEvent.KIND) { _, it -> acceptDVM(it) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt index 7386a6904..a4c16b9e3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.FilterByListParams import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent @@ -46,7 +47,7 @@ open class DiscoverMarketplaceFeedFilter( val params = buildFilterParams(account) val notes = - LocalCache.addressables.filterIntoSet { _, it -> + LocalCache.addressables.filterIntoSet(ClassifiedsEvent.KIND) { _, it -> val noteEvent = it.event noteEvent is ClassifiedsEvent && noteEvent.isWellFormed() && params.match(noteEvent) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt index d9026aa88..21364ee0e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.dal import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent @@ -39,7 +40,7 @@ class DraftEventsFeedFilter( override fun feed(): List { val drafts = - LocalCache.addressables.filterIntoSet { _, note -> + LocalCache.addressables.filterIntoSet(DraftWrapEvent.KIND, account.userProfile().pubkeyHex) { _, note -> acceptableEvent(note) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt index 1f9b199ee..be69e6a00 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter @@ -45,6 +46,17 @@ import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent class HomeNewThreadFeedFilter( val account: Account, ) : AdditiveFeedFilter() { + companion object { + val ADDRESSABLE_KINDS = + listOf( + AudioTrackEvent.KIND, + InteractiveStoryPrologueEvent.KIND, + WikiNoteEvent.KIND, + ClassifiedsEvent.KIND, + LongTextNoteEvent.KIND, + ) + } + override fun feedKey(): String = account.userProfile().pubkeyHex + "-" + account.settings.defaultHomeFollowList.value override fun showHiddenKey(): Boolean = @@ -67,7 +79,9 @@ class HomeNewThreadFeedFilter( } val longFormNotes = - LocalCache.addressables.filterIntoSet { _, note -> + LocalCache.addressables.filterIntoSet( + kinds = ADDRESSABLE_KINDS, + ) { _, note -> acceptableEvent(note, filterParams) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt index 1f80d5230..ed5a07640 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt @@ -24,9 +24,11 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.FilterByListParams +import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent import com.vitorpamplona.quartz.experimental.forks.forkFromVersion import com.vitorpamplona.quartz.experimental.forks.isForkFromAddressWithPubkey import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent @@ -37,6 +39,7 @@ import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip22Comments.CommentEvent +import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent @@ -47,6 +50,11 @@ import com.vitorpamplona.quartz.nip47WalletConnect.LnZapPaymentResponseEvent import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent +import com.vitorpamplona.quartz.nip52Calendar.CalendarDateSlotEvent +import com.vitorpamplona.quartz.nip52Calendar.CalendarRSVPEvent +import com.vitorpamplona.quartz.nip52Calendar.CalendarTimeSlotEvent +import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent +import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip58Badges.BadgeDefinitionEvent @@ -58,10 +66,25 @@ import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryRequestEvent import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent import com.vitorpamplona.quartz.nip90Dvms.NIP90StatusEvent +import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent class NotificationFeedFilter( val account: Account, ) : AdditiveFeedFilter() { + companion object { + val ADDRESSABLE_KINDS = + listOf( + AudioTrackEvent.KIND, + WikiNoteEvent.KIND, + ClassifiedsEvent.KIND, + LongTextNoteEvent.KIND, + CalendarTimeSlotEvent.KIND, + CalendarDateSlotEvent.KIND, + CalendarRSVPEvent.KIND, + LiveActivitiesEvent.KIND, + ) + } + override fun feedKey(): String = account.userProfile().pubkeyHex + "-" + account.settings.defaultNotificationFollowList.value override fun showHiddenKey(): Boolean = @@ -83,7 +106,7 @@ class NotificationFeedFilter( LocalCache.notes.filterIntoSet { _, note -> note.event !is AddressableEvent && acceptableEvent(note, filterParams) } + - LocalCache.addressables.filterIntoSet { _, note -> + LocalCache.addressables.filterIntoSet(ADDRESSABLE_KINDS) { _, note -> acceptableEvent(note, filterParams) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt index fc20626e1..92671a5dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt @@ -24,7 +24,9 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.LocalCache.notes import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.filterIntoSet import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.FilterByListParams @@ -67,7 +69,10 @@ class VideoFeedFilter( LocalCache.notes.filterIntoSet { _, it -> acceptableEvent(it, params) } + - LocalCache.addressables.filterIntoSet { _, it -> + LocalCache.addressables.filterIntoSet(VideoHorizontalEvent.KIND) { _, it -> + acceptableEvent(it, params) + } + + LocalCache.addressables.filterIntoSet(VideoVerticalEvent.KIND) { _, it -> acceptableEvent(it, params) } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt index ec4a93d4b..882253488 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt @@ -70,6 +70,108 @@ interface ICacheOperations { fun associateWith(transform: (K, V) -> U?): Map + // -- + // Sub map operations + // -- + + fun filter( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): List + + fun filterIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): Set + + fun map( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): List + + fun mapNotNull( + from: K, + to: K, + consumer: CacheCollectors.BiMapper, + ): List + + fun mapNotNullIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiMapper, + ): Set + + fun mapFlatten( + from: K, + to: K, + consumer: CacheCollectors.BiMapper?>, + ): List + + fun mapFlattenIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiMapper?>, + ): Set + + fun maxOrNullOf( + from: K, + to: K, + filter: CacheCollectors.BiFilter, + comparator: Comparator, + ): V? + + fun sumOf( + from: K, + to: K, + consumer: CacheCollectors.BiSumOf, + ): Int + + fun sumOfLong( + from: K, + to: K, + consumer: CacheCollectors.BiSumOfLong, + ): Long + + fun groupBy( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): Map> + + fun countByGroup( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): Map + + fun sumByGroup( + from: K, + to: K, + groupMap: CacheCollectors.BiNotNullMapper, + sumOf: CacheCollectors.BiNotNullMapper, + ): Map + + fun count( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): Int + + fun associate( + from: K, + to: K, + transform: (K, V) -> Pair, + ): Map + + fun associateWith( + from: K, + to: K, + transform: (K, V) -> U?, + ): Map + fun joinToString( separator: CharSequence = ", ", prefix: CharSequence = "", diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt index 00a51c43f..35a44cd1f 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt @@ -36,6 +36,12 @@ class MyBiConsumer( interface CacheOperations : ICacheOperations { fun forEach(consumer: BiConsumer) + fun forEach( + from: K, + to: K, + consumer: BiConsumer, + ) + override fun size(): Int override fun forEach(consumer: ICacheBiConsumer) { @@ -144,6 +150,171 @@ interface CacheOperations : ICacheOperations { return runner.results } + // ---- + // submap operations + // ---- + override fun filter( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): List { + val runner = BiFilterCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun filterIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): Set { + val runner = BiFilterUniqueCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun map( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): List { + val runner = BiNotNullMapCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun mapNotNull( + from: K, + to: K, + consumer: CacheCollectors.BiMapper, + ): List { + val runner = BiMapCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun mapNotNullIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiMapper, + ): Set { + val runner = BiMapUniqueCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun mapFlatten( + from: K, + to: K, + consumer: CacheCollectors.BiMapper?>, + ): List { + val runner = BiMapFlattenCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun mapFlattenIntoSet( + from: K, + to: K, + consumer: CacheCollectors.BiMapper?>, + ): Set { + val runner = BiMapFlattenUniqueCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun maxOrNullOf( + from: K, + to: K, + filter: CacheCollectors.BiFilter, + comparator: Comparator, + ): V? { + val runner = BiMaxOfCollector(filter, comparator) + forEach(from, to, runner) + return runner.maxV + } + + override fun sumOf( + from: K, + to: K, + consumer: CacheCollectors.BiSumOf, + ): Int { + val runner = BiSumOfCollector(consumer) + forEach(from, to, runner) + return runner.sum + } + + override fun sumOfLong( + from: K, + to: K, + consumer: CacheCollectors.BiSumOfLong, + ): Long { + val runner = BiSumOfLongCollector(consumer) + forEach(from, to, runner) + return runner.sum + } + + override fun groupBy( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): Map> { + val runner = BiGroupByCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun countByGroup( + from: K, + to: K, + consumer: CacheCollectors.BiNotNullMapper, + ): Map { + val runner = BiCountByGroupCollector(consumer) + forEach(from, to, runner) + return runner.results + } + + override fun sumByGroup( + from: K, + to: K, + groupMap: CacheCollectors.BiNotNullMapper, + sumOf: CacheCollectors.BiNotNullMapper, + ): Map { + val runner = BiSumByGroupCollector(groupMap, sumOf) + forEach(from, to, runner) + return runner.results + } + + override fun count( + from: K, + to: K, + consumer: CacheCollectors.BiFilter, + ): Int { + val runner = BiCountIfCollector(consumer) + forEach(from, to, runner) + return runner.count + } + + override fun associate( + from: K, + to: K, + transform: (K, V) -> Pair, + ): Map { + val runner = BiAssociateCollector(size(), transform) + forEach(from, to, runner) + return runner.results + } + + override fun associateWith( + from: K, + to: K, + transform: (K, V) -> U?, + ): Map { + val runner = BiAssociateWithCollector(size(), transform) + forEach(from, to, runner) + return runner.results + } + override fun joinToString( separator: CharSequence, prefix: CharSequence, diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt index 6a430bb86..c175ada41 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt @@ -79,4 +79,12 @@ actual class LargeCache : CacheOperations { override fun forEach(consumer: BiConsumer) { cache.forEach(consumer) } + + override fun forEach( + from: K, + to: K, + consumer: BiConsumer, + ) { + cache.subMap(from, to).forEach(consumer) + } }