Use a cache for Sones’ names
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 18 Oct 2017 05:51:14 +0000 (07:51 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 18 Oct 2017 14:09:54 +0000 (16:09 +0200)
src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt

diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt
new file mode 100644 (file)
index 0000000..bd67ae2
--- /dev/null
@@ -0,0 +1,12 @@
+package net.pterodactylus.sone.utils
+
+class Memoize<in T, out R>(private val calc: (T) -> R) : (T) -> R {
+
+       private val values = mutableMapOf<T, R>()
+
+       override fun invoke(value: T) =
+                       values.getOrPut(value, { calc(value) })
+
+}
+
+fun <T, R> ((T) -> R).memoize(): (T) -> R = Memoize(this)
index 577ea90..f296e03 100644 (file)
@@ -9,6 +9,7 @@ import net.pterodactylus.sone.data.PostReply
 import net.pterodactylus.sone.data.Sone
 import net.pterodactylus.sone.utils.Pagination
 import net.pterodactylus.sone.utils.emptyToNull
+import net.pterodactylus.sone.utils.memoize
 import net.pterodactylus.sone.utils.paginate
 import net.pterodactylus.sone.utils.parameters
 import net.pterodactylus.sone.web.WebInterface
@@ -53,14 +54,15 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web
                        }
                }
 
+               val soneNameCache = { sone: Sone -> sone.names() }.memoize()
                val sonePagination = webInterface.core.sones
-                               .scoreAndPaginate(phrases) { it.allText() }
+                               .scoreAndPaginate(phrases) { it.allText(soneNameCache) }
                                .apply { page = freenetRequest.parameters["sonePage"].emptyToNull?.toIntOrNull() ?: 0 }
                val postPagination = cache.get(phrases) {
                        webInterface.core.sones
                                        .flatMap(Sone::getPosts)
                                        .filter { Post.FUTURE_POSTS_FILTER.apply(it) }
-                                       .scoreAndPaginate(phrases) { it.allText() }
+                                       .scoreAndPaginate(phrases) { it.allText(soneNameCache) }
                }.apply { page = freenetRequest.parameters["postPage"].emptyToNull?.toIntOrNull() ?: 0 }
 
                Logger.normal(SearchPage::class.java, "Finished search for “${freenetRequest.parameters["query"]}” in ${System.currentTimeMillis() - startTime}ms.")
@@ -78,17 +80,19 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web
                                        .paginate(webInterface.core.preferences.postsPerPage)
 
        private fun Sone.names() =
-                       listOf(name, profile.firstName, profile.middleName, profile.lastName)
-                                       .filterNotNull()
-                                       .joinToString("")
+                       with(profile) {
+                               listOf(name, firstName, middleName, lastName)
+                                               .filterNotNull()
+                                               .joinToString("")
+                       }
 
-       private fun Sone.allText() =
-                       (names() + profile.fields.map { "${it.name} ${it.value}" }.joinToString(" ", " ")).toLowerCase()
+       private fun Sone.allText(soneNameCache: (Sone) -> String) =
+                       (soneNameCache(this) + profile.fields.map { "${it.name} ${it.value}" }.joinToString(" ", " ")).toLowerCase()
 
-       private fun Post.allText() =
-                       (text + recipient.orNull()?.let { " ${it.names()}" } + webInterface.core.getReplies(id)
+       private fun Post.allText(soneNameCache: (Sone) -> String) =
+                       (text + recipient.orNull()?.let { " ${soneNameCache(it)}" } + webInterface.core.getReplies(id)
                                        .filter { PostReply.FUTURE_REPLY_FILTER.apply(it) }
-                                       .map { "${it.sone.names()} ${it.text}" }.joinToString(" ", " ")).toLowerCase()
+                                       .map { "${soneNameCache(it.sone)} ${it.text}" }.joinToString(" ", " ")).toLowerCase()
 
        private fun score(text: String, phrases: Iterable<Phrase>): Double {
                val requiredPhrases = phrases.count { it.required }