@@ -4,7 +4,8 @@ import dfhdl.internals.invert
4
4
private final case class ReplacementContext (
5
5
refTable : Map [DFRefAny , DFMember ],
6
6
memberTable : Map [DFMember , Set [DFRefAny ]],
7
- memberRepTable : Map [DFMember , List [(DFMember , Patch .Replace .RefFilter )]]
7
+ memberRepTable : Map [DFMember , List [(DFMember , Patch .Replace .RefFilter )]],
8
+ typeRefRepeats : Map [DFRef .TypeRef , Int ]
8
9
)(using getSet : MemberGetSet ):
9
10
def changeRef (origRef : DFRefAny , updateMember : DFMember ): ReplacementContext =
10
11
// println("changeRef", origRef, updateMember)
@@ -55,10 +56,12 @@ private final case class ReplacementContext(
55
56
val purgedRefs = config match
56
57
case Patch .Replace .Config .ChangeRefOnly => Set ()
57
58
case _ => refFilter(origMember.getRefs.toSet -- keepRefs)
59
+ val (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs) =
60
+ getUpdatedTypeRefCount(purgedRefs)
58
61
val updatedRefTable : Map [DFRefAny , DFMember ] =
59
62
replacementHistory.foldRight(refTable) { case ((rm, rf), rt) =>
60
63
rf(refs).foldLeft(rt)((rt2, r) => rt2.updated(r, rm))
61
- } -- purgedRefs
64
+ } -- purgedRefsWithoutRepeatedTypeRefs
62
65
val updatedMemberRepTable : Map [DFMember , List [(DFMember , Patch .Replace .RefFilter )]] =
63
66
refFilter match
64
67
// An all inclusive filter is purging all other replacement histories, so we only save it alone
@@ -70,24 +73,56 @@ private final case class ReplacementContext(
70
73
val updatedMemberTable = purgedRefs.foldLeft(memberTable) { case (mt, r) =>
71
74
mt.updatedWith(r.get)(SomeRefs => Some (SomeRefs .get - r))
72
75
} + (latestRepMember -> refs)
73
- ReplacementContext (updatedRefTable, updatedMemberTable, updatedMemberRepTable)
76
+ ReplacementContext (
77
+ updatedRefTable,
78
+ updatedMemberTable,
79
+ updatedMemberRepTable,
80
+ updatedTypeRefRepeats
81
+ )
74
82
end if
75
83
end replaceMember
76
84
77
- def removeMember (origMember : DFMember ): ReplacementContext =
78
- // total references to be removed are both
79
- // * refs - directly referencing the member
80
- // * originRefs - the member is referencing other members with a two-way
81
- // reference that points back to it.
82
- val totalRefs =
83
- memberTable.getOrElse(origMember, Set ()) ++ origMember.getRefs.filter {
84
- case _ : DFRef .TypeRef => false
85
- case _ => true
85
+ // returns the updated type ref count and the purged refs without repeated type refs
86
+ private def getUpdatedTypeRefCount (
87
+ purgedRefs : Set [DFRefAny ]
88
+ ): (Map [DFRef .TypeRef , Int ], Set [DFRefAny ]) =
89
+ val updatedTypeRefRepeats = purgedRefs.view
90
+ .collect { case ref : DFRef .TypeRef => ref }
91
+ .foldLeft(typeRefRepeats) { case (counts, ref) =>
92
+ counts.get(ref) match
93
+ case Some (count) => counts.updated(ref, count - 1 )
94
+ case None => counts
86
95
}
87
- this .copy(refTable = this .refTable -- totalRefs)
96
+ val purgedRefsWithoutRepeatedTypeRefs = purgedRefs.filter {
97
+ case ref : DFRef .TypeRef => updatedTypeRefRepeats.get(ref).exists(_ == 0 )
98
+ case _ => true
99
+ }
100
+ (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs)
101
+ end getUpdatedTypeRefCount
102
+
103
+ def removeMember (origMember : DFMember ): ReplacementContext =
104
+ // Total references to be removed are:
105
+ // * refs from memberTable - references from other members to this member
106
+ // * refs from origMember - references from this member to other members
107
+ // Together these cover both directions of two-way references
108
+ val purgedRefs =
109
+ memberTable.getOrElse(origMember, Set ()) ++ origMember.getRefs
110
+ val (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs) =
111
+ getUpdatedTypeRefCount(purgedRefs)
112
+ this .copy(
113
+ refTable = this .refTable -- purgedRefsWithoutRepeatedTypeRefs,
114
+ typeRefRepeats = updatedTypeRefRepeats
115
+ )
88
116
89
117
end ReplacementContext
90
118
91
119
private object ReplacementContext :
92
120
def fromRefTable (refTable : Map [DFRefAny , DFMember ])(using MemberGetSet ): ReplacementContext =
93
- ReplacementContext (refTable, refTable.invert, Map ())
121
+ val typeRefRepeats =
122
+ getSet.designDB.members.view
123
+ .flatMap(_.getRefs.view.collect { case ref : DFRef .TypeRef => ref })
124
+ .groupBy(identity)
125
+ .view
126
+ .mapValues(_.size)
127
+ .toMap
128
+ ReplacementContext (refTable, refTable.invert, Map (), typeRefRepeats)
0 commit comments