vChewing-macOS/Source/Modules/LanguageParsers/Megrez/6_Node.swift

206 lines
8.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Swiftified by (c) 2022 and onwards The vChewing Project (MIT License).
// Rebranded from (c) Lukhnos Liu's C++ library "Gramambular 2" (MIT License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
extension Megrez.Compositor {
///
///
///
///
/// 2
public class Node: Equatable, Hashable {
///
/// - withNoOverrides:
/// - withTopUnigramScore: 使使
///
/// [("a", -114), ("b", -514), ("c", -1919)]
/// ("c", -114)使
///
/// overridingScore
/// - withHighScore: overridingScore使
public enum OverrideType: Int {
case withNoOverrides = 0
case withTopUnigramScore = 1
case withHighScore = 2
}
///
/// 0使
/// a b cA B C使
/// c bc
/// A->bc A B 使0
/// A-B 0
/// c
public var overridingScore: Double = 114_514
private(set) var key: String
private(set) var keyArray: [String]
private(set) var spanLength: Int
private(set) var unigrams: [Megrez.Unigram]
private(set) var currentUnigramIndex: Int = 0 {
didSet { currentUnigramIndex = min(max(0, currentUnigramIndex), unigrams.count - 1) }
}
public var currentPair: Megrez.Compositor.KeyValuePaired { .init(key: key, value: value) }
public func hash(into hasher: inout Hasher) {
hasher.combine(key)
hasher.combine(spanLength)
hasher.combine(unigrams)
hasher.combine(currentUnigramIndex)
hasher.combine(spanLength)
hasher.combine(overrideType)
}
private(set) var overrideType: Node.OverrideType
public static func == (lhs: Node, rhs: Node) -> Bool {
lhs.key == rhs.key && lhs.spanLength == rhs.spanLength
&& lhs.unigrams == rhs.unigrams && lhs.overrideType == rhs.overrideType
}
public init(
keyArray: [String] = [], spanLength: Int = 0, unigrams: [Megrez.Unigram] = [], keySeparator: String = ""
) {
key = keyArray.joined(separator: keySeparator)
self.keyArray = keyArray
self.spanLength = spanLength
self.unigrams = unigrams
overrideType = .withNoOverrides
}
///
public var isReadingMismatched: Bool {
keyArray.count != value.count
}
///
public var currentUnigram: Megrez.Unigram {
unigrams.isEmpty ? .init() : unigrams[currentUnigramIndex]
}
public var value: String { currentUnigram.value }
public var score: Double {
guard !unigrams.isEmpty else { return 0 }
switch overrideType {
case .withHighScore: return overridingScore
case .withTopUnigramScore: return unigrams[0].score
default: return currentUnigram.score
}
}
public var isOverriden: Bool {
overrideType != .withNoOverrides
}
public func reset() {
currentUnigramIndex = 0
overrideType = .withNoOverrides
}
public func selectOverrideUnigram(value: String, type: Node.OverrideType) -> Bool {
guard type != .withNoOverrides else {
return false
}
for (i, gram) in unigrams.enumerated() {
if value != gram.value { continue }
currentUnigramIndex = i
overrideType = type
return true
}
return false
}
}
}
extension Megrez.Compositor {
///
///
/// Gramambular NodeInSpan
public struct NodeAnchor: Hashable {
let node: Megrez.Compositor.Node
let spanIndex: Int //
var spanLength: Int { node.spanLength }
var unigrams: [Megrez.Unigram] { node.unigrams }
var key: String { node.key }
var value: String { node.value }
///
public func hash(into hasher: inout Hasher) {
hasher.combine(node)
hasher.combine(spanIndex)
}
}
}
// MARK: - Array Extensions.
extension Array where Element == Megrez.Compositor.Node {
///
public var values: [String] { map(\.value) }
///
public var keys: [String] { map(\.key) }
/// (Result A, Result B)
/// Result A Result B
public var nodeBorderPointDictPair: ([Int: Int], [Int: Int]) {
// Result A Result B
var resultA = [Int: Int]()
var resultB = [Int: Int]()
var i = 0
for (j, neta) in enumerated() {
resultA[j] = i
neta.keyArray.forEach { _ in
resultB[i] = j
i += 1
}
}
resultA[resultA.count] = i
resultB[i] = resultB.count
return (resultA, resultB)
}
///
public var totalKeyCount: Int { map(\.keyArray.count).reduce(0, +) }
///
/// - Parameter cursor:
public func contextRange(ofGivenCursor cursor: Int) -> Range<Int> {
guard !isEmpty else { return 0..<0 }
let lastSpanningLength = reversed()[0].keyArray.count
var nilReturn = (totalKeyCount - lastSpanningLength)..<totalKeyCount
if cursor >= totalKeyCount { return nilReturn } //
let cursor = Swift.max(0, cursor) //
nilReturn = cursor..<cursor
guard let rearNodeID = nodeBorderPointDictPair.1[cursor] else { return nilReturn } // nilReturn
guard let rearIndex = nodeBorderPointDictPair.0[rearNodeID] else { return nilReturn } // nilReturn
guard let frontIndex = nodeBorderPointDictPair.0[rearNodeID + 1] else { return nilReturn } // nilReturn
return rearIndex..<frontIndex
}
///
/// - 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.min(Swift.max(0, cursor), totalKeyCount - 1) //
let range = contextRange(ofGivenCursor: cursor)
outCursorPastNode = range.upperBound
guard let rearNodeID = nodeBorderPointDictPair.1[cursor] else { return nil }
return count - 1 >= rearNodeID ? self[rearNodeID] : nil
}
///
/// - Parameter cursor:
/// - Returns:
public func findNode(at cursor: Int) -> Megrez.Compositor.Node? {
var useless = 0
return findNode(at: cursor, target: &useless)
}
}