vChewing-macOS/Packages/vChewing_Megrez/Sources/Megrez/4_SpanUnit.swift

105 lines
3.9 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 and further development by (c) 2022 and onwards The vChewing Project (MIT License).
// Was initially 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 {
///
public class SpanUnit {
/// nil
public var nodes: [Node?] = []
///
///
public private(set) var maxLength = 0
/// Megrez.Compositor.maxSpanLength
private var maxSpanLength: Int { Megrez.Compositor.maxSpanLength }
///
private var allowedLengths: ClosedRange<Int> { 1 ... maxSpanLength }
///
public init() {
clear()
}
/// 0
public func clear() {
nodes.removeAll()
for _ in 0 ..< maxSpanLength {
nodes.append(nil)
}
maxLength = 0
}
///
/// - Parameter node:
/// - Returns:
@discardableResult public func append(node: Node) -> Bool {
guard allowedLengths.contains(node.spanLength) else {
return false
}
nodes[node.spanLength - 1] = node
maxLength = max(maxLength, node.spanLength)
return true
}
///
/// - Parameter length:
/// - Returns:
@discardableResult public func dropNodesOfOrBeyond(length: Int) -> Bool {
guard allowedLengths.contains(length) else {
return false
}
for i in length ... maxSpanLength {
nodes[i - 1] = nil
}
maxLength = 0
guard length > 1 else { return false }
let maxR = length - 2
for i in 0 ... maxR {
if nodes[maxR - i] == nil { continue }
maxLength = maxR - i + 1
break
}
return true
}
///
/// - Parameter length:
/// - Returns:
public func nodeOf(length: Int) -> Node? {
guard allowedLengths.contains(length) else { return nil }
return nodes[length - 1]
}
}
// MARK: Internal implementations.
///
/// - Parameter location:
/// - Returns:
internal func fetchOverlappingNodes(at location: Int) -> [NodeAnchor] {
var results = [NodeAnchor]()
guard !spans.isEmpty, location < spans.count else { return results }
//
for theLocation in 1 ... spans[location].maxLength {
guard let node = spans[location].nodeOf(length: theLocation) else { continue }
results.append(.init(node: node, spanIndex: location))
}
//
let begin: Int = location - min(location, Megrez.Compositor.maxSpanLength - 1)
for theLocation in begin ..< location {
let (A, B): (Int, Int) = (location - theLocation + 1, spans[theLocation].maxLength)
guard A <= B else { continue }
for theLength in A ... B {
guard let node = spans[theLocation].nodeOf(length: theLength) else { continue }
results.append(.init(node: node, spanIndex: theLocation))
}
}
return results
}
}