diff --git a/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift b/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift index 1b1e8a02..afda1f2a 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift @@ -223,34 +223,6 @@ extension Array where Element == Megrez.Compositor.Node { } return counter } - - public func findNode(at cursor: Int, target outCursorPastNode: inout Int) -> Megrez.Compositor.Node? { - guard !isEmpty else { return nil } - let cursor = Swift.max(0, Swift.min(cursor, keys.count)) - - if cursor == 0, let theFirst = first { - outCursorPastNode = theFirst.spanLength - return theFirst - } - - // 同時應對「游標在右端」與「游標離右端還差一個位置」的情形。 - if cursor >= keys.count - 1, let theLast = last { - outCursorPastNode = keys.count - return theLast - } - - var accumulated = 0 - for neta in self { - accumulated += neta.spanLength - if accumulated > cursor { - outCursorPastNode = accumulated - return neta - } - } - - // 下述情形本不應該出現。 - return nil - } } // MARK: - Private Methods diff --git a/Source/Modules/LanguageParsers/Megrez/1_Compositor.swift b/Source/Modules/LanguageParsers/Megrez/1_Compositor.swift index 9d0be506..078fdf97 100644 --- a/Source/Modules/LanguageParsers/Megrez/1_Compositor.swift +++ b/Source/Modules/LanguageParsers/Megrez/1_Compositor.swift @@ -13,7 +13,7 @@ extension Megrez { /// 簡單的貝氏推論:因為底層的語言模組只會提供單元圖資料。一旦將所有可以組字的單元圖 /// 作為節點塞到組字器內,就可以用一個簡單的有向無環圖爬軌過程、來利用這些隱性資料值 /// 算出最大相似估算結果。 - public class Compositor { + public struct Compositor { /// 就文字輸入方向而言的方向。 public enum TypingDirection { case front, rear } /// 軌格增減行為。 @@ -51,7 +51,7 @@ extension Megrez { self.separator = separator } - public func clear() { + public mutating func clear() { cursor = 0 keys.removeAll() spans.removeAll() @@ -62,7 +62,7 @@ extension Megrez { /// 在游標位置插入給定的索引鍵。 /// - Parameter key: 要插入的索引鍵。 /// - Returns: 該操作是否成功執行。 - @discardableResult public func insertKey(_ key: String) -> Bool { + @discardableResult public mutating func insertKey(_ key: String) -> Bool { guard !key.isEmpty, key != separator, langModel.hasUnigramsFor(key: key) else { return false } keys.insert(key, at: cursor) resizeGrid(at: cursor, do: .expand) @@ -77,7 +77,7 @@ extension Megrez { /// 如果是朝著與文字輸入方向相反的方向砍的話,游標位置會自動遞減。 /// - Parameter direction: 指定方向(相對於文字輸入方向而言)。 /// - Returns: 該操作是否成功執行。 - @discardableResult public func dropKey(direction: TypingDirection) -> Bool { + @discardableResult public mutating func dropKey(direction: TypingDirection) -> Bool { let isBackSpace: Bool = direction == .rear ? true : false guard cursor != (isBackSpace ? 0 : keys.count) else { return false } keys.remove(at: cursor - (isBackSpace ? 1 : 0)) @@ -90,7 +90,7 @@ extension Megrez { /// 按幅位來前後移動游標。 /// - Parameter direction: 移動方向。 /// - Returns: 該操作是否順利完成。 - @discardableResult public func jumpCursorBySpan(to direction: TypingDirection) -> Bool { + @discardableResult public mutating func jumpCursorBySpan(to direction: TypingDirection) -> Bool { switch direction { case .front: if cursor == width { return false } @@ -158,7 +158,7 @@ extension Megrez.Compositor { /// - Parameters: /// - location: 給定的幅位座標。 /// - action: 指定是擴張還是縮減一個幅位。 - func resizeGrid(at location: Int, do action: ResizeBehavior) { + mutating func resizeGrid(at location: Int, do action: ResizeBehavior) { let location = max(min(location, spans.count), 0) // 防呆 switch action { case .expand: @@ -255,7 +255,7 @@ extension Megrez.Compositor { } } - func updateCursorJumpingTables(_ walkedNodes: [Node]) { + mutating func updateCursorJumpingTables(_ walkedNodes: [Node]) { var cursorRegionMapDict = [Int: Int]() cursorRegionMapDict[-1] = 0 // 防呆 var counter = 0 diff --git a/Source/Modules/LanguageParsers/Megrez/2_Walker.swift b/Source/Modules/LanguageParsers/Megrez/2_Walker.swift index b7f4b091..385f837a 100644 --- a/Source/Modules/LanguageParsers/Megrez/2_Walker.swift +++ b/Source/Modules/LanguageParsers/Megrez/2_Walker.swift @@ -11,7 +11,7 @@ extension Megrez.Compositor { /// 對於 `G = (V, E)`,該算法的運行次數為 `O(|V|+|E|)`,其中 `G` 是一個有向無環圖。 /// 這意味著,即使軌格很大,也可以用很少的算力就可以爬軌。 /// - Returns: 爬軌結果+該過程是否順利執行。 - @discardableResult public func walk() -> ([Node], Bool) { + @discardableResult public mutating func walk() -> ([Node], Bool) { var result = [Node]() defer { walkedNodes = result diff --git a/Source/Modules/LanguageParsers/Megrez/3_Candidate.swift b/Source/Modules/LanguageParsers/Megrez/3_Candidate.swift index 2e57e6cd..2b1c46b5 100644 --- a/Source/Modules/LanguageParsers/Megrez/3_Candidate.swift +++ b/Source/Modules/LanguageParsers/Megrez/3_Candidate.swift @@ -144,13 +144,17 @@ extension Megrez.Compositor { guard let overridden = overridden else { return false } // 啥也不覆寫。 for i in overridden.spanIndex..bc」的爬軌途徑(尤其是當 A 和 B 使用「0」作為複寫數值的情況下)。這樣 /// 一來,「A-B」就不一定始終會是爬軌函式的青睞結果了。所以,這裡一定要用大於 0 的 /// 數(比如野獸常數),以讓「c」更容易單獨被選中。 - public static let kOverridingScore: Double = 114_514 + public var overridingScore: Double = 114_514 private(set) var key: String private(set) var keyArray: [String] @@ -81,7 +81,7 @@ extension Megrez.Compositor { public var score: Double { guard !unigrams.isEmpty else { return 0 } switch overrideType { - case .withHighScore: return Megrez.Compositor.Node.kOverridingScore + case .withHighScore: return overridingScore case .withTopUnigramScore: return unigrams[0].score default: return currentUnigram.score } @@ -139,4 +139,45 @@ extension Array where Element == Megrez.Compositor.Node { /// 從一個節點陣列當中取出目前的索引鍵陣列。 public var keys: [String] { map(\.key) } + + /// 在陣列內以給定游標位置找出對應的節點。 + /// - Parameters: + /// - cursor: 給定游標位置。 + /// - outCursorPastNode: 找出的節點的前端位置。 + /// - Returns: 查找結果。 + public func findNode(at cursor: Int, target outCursorPastNode: inout Int) -> Megrez.Compositor.Node? { + guard !isEmpty else { return nil } + let cursor = Swift.max(0, Swift.min(cursor, keys.count)) + + if cursor == 0, let theFirst = first { + outCursorPastNode = theFirst.spanLength + return theFirst + } + + // 同時應對「游標在右端」與「游標離右端還差一個位置」的情形。 + if cursor >= keys.count - 1, let theLast = last { + outCursorPastNode = keys.count + return theLast + } + + var accumulated = 0 + for neta in self { + accumulated += neta.spanLength + if accumulated > cursor { + outCursorPastNode = accumulated + return neta + } + } + + // 下述情形本不應該出現。 + return nil + } + + /// 在陣列內以給定游標位置找出對應的節點。 + /// - Parameter cursor: 給定游標位置。 + /// - Returns: 查找結果。 + public func findNode(at cursor: Int) -> Megrez.Compositor.Node? { + var useless = 0 + return findNode(at: cursor, target: &useless) + } }