package engine // collectionPolicyRetirementIndex locates only assembly policies whose YAML // identity or record-owned state can be cleared by an ancestor replacement. // Mapping keys and sequence indexes remain distinct through pathSegment keys. type collectionPolicyRetirementIndex struct { children map[pathSegment]*collectionPolicyRetirementIndex entryKey string hasEntry bool } func newCollectionPolicyRetirementIndex(scope collectionPolicyScope) *collectionPolicyRetirementIndex { index := &collectionPolicyRetirementIndex{} for _, entry := range scope.collections { if collectionPolicyHasRetirementState(entry.policy) { index.set(entry) } } return index } func (index *collectionPolicyRetirementIndex) set(entry collectionPolicyEntry) { node := index for _, segment := range entry.destination.segments { if node.children == nil { node.children = make(map[pathSegment]*collectionPolicyRetirementIndex) } if node.children[segment] == nil { node.children[segment] = &collectionPolicyRetirementIndex{} } node = node.children[segment] } node.entryKey = entry.destination.String() node.hasEntry = true } func (index *collectionPolicyRetirementIndex) remove(destination Path) { if index == nil { return } nodes := make([]*collectionPolicyRetirementIndex, 1, len(destination.segments)+1) nodes[0] = index node := index for _, segment := range destination.segments { node = node.children[segment] if node == nil { return } nodes = append(nodes, node) } node.entryKey = "" node.hasEntry = false pruneCollectionPolicyIndex(nodes, destination.segments) } func (index *collectionPolicyRetirementIndex) retire(scope *collectionPolicyScope, ancestor Path) { if index == nil || scope == nil { return } nodes := make([]*collectionPolicyRetirementIndex, 1, len(ancestor.segments)+1) nodes[0] = index node := index for _, segment := range ancestor.segments { node = node.children[segment] if node == nil { return } nodes = append(nodes, node) } index.clearSubtree(scope, node) pruneCollectionPolicyIndex(nodes, ancestor.segments) } func (index *collectionPolicyRetirementIndex) clearSubtree(scope *collectionPolicyScope, node *collectionPolicyRetirementIndex) { if node.hasEntry { if entry, found := scope.collections[node.entryKey]; found { clearCollectionIdentity(&entry.policy) scope.collections[node.entryKey] = entry } node.entryKey = "" node.hasEntry = false } for segment, child := range node.children { index.clearSubtree(scope, child) if child.empty() { delete(node.children, segment) } } if len(node.children) == 0 { node.children = nil } } func (index *collectionPolicyRetirementIndex) empty() bool { return index == nil || !index.hasEntry && len(index.children) == 0 } func pruneCollectionPolicyIndex(nodes []*collectionPolicyRetirementIndex, segments []pathSegment) { for position := len(segments) - 1; position >= 0; position-- { child := nodes[position+1] if !child.empty() { return } delete(nodes[position].children, segments[position]) } } func collectionPolicyHasRetirementState(policy collectionPolicy) bool { return policy.identityFields != nil || policy.identityPresent || policy.identityLocation != nil || policy.recordOrder != nil || policy.recordPolicies != nil } func (assembly *assemblyAccumulator) setCollectionPolicy(destination Path, policy collectionPolicy) { if assembly == nil || assembly.current == nil { return } if assembly.collectionPolicyRetirement == nil { assembly.collectionPolicyRetirement = newCollectionPolicyRetirementIndex(assembly.current.collectionPolicies) } assembly.current.collectionPolicies.set(destination, policy) entry := assembly.current.collectionPolicies.collections[destination.String()] if collectionPolicyHasRetirementState(entry.policy) { assembly.collectionPolicyRetirement.set(entry) } else { assembly.collectionPolicyRetirement.remove(destination) } } func (assembly *assemblyAccumulator) retireCollectionPoliciesAtOrBelow(ancestor Path) { if assembly == nil || assembly.current == nil { return } if assembly.collectionPolicyRetirement == nil { assembly.collectionPolicyRetirement = newCollectionPolicyRetirementIndex(assembly.current.collectionPolicies) } assembly.collectionPolicyRetirement.retire(&assembly.current.collectionPolicies, ancestor) }