Support Strict concurrency

This commit is contained in:
ensan
2023-07-23 18:37:45 +09:00
parent 5740748de0
commit aad755da6f
8 changed files with 31 additions and 32 deletions

View File

@@ -10,14 +10,14 @@ import Foundation
import SwiftUtils
///
public final class KanaKanjiConverter {
@MainActor public final class KanaKanjiConverter {
public init() {}
public init(dicdataStore: DicdataStore) {
self.converter = .init(dicdataStore: dicdataStore)
}
private var converter = Kana2Kanji()
private var checker = SpellChecker()
@MainActor private var checker = SpellChecker()
private var checkerInitialized: [KeyboardLanguage: Bool] = [.none: true, .ja_JP: true]
//
@@ -34,18 +34,19 @@ public final class KanaKanjiConverter {
self.lastData = nil
}
/// SpellChecker
public func setKeyboardLanguage(_ language: KeyboardLanguage) {
if !checkerInitialized[language, default: false] {
switch language {
case .en_US:
Task {
_ = checker.completions(forPartialWordRange: NSRange(location: 0, length: 1), in: "a", language: "en-US")
checkerInitialized[language] = true
Task { @MainActor in
_ = self.checker.completions(forPartialWordRange: NSRange(location: 0, length: 1), in: "a", language: "en-US")
self.checkerInitialized[language] = true
}
case .el_GR:
Task {
_ = checker.completions(forPartialWordRange: NSRange(location: 0, length: 1), in: "α", language: "el-GR")
checkerInitialized[language] = true
Task { @MainActor in
_ = self.checker.completions(forPartialWordRange: NSRange(location: 0, length: 1), in: "a", language: "el-GR")
self.checkerInitialized[language] = true
}
case .none, .ja_JP:
checkerInitialized[language] = true

View File

@@ -12,7 +12,7 @@ import UIKit
import AppKit
#endif
final class SpellChecker {
@MainActor final class SpellChecker {
#if os(iOS) || os(tvOS)
private let checker = UITextChecker()
#elseif os(macOS)

View File

@@ -81,7 +81,6 @@ struct LongTermLearningMemory {
}
static var txtFileSplit: Int { 2048 }
static var maxMemoryCount: Int = 8192
private static func BoolToUInt64(_ bools: [Bool]) -> [UInt64] {
let unit = 64
@@ -196,7 +195,7 @@ struct LongTermLearningMemory {
}
///
static func merge(tempTrie: TemporalLearningMemoryTrie, forgetTargets: [DicdataElement] = [], directoryURL: URL) throws {
static func merge(tempTrie: TemporalLearningMemoryTrie, forgetTargets: [DicdataElement] = [], directoryURL: URL, maxMemoryCount: Int, char2UInt8: [Character: UInt8]) throws {
// MARK: `.pause``merge``.2``merge`
if fileExist(pauseFileURL(directoryURL: directoryURL)) {
debug("LongTermLearningMemory merge collapsion detected, trying recovery...")
@@ -283,13 +282,13 @@ struct LongTermLearningMemory {
newDicdata.append(dicdataElement)
newMetadata.append(metadataElement)
}
guard let chars = LearningManager.keyToChars(ruby) else {
guard let chars = LearningManager.keyToChars(ruby, char2UInt8: char2UInt8) else {
continue
}
newTrie.append(dicdata: newDicdata, chars: chars, metadata: newMetadata)
}
//
if newTrie.dicdata.count > Self.maxMemoryCount {
if newTrie.dicdata.count > maxMemoryCount {
break
}
}
@@ -604,22 +603,22 @@ struct TemporalLearningMemoryTrie {
}
final class LearningManager {
private static func updateChar2Int8(bundleURL: URL) {
private static func updateChar2Int8(bundleURL: URL, target: inout [Character: UInt8]) {
do {
let chidURL = bundleURL.appendingPathComponent("louds/charID.chid", isDirectory: false)
let string = try String(contentsOf: chidURL, encoding: .utf8)
Self.char2UInt8 = [Character: UInt8].init(uniqueKeysWithValues: string.enumerated().map {($0.element, UInt8($0.offset))})
target = [Character: UInt8].init(uniqueKeysWithValues: string.enumerated().map {($0.element, UInt8($0.offset))})
} catch {
debug("ファイルが存在しません: \(error)")
}
}
private static var char2UInt8: [Character: UInt8] = [:]
private var char2UInt8: [Character: UInt8] = [:]
static var today: UInt16 {
UInt16(Int(Date().timeIntervalSince1970) / 86400) - 19000
}
static func keyToChars(_ key: some StringProtocol) -> [UInt8]? {
static func keyToChars(_ key: some StringProtocol, char2UInt8: [Character: UInt8]) -> [UInt8]? {
var chars: [UInt8] = []
chars.reserveCapacity(key.count)
for character in key {
@@ -649,17 +648,16 @@ final class LearningManager {
if !options.learningType.needUsingMemory {
return
}
Self.updateChar2Int8(bundleURL: options.dictionaryResourceURL)
Self.updateChar2Int8(bundleURL: options.dictionaryResourceURL, target: &char2UInt8)
}
/// - Returns: Whether cache should be reseted or not.
func setRequestOptions(options: ConvertRequestOptions) -> Bool {
// `char2Int8`
if options.dictionaryResourceURL != self.options.dictionaryResourceURL {
Self.updateChar2Int8(bundleURL: options.dictionaryResourceURL)
Self.updateChar2Int8(bundleURL: options.dictionaryResourceURL, target: &char2UInt8)
}
self.options = options
LongTermLearningMemory.maxMemoryCount = options.maxMemoryCount
switch options.learningType {
case .inputAndOutput, .onlyOutput: break
@@ -703,7 +701,7 @@ final class LearningManager {
}
//
for datum in data where DicdataStore.needWValueMemory(datum) {
guard let chars = Self.keyToChars(datum.ruby) else {
guard let chars = Self.keyToChars(datum.ruby, char2UInt8: char2UInt8) else {
continue
}
self.temporaryMemory.memorize(dicdataElement: datum, chars: chars)
@@ -732,7 +730,7 @@ final class LearningManager {
// firstClause
firstClause = secondClause
secondClause = datum
guard let chars = Self.keyToChars(element.ruby) else {
guard let chars = Self.keyToChars(element.ruby, char2UInt8: char2UInt8) else {
continue
}
debug("LearningManager update first/second", element)
@@ -777,7 +775,7 @@ final class LearningManager {
mid: secondClause.mid,
value: firstClause.baseValue + secondClause.baseValue
)
if let chars = Self.keyToChars(element.ruby) {
if let chars = Self.keyToChars(element.ruby, char2UInt8: char2UInt8) {
debug("LearningManager update first/second rest", element)
self.temporaryMemory.memorize(dicdataElement: element, chars: chars)
}
@@ -792,7 +790,7 @@ final class LearningManager {
mid: data.last?.mid ?? MIDData..mid,
value: data.reduce(into: 0) {$0 += $1.baseValue}
)
guard let chars = Self.keyToChars(element.ruby) else {
guard let chars = Self.keyToChars(element.ruby, char2UInt8: char2UInt8) else {
return
}
debug("LearningManager update all", element)
@@ -803,14 +801,14 @@ final class LearningManager {
func forgetMemory(data: [DicdataElement]) {
// 1. temporary memory
for element in data {
guard let chars = Self.keyToChars(element.ruby) else {
guard let chars = Self.keyToChars(element.ruby, char2UInt8: char2UInt8) else {
continue
}
self.temporaryMemory.forget(dicdataElement: element, chars: chars)
}
// 2. longterm memory
do {
try LongTermLearningMemory.merge(tempTrie: self.temporaryMemory, forgetTargets: data, directoryURL: self.options.memoryDirectoryURL)
try LongTermLearningMemory.merge(tempTrie: self.temporaryMemory, forgetTargets: data, directoryURL: self.options.memoryDirectoryURL, maxMemoryCount: options.maxMemoryCount, char2UInt8: char2UInt8)
// temporaryMemory
self.temporaryMemory = TemporalLearningMemoryTrie()
} catch {
@@ -826,7 +824,7 @@ final class LearningManager {
return
}
do {
try LongTermLearningMemory.merge(tempTrie: self.temporaryMemory, directoryURL: self.options.memoryDirectoryURL)
try LongTermLearningMemory.merge(tempTrie: self.temporaryMemory, directoryURL: self.options.memoryDirectoryURL, maxMemoryCount: options.maxMemoryCount, char2UInt8: char2UInt8)
// temporaryMemory
self.temporaryMemory = TemporalLearningMemoryTrie()
} catch {

View File

@@ -12,7 +12,7 @@ public enum InputStyle: String {
case roman2kana = "roman"
}
public enum KeyboardLanguage: String, Codable, Equatable {
public enum KeyboardLanguage: String, Codable, Equatable, Sendable {
case en_US
case ja_JP
case el_GR