Generate SSD truth index cache from typed Jerboa

ober

a606ced144b0bafb966c95572a34486623051a45

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 351708c..6618052 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -15582,6 +15582,9 @@
                 truthStoreEnsureStorageCapacityLocal
                 truthStoreLoadRemoteConfigLocal
                 truthStoreRemoteUrlLocal
+                truthStoreInvalidateTruthIndexLocal
+                truthStoreTruthIndexEntriesLocal
+                truthStoreTruthIndexEntryLocal
                 truthStoreReadResponseTextLocal
                 truthStoreWriteRemoteTruthLocal
                 truthStoreApplyLearnedGuessesLocal
@@ -15620,6 +15623,7 @@
         (type SsdSession)
         (type SharedPreferences)
         (type StorageStats)
+        (type TruthIndexEntry)
         (type TruthStore)
         (type URL)
         (type JSONArray)
@@ -15653,6 +15657,20 @@
         (extern (truthStoreReviewsDir
                   (store : TruthStore)) : File
           (kotlin-member-get reviewsDir))
+        (extern (truthStoreTruthIndexCacheLoaded
+                  (store : TruthStore)) : Bool
+          (kotlin-member-get truthIndexCacheLoaded))
+        (extern (truthStoreTruthIndexCacheLoadedSet
+                  (store : TruthStore)
+                  (loaded : Bool)) : Unit
+          (kotlin-member-set truthIndexCacheLoaded))
+        (extern (truthStoreTruthIndexCache
+                  (store : TruthStore)) : (MutableList TruthIndexEntry)
+          (kotlin-member-get truthIndexCache))
+        (extern (truthStoreTruthIndexCacheSet
+                  (store : TruthStore)
+                  (entries : (MutableList TruthIndexEntry))) : Unit
+          (kotlin-member-set truthIndexCache))
         (extern (truthStoreChildFile
                   (parent : File)
                   (name : String)) : File
@@ -16299,7 +16317,106 @@
                   session
                   (learnedExamplesFromDocument
                     (jsonObjectFromText
-                      (truthStoreReadLocalText file))))))))
+                    (truthStoreReadLocalText file))))))))
+        (def (truthStoreInvalidateTruthIndexLocal
+               (store : TruthStore)) : Unit
+          (begin
+            (truthStoreTruthIndexCacheLoadedSet store #f)
+            (truthStoreTruthIndexCacheSet
+              store
+              (mutable-list-empty TruthIndexEntry))))
+        (def (truthStoreTruthIndexFileBefore?
+               (candidate : File)
+               (existing : File)) : Bool
+          (< (string-compare-to
+               (truthStoreFileName candidate)
+               (truthStoreFileName existing))
+             (int32 0)))
+        (def (truthStoreTruthIndexInsertIndex
+               (sorted : (MutableList File))
+               (file : File)) : Int32
+          (for/fold ((found (int32 -1)))
+                    ((i (in-range (int32 0) (list-size sorted))))
+            (if (>= found (int32 0))
+              found
+              (if (truthStoreTruthIndexFileBefore? file (list-ref sorted i))
+                i
+                found))))
+        (def (truthStoreTruthIndexInsertSorted
+               (sorted : (MutableList File))
+               (file : File)) : (MutableList File)
+          (let ((insertAt (truthStoreTruthIndexInsertIndex sorted file)))
+            (if (< insertAt (int32 0))
+              (begin
+                (mutable-list-add! sorted file)
+                sorted)
+              (let ((out (mutable-list-empty File)))
+                (begin
+                  (for/fold ((ignored (int32 0)))
+                            ((i (in-range (int32 0) (list-size sorted))))
+                    (begin
+                      (if (= i insertAt)
+                        (begin
+                          (mutable-list-add! out file)
+                          (mutable-list-add! out (list-ref sorted i)))
+                        (mutable-list-add! out (list-ref sorted i)))
+                      ignored))
+                  out)))))
+        (def (truthStoreSortedTruthIndexFiles
+               (store : TruthStore)) : (MutableList File)
+          (let ((files
+                  (truthStoreListFiles
+                    (truthStoreGroundTruthDir store))))
+            (if (nullable-null? files)
+              (mutable-list-empty File)
+              (for/fold ((sorted (mutable-list-empty File)))
+                        ((i (in-range
+                              (int32 0)
+                              (list-size (nullable-get files)))))
+                (let ((file (list-ref (nullable-get files) i)))
+                  (if (truthJsonFileName (truthStoreFileName file))
+                    (truthStoreTruthIndexInsertSorted sorted file)
+                    sorted))))))
+        (def (truthStoreTruthIndexEntryLocal
+               (store : TruthStore)
+               (file : File)) : (Nullable TruthIndexEntry)
+          (if (fileIsNotRegular file)
+            (nullable-none TruthIndexEntry)
+            (try
+              (let ((truth
+                      (jsonObjectFromText
+                        (truthStoreReadLocalText file))))
+                (truthIndexEntryFromJson
+                  file
+                  truth
+                  (nullableByteCountOrDefault
+                    (truthStoreTruthTimeLocal truth)
+                    (truthStoreFileLastModified file))))
+              (catch (error : Exception)
+                (nullable-none TruthIndexEntry)))))
+        (def (truthStoreBuildTruthIndexEntries
+               (store : TruthStore)) : (MutableList TruthIndexEntry)
+          (let ((files (truthStoreSortedTruthIndexFiles store)))
+            (for/fold ((entries (mutable-list-empty TruthIndexEntry)))
+                      ((i (in-range (int32 0) (list-size files))))
+              (let ((entry
+                      (truthStoreTruthIndexEntryLocal
+                        store
+                        (list-ref files i))))
+                (begin
+                  (if (truthIndexEntryPresent entry)
+                    (mutable-list-add! entries (nullable-get entry))
+                    (begin))
+                  entries)))))
+        (def (truthStoreTruthIndexEntriesLocal
+               (store : TruthStore)) : (MutableList TruthIndexEntry)
+          (if (truthStoreTruthIndexCacheLoaded store)
+            (truthStoreTruthIndexCache store)
+            (let ((entries (truthStoreBuildTruthIndexEntries store)))
+              (begin
+                (truthStoreTruthIndexCacheSet store entries)
+                (truthStoreTruthIndexCacheLoadedSet store #t)
+                entries))))
         (def (truthStoreSeedBundledTruthLocal
                (store : TruthStore)
                (context : Context)) : Int32
@@ -16897,8 +17014,8 @@
        "    internal val reviewsDir = File(root, \"reviews\")"
        "    private val remoteConfig: RemoteConfig? by lazy { loadRemoteConfig() }"
        "    @Volatile internal var seedStarted = false"
-       "    @Volatile private var truthIndexCacheLoaded = false"
-       "    @Volatile private var truthIndexCache: List<TruthIndexEntry> = emptyList()"
+       "    @Volatile internal var truthIndexCacheLoaded = false"
+       "    @Volatile internal var truthIndexCache: MutableList<TruthIndexEntry> = ArrayList()"
        ""
        "    init {"
        "        ensureTruthStoreDirectories(root, groundTruthDir, learnedDir, eventsDir, reviewsDir)"
@@ -16921,35 +17038,15 @@
        "    }"
        ""
        "    @Synchronized"
-       "    internal fun invalidateTruthIndex() {"
-       "        truthIndexCacheLoaded = false"
-       "        truthIndexCache = emptyList()"
-       "    }"
+       "    internal fun invalidateTruthIndex() ="
+       "        truthStoreInvalidateTruthIndexLocal(this)"
        ""
        "    @Synchronized"
-       "    private fun truthIndexEntries(): List<TruthIndexEntry> {"
-       "        if (truthIndexCacheLoaded) return truthIndexCache"
-       "        val entries = if (fileListFilesPresent(groundTruthDir)) {"
-       "            checkNotNull(groundTruthDir.listFiles { f -> truthJsonFileName(f.name) })"
-       "                .sortedBy { it.name }"
-       "                .mapNotNull { truthIndexEntry(it) }"
-       "        } else {"
-       "            emptyList()"
-       "        }"
-       "        truthIndexCache = entries"
-       "        truthIndexCacheLoaded = true"
-       "        return entries"
-       "    }"
+       "    private fun truthIndexEntries(): List<TruthIndexEntry> ="
+       "        truthStoreTruthIndexEntriesLocal(this)"
        ""
-       "    private fun truthIndexEntry(file: File): TruthIndexEntry? {"
-       "        if (fileIsNotRegular(file)) return null"
-       "        return try {"
-       "            val truth = jsonObjectFromText(readLocalText(file))"
-       "            truthIndexEntryFromJson(file, truth, nullableByteCountOrDefault(truthTime(truth), file.lastModified()))"
-       "        } catch (_: Exception) {"
-       "            null"
-       "        }"
-       "    }"
+       "    private fun truthIndexEntry(file: File): TruthIndexEntry? ="
+       "        truthStoreTruthIndexEntryLocal(this, file)"
        ""
        "    fun saveSession(session: SsdSession): File ="
        "        truthStoreSaveSession(this, session)"