From cf179f6dde9967e89d2ab2ee4d3e8ab4afe91ce1 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:50:41 +0000 Subject: [PATCH] storing the trie and the dict, should be much faster idk if ts acc helped tho --- StickerSlack/Emoji/EmojiHoarder.swift | 39 +++++++++++++++++++++++---- StickerSlack/Trie/Trie.swift | 16 +++++------ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/StickerSlack/Emoji/EmojiHoarder.swift b/StickerSlack/Emoji/EmojiHoarder.swift index cf3c225..aea5900 100644 --- a/StickerSlack/Emoji/EmojiHoarder.swift +++ b/StickerSlack/Emoji/EmojiHoarder.swift @@ -14,6 +14,8 @@ import Haptics class EmojiHoarder: ObservableObject { static let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.neon443.StickerSlack")!.appendingPathComponent("Library", conformingTo: .directory) nonisolated static let localEmojiDB: URL = EmojiHoarder.container.appendingPathComponent("_localEmojiDB.json", conformingTo: .fileURL) + nonisolated static let localTrie: URL = EmojiHoarder.container.appendingPathComponent("_localTrie.json", conformingTo: .fileURL) + nonisolated static let localTrieDict: URL = EmojiHoarder.container.appendingPathComponent("_localTrieDict.json", conformingTo: .fileURL) private let endpoint: URL = URL(string: "https://cachet.dunkirk.sh/emojis")! private let encoder = JSONEncoder() private let decoder = JSONDecoder() @@ -28,10 +30,11 @@ class EmojiHoarder: ObservableObject { init(localOnly: Bool = false, skipIndex: Bool = false) { let localDB = loadLocalDB() withAnimation { self.emojis = localDB } + loadTrie() if !skipIndex { buildTrie() } guard !localOnly else { return } - Task.detached { + Task { print("start loading remote db") await self.loadRemoteDB() print("end") @@ -69,22 +72,48 @@ class EmojiHoarder: ObservableObject { downloadedEmojis = [] } + func saveTrie() { + guard let data = try? encoder.encode(trie.root) else { + fatalError("failed to encode trie") + } + try! data.write(to: EmojiHoarder.localTrie) + + guard let dataDict = try? encoder.encode(trie.dict) else { + fatalError("failed to encode trie dict") + } + try! dataDict.write(to: EmojiHoarder.localTrieDict) + } + + func loadTrie() { + guard FileManager.default.fileExists(atPath: EmojiHoarder.localTrie.path) else { return } + guard let data = try? Data(contentsOf: EmojiHoarder.localTrie) else { return } + guard let decoded = try? decoder.decode(TrieNode.self, from: data) else { + fatalError("failed to decode trie") + } + self.trie.root = decoded + + guard FileManager.default.fileExists(atPath: EmojiHoarder.localTrieDict.path) else { return } + guard let dataDict = try? Data(contentsOf: EmojiHoarder.localTrieDict) else { return } + guard let decodedDict = try? decoder.decode([String:Emoji].self, from: dataDict) else { + fatalError("failed to decode dict") + } + self.trie.dict = decodedDict + } + func buildTrie() { let start = Date().timeIntervalSince1970 - trie.root = TrieNode() for emoji in emojis { trie.insert(word: emoji.name) } buildTrieDict() + saveTrie() print("done building trie in", Date().timeIntervalSince1970-start) } func buildTrieDict() { - var dict: [String:Emoji] = [:] for emoji in emojis { - dict[emoji.name] = emoji + trie.dict[emoji.name] = emoji } - self.trie.dict = dict buildDownloadedEmojis() } diff --git a/StickerSlack/Trie/Trie.swift b/StickerSlack/Trie/Trie.swift index 4a620ba..002b653 100644 --- a/StickerSlack/Trie/Trie.swift +++ b/StickerSlack/Trie/Trie.swift @@ -9,14 +9,14 @@ import Foundation import SwiftUI import Combine -class TrieNode: ObservableObject { - @Published var children: [Character: TrieNode] = [:] - @Published var isEndOfWord: Bool = false +class TrieNode: Codable { + var children: [String: TrieNode] = [:] + var isEndOfWord: Bool = false } class Trie: ObservableObject { - @Published var root: TrieNode = TrieNode() - @Published var dict: [String:Emoji] = [:] + var root: TrieNode = TrieNode() + var dict: [String:Emoji] = [:] func insert(word: String) { let word = word.lowercased() @@ -25,7 +25,7 @@ class Trie: ObservableObject { let last = indices.last for i in indices { - let char = word[i] + let char = String(word[i]) if let node = currentNode.children[char] { currentNode = node } else { @@ -42,7 +42,7 @@ class Trie: ObservableObject { var currentNode = root for char in query.lowercased() { - if let node = currentNode.children[char] { + if let node = currentNode.children[String(char)] { currentNode = node } else { return false @@ -57,7 +57,7 @@ class Trie: ObservableObject { var currentNode = root for char in prefixQuery { - guard let child = currentNode.children[char] else { + guard let child = currentNode.children[String(char)] else { return [] } currentNode = child