Skip to content

Commit

Permalink
SwiftFormat // Fix configuration file.
Browse files Browse the repository at this point in the history
  • Loading branch information
ShikiSuen committed Jun 13, 2024
1 parent a4376d4 commit 43e1207
Show file tree
Hide file tree
Showing 11 changed files with 467 additions and 266 deletions.
11 changes: 8 additions & 3 deletions .swiftformat.json → .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ redundantRawValues, \
redundantType, \
redundantVoidReturnType, \
semicolons, \
sortedImports, \
sortedSwitchCases, \
sortImports, \
sortSwitchCases, \
spaceAroundBraces, \
spaceAroundBrackets, \
spaceAroundComments, \
Expand Down Expand Up @@ -101,4 +101,9 @@ strongifiedSelf

--exclude Pods,**/UNTESTED_TODO,vendor,fastlane

# https://github.com/NoemiRozpara/Google-SwiftFormat-Config
# https://github.com/NoemiRozpara/Google-SwiftFormat-Config

# vChewing-specific settings:

--disable preferForLoop

151 changes: 87 additions & 64 deletions Sources/Megrez/1_Compositor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)

public extension Megrez {
// MARK: - Megrez.Compositor

extension Megrez {
/// 一個組字器用來在給定一系列的索引鍵的情況下(藉由一系列的觀測行為)返回一套資料值。
///
/// 用於輸入法的話,給定的索引鍵可以是注音、且返回的資料值都是漢語字詞組合。該組字器
Expand All @@ -13,15 +15,50 @@ public extension Megrez {
/// 簡單的貝氏推論:因為底層的語言模組只會提供單元圖資料。一旦將所有可以組字的單元圖
/// 作為節點塞到組字器內,就可以用一個簡單的有向無環圖爬軌過程、來利用這些隱性資料值
/// 算出最大相似估算結果。
struct Compositor {
public struct Compositor {
// MARK: Lifecycle

/// 初期化一個組字器。
/// - Parameter langModel: 要對接的語言模組。
public init(with langModel: LangModelProtocol, separator: String = "-") {
self.langModel = .init(withLM: langModel)
self.separator = separator
}

/// 以指定組字器生成拷貝。
/// - Remark: 因為 Node 不是 Struct,所以會在 Compositor 被拷貝的時候無法被真實複製。
/// 這樣一來,Compositor 複製品當中的 Node 的變化會被反應到原先的 Compositor 身上。
/// 這在某些情況下會造成意料之外的混亂情況,所以需要引入一個拷貝用的建構子。
public init(from target: Compositor) {
self.cursor = target.cursor
self.marker = target.marker
self.separator = target.separator
self.walkedNodes = target.walkedNodes.map(\.copy)
self.keys = target.keys
self.spans = target.spans.map(\.hardCopy)
self.langModel = target.langModel
}

// MARK: Public

/// 就文字輸入方向而言的方向。
public enum TypingDirection { case front, rear }
/// 軌格增減行為。
public enum ResizeBehavior { case expand, shrink }
/// 該軌格內可以允許的最大幅位長度。
public static var maxSpanLength: Int = 10 { didSet { maxSpanLength = max(6, maxSpanLength) } }

/// 多字讀音鍵當中用以分割漢字讀音的記號的預設值,是「-」。
public static var theSeparator: String = "-"

/// 該軌格內可以允許的最大幅位長度。
public static var maxSpanLength: Int = 10 { didSet { maxSpanLength = max(6, maxSpanLength) } }

/// 最近一次爬軌結果。
public var walkedNodes: [Node] = []
/// 該組字器已經插入的的索引鍵,以陣列的形式存放。
public private(set) var keys = [String]()
/// 該組字器的幅位單元陣列。
public private(set) var spans = [SpanUnit]()

/// 該組字器的敲字游標位置。
public var cursor: Int = 0 {
didSet {
Expand All @@ -39,51 +76,48 @@ public extension Megrez {
}
}

/// 最近一次爬軌結果。
public var walkedNodes: [Node] = []
/// 該組字器的長度,組字器內已經插入的單筆索引鍵的數量,也就是內建漢字讀音的數量(唯讀)。
/// - Remark: 理論上而言,spans.count 也是這個數。
/// 但是,為了防止萬一,就用了目前的方法來計算。
public var length: Int { keys.count }
/// 組字器是否為空。
public var isEmpty: Bool { spans.isEmpty && keys.isEmpty }

/// 該組字器已經插入的的索引鍵,以陣列的形式存放。
public private(set) var keys = [String]()
/// 該組字器的幅位單元陣列。
public private(set) var spans = [SpanUnit]()
/// 該組字器所使用的語言模型(被 LangModelRanked 所封裝)。
public var langModel: LangModelRanked {
didSet { clear() }
}

/// 初期化一個組字器。
/// - Parameter langModel: 要對接的語言模組。
public init(with langModel: LangModelProtocol, separator: String = "-") {
self.langModel = .init(withLM: langModel)
self.separator = separator
}

/// 以指定組字器生成拷貝。
/// - Remark: 因為 Node 不是 Struct,所以會在 Compositor 被拷貝的時候無法被真實複製。
/// 這樣一來,Compositor 複製品當中的 Node 的變化會被反應到原先的 Compositor 身上。
/// 這在某些情況下會造成意料之外的混亂情況,所以需要引入一個拷貝用的建構子。
public init(from target: Compositor) {
cursor = target.cursor
marker = target.marker
separator = target.separator
walkedNodes = target.walkedNodes.map(\.copy)
keys = target.keys
spans = target.spans.map(\.hardCopy)
langModel = target.langModel
}

/// 該組字器的硬拷貝。
/// - Remark: 因為 Node 不是 Struct,所以會在 Compositor 被拷貝的時候無法被真實複製。
/// 這樣一來,Compositor 複製品當中的 Node 的變化會被反應到原先的 Compositor 身上。
/// 這在某些情況下會造成意料之外的混亂情況,所以需要引入一個拷貝用的建構子。
public var hardCopy: Compositor { .init(from: self) }

/// 生成用以交給 GraphViz 診斷的資料檔案內容,純文字。
public var dumpDOT: String {
// C# StringBuilder 與 Swift NSMutableString 能提供爆發性的效能。
var strOutput = "digraph {\ngraph [ rankdir=LR ];\nBOS;\n"
spans.enumerated().forEach { p, span in
(0 ... span.maxLength).forEach { ni in
guard let np = span[ni] else { return }
if p == 0 { strOutput.append("BOS -> \(np.value);\n") }
strOutput.append("\(np.value);\n")
if (p + ni) < spans.count {
let destinationSpan = spans[p + ni]
(0 ... destinationSpan.maxLength).forEach { q in
guard let dn = destinationSpan[q] else { return }
strOutput.append(np.value + " -> " + dn.value + ";\n")
}
}
guard (p + ni) == spans.count else { return }
strOutput.append(np.value + " -> EOS;\n")
}
}
strOutput.append("EOS;\n}\n")
return strOutput.description
}

/// 重置包括游標在內的各項參數,且清空各種由組字器生成的內部資料。
///
/// 將已經被插入的索引鍵陣列與幅位單元陣列(包括其內的節點)全部清空。
Expand All @@ -99,8 +133,10 @@ public extension Megrez {
/// 在游標位置插入給定的索引鍵。
/// - Parameter key: 要插入的索引鍵。
/// - Returns: 該操作是否成功執行。
@discardableResult public mutating func insertKey(_ key: String) -> Bool {
guard !key.isEmpty, key != separator, langModel.hasUnigramsFor(keyArray: [key]) else { return false }
@discardableResult
public mutating func insertKey(_ key: String) -> Bool {
guard !key.isEmpty, key != separator,
langModel.hasUnigramsFor(keyArray: [key]) else { return false }
keys.insert(key, at: cursor)
let gridBackup = spans
resizeGrid(at: cursor, do: .expand)
Expand All @@ -120,7 +156,8 @@ public extension Megrez {
/// 如果是朝著與文字輸入方向相反的方向砍的話,游標位置會自動遞減。
/// - Parameter direction: 指定方向(相對於文字輸入方向而言)。
/// - Returns: 該操作是否成功執行。
@discardableResult public mutating 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))
Expand All @@ -142,9 +179,12 @@ public extension Megrez {
/// // 該特性不適用於小麥注音,除非小麥注音重新設計 InputState 且修改 KeyHandler、
/// 將標記游標交給敝引擎來管理。屆時,NSStringUtils 將徹底卸任。
/// - Returns: 該操作是否順利完成。
@discardableResult public mutating func jumpCursorBySpan(to direction: TypingDirection, isMarker: Bool = false)
-> Bool
{
@discardableResult
public mutating func jumpCursorBySpan(
to direction: TypingDirection,
isMarker: Bool = false
)
-> Bool {
var target = isMarker ? marker : cursor
switch direction {
case .front:
Expand All @@ -155,7 +195,10 @@ public extension Megrez {
guard let currentRegion = walkedNodes.cursorRegionMap[target] else { return false }

let aRegionForward = max(currentRegion - 1, 0)
let currentRegionBorderRear: Int = walkedNodes[0 ..< currentRegion].map(\.spanLength).reduce(0, +)
let currentRegionBorderRear: Int = walkedNodes[0 ..< currentRegion].map(\.spanLength).reduce(
0,
+
)
switch target {
case currentRegionBorderRear:
switch direction {
Expand All @@ -180,30 +223,6 @@ public extension Megrez {
}
return true
}

/// 生成用以交給 GraphViz 診斷的資料檔案內容,純文字。
public var dumpDOT: String {
// C# StringBuilder 與 Swift NSMutableString 能提供爆發性的效能。
var strOutput = "digraph {\ngraph [ rankdir=LR ];\nBOS;\n"
spans.enumerated().forEach { p, span in
(0 ... span.maxLength).forEach { ni in
guard let np = span[ni] else { return }
if p == 0 { strOutput.append("BOS -> \(np.value);\n") }
strOutput.append("\(np.value);\n")
if (p + ni) < spans.count {
let destinationSpan = spans[p + ni]
(0 ... destinationSpan.maxLength).forEach { q in
guard let dn = destinationSpan[q] else { return }
strOutput.append(np.value + " -> " + dn.value + ";\n")
}
}
guard (p + ni) == spans.count else { return }
strOutput.append(np.value + " -> EOS;\n")
}
}
strOutput.append("EOS;\n}\n")
return strOutput.description
}
}
}

Expand Down Expand Up @@ -284,9 +303,13 @@ extension Megrez.Compositor {
/// - Parameter updateExisting: 是否根據目前的語言模型的資料狀態來對既有節點更新其內部的單元圖陣列資料。
/// 該特性可以用於「在選字窗內屏蔽了某個詞之後,立刻生效」這樣的軟體功能需求的實現。
/// - Returns: 新增或影響了多少個節點。如果返回「0」則表示可能發生了錯誤。
@discardableResult public mutating func update(updateExisting: Bool = false) -> Int {
@discardableResult
public mutating func update(updateExisting: Bool = false) -> Int {
let maxSpanLength = Megrez.Compositor.maxSpanLength
let rangeOfPositions = max(0, cursor - maxSpanLength) ..< min(cursor + maxSpanLength, keys.count)
let rangeOfPositions = max(0, cursor - maxSpanLength) ..< min(
cursor + maxSpanLength,
keys.count
)
var nodesChanged = 0
rangeOfPositions.forEach { position in
let rangeOfLengths = 1 ... min(maxSpanLength, rangeOfPositions.upperBound - position)
Expand Down
5 changes: 3 additions & 2 deletions Sources/Megrez/2_Walker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)

public extension Megrez.Compositor {
extension Megrez.Compositor {
/// 爬軌函式,會更新當前組字器的 walkedNodes。
///
/// 找到軌格陣圖內權重最大的路徑。該路徑代表了可被觀測到的最可能的隱藏事件鏈。
Expand All @@ -17,7 +17,8 @@ public extension Megrez.Compositor {
/// 郭家寶(ByVoid)的《[基於統計語言模型的拼音輸入法](https://byvoid.com/zht/blog/slm_based_pinyin_ime/) 》;
/// 再後來則是 2022 年中時期劉燈的 Gramambular 2 組字引擎。
/// - Returns: 爬軌結果+該過程是否順利執行。
@discardableResult mutating func walk() -> [Megrez.Node] {
@discardableResult
public mutating func walk() -> [Megrez.Node] {
defer { Self.reinitVertexNetwork() }
walkedNodes.removeAll()
sortAndRelax()
Expand Down
Loading

0 comments on commit 43e1207

Please sign in to comment.