Step 1 of the GSS content-matcher build (docs/design/counted-content-automaton.md). A multiply-referenced `<xs:group>` expands to one copy-on-write-shared `Particle` (GroupParticleMemo), but `Group`/`Term` are value types with no exposed identity, so a content-model compiler cannot tell two references apart and inlines the group per reference (the 2^K build the GSS matcher will close). Group now carries a `definitionID: Int?`, stamped from a per-compile counter on GroupParticleMemo when an expansion is first compiled, so every reference sharing the memo key reuses the same stamped term and distinct definitions differ. It is metadata only: Group is not Equatable/Hashable, so it perturbs no determinism or restriction comparison, and it is nil for an inline group. FP-neutral by construction (no consumer yet). Full in-repo suite green; the XSTS buckets are unchanged (valid-schemas-rejected 0, invalid-schemas-accepted 8, valid-instances-rejected 0, invalid-instances-accepted 14); swiftformat/swiftlint clean. Step 2 (a call/return content-model build keyed on this id, alongside the inlining oracle) consumes it.
32 lines
1.5 KiB
Swift
32 lines
1.5 KiB
Swift
extension PureXML.Schema {
|
|
/// The key under which an `<xs:group>` reference's expansion is memoized: the
|
|
/// group DEFINITION node and the cycle-visiting set at the reference site. The
|
|
/// expansion is determined by these (the namespace scope is fixed per
|
|
/// definition), so two references that share them share the result.
|
|
struct GroupParticleMemoKey: Hashable {
|
|
let definition: ObjectIdentifier
|
|
let visiting: Set<String>
|
|
}
|
|
|
|
/// Memoizes group-reference expansion during one schema compile. A
|
|
/// multiply-referenced nested group (`g0=(g1,g1), g1=(g2,g2), …`) otherwise
|
|
/// rebuilds each subtree per reference, an exponential `2^K` compile; sharing the
|
|
/// expansion across sibling references drops the build to `O(groups)`. The
|
|
/// resulting `Particle` is semantically identical (a value type, so the shared
|
|
/// content term is copy-on-write), only built once. A reference type so it is
|
|
/// shared across the value copies `XSDContext.scoped`/`visiting` make; one
|
|
/// instance per compile.
|
|
final class GroupParticleMemo {
|
|
var store: [GroupParticleMemoKey: PureXML.Schema.Particle] = [:]
|
|
/// Source of the stable `Group.definitionID` stamped on each distinct
|
|
/// expansion as it is first compiled, so every reference sharing the
|
|
/// expansion carries the same id and distinct definitions differ.
|
|
private var nextID = 0
|
|
|
|
func allocateDefinitionID() -> Int {
|
|
defer { nextID += 1 }
|
|
return nextID
|
|
}
|
|
}
|
|
}
|