private static void CategorizeNodesByLabels( TreeComparer <TNode> comparer, TNode root, int labelCount, out List <TNode>[] nodes, out int totalCount) { nodes = new List <TNode> [labelCount]; var count = 0; // It is important that we add the nodes in depth-first prefix order. // This order ensures that a node of a certain kind can have a parent of the same kind // and we can still use tied-to-parent for that kind. That's because the parent will always // be processed earlier than the child due to depth-first prefix ordering. foreach (var node in comparer.GetDescendants(root)) { var label = comparer.GetLabel(node); if (label < 0 || label >= labelCount) { throw new InvalidOperationException(string.Format(WorkspacesResources.Label_for_node_0_is_invalid_it_must_be_within_bracket_0_1, node, labelCount)); } var list = nodes[label]; if (list == null) { nodes[label] = list = new List <TNode>(); } list.Add(node); count++; } totalCount = count; }
internal Edit(EditKind kind, TreeComparer <TNode> comparer, TNode oldNode, TNode newNode) { Debug.Assert((oldNode == null || oldNode.Equals(null)) == (kind == EditKind.Insert)); Debug.Assert((newNode == null || newNode.Equals(null)) == (kind == EditKind.Delete)); Debug.Assert((oldNode == null || oldNode.Equals(null)) || (newNode == null || newNode.Equals(null)) || !comparer.TreesEqual(oldNode, newNode)); _comparer = comparer; _kind = kind; _oldNode = oldNode; _newNode = newNode; }
internal Edit(EditKind kind, TreeComparer <TNode> comparer, TNode node1, TNode node2) { Debug.Assert((node1 == null || node1.Equals(default(TNode))) == (kind == EditKind.Insert)); Debug.Assert((node2 == null || node2.Equals(default(TNode))) == (kind == EditKind.Delete)); Debug.Assert((node1 == null || node1.Equals(default(TNode))) || (node2 == null || node2.Equals(default(TNode))) || !comparer.TreesEqual(node1, node2)); this.comparer = comparer; this.kind = kind; this.node1 = node1; this.node2 = node2; }
internal Edit(EditKind kind, TreeComparer <TNode> comparer, TNode oldNode, TNode newNode) { Debug.Assert((oldNode == null || oldNode.Equals(default(TNode))) == (kind == EditKind.Insert)); Debug.Assert((newNode == null || newNode.Equals(default(TNode))) == (kind == EditKind.Delete)); Debug.Assert((oldNode == null || oldNode.Equals(default(TNode))) || (newNode == null || newNode.Equals(default(TNode))) || !comparer.TreesEqual(oldNode, newNode)); this.comparer = comparer; this.kind = kind; this.oldNode = oldNode; this.newNode = newNode; }
internal Match(TNode root1, TNode root2, TreeComparer <TNode> nodeComparer, IEnumerable <KeyValuePair <TNode, TNode> > knownMatches) { this.root1 = root1; this.root2 = root2; this.comparer = nodeComparer; int labelCount = nodeComparer.LabelCount; // Calculate chains (not including root node): int count1, count2; List <TNode>[] nodes1, nodes2; CategorizeNodesByLabels(root1, labelCount, out nodes1, out count1); CategorizeNodesByLabels(root2, labelCount, out nodes2, out count2); // Calculate match: this.oneToTwo = new Dictionary <TNode, TNode>(count1); this.twoToOne = new Dictionary <TNode, TNode>(count2); if (knownMatches != null) { foreach (var knownMatch in knownMatches) { if (comparer.GetLabel(knownMatch.Key) != comparer.GetLabel(knownMatch.Value)) { throw new ArgumentException(string.Format("Matching nodes '{0}' and '{1}' must have the same label.".NeedsLocalization(), knownMatch.Key, knownMatch.Value), "knownMatches"); } if (!comparer.TreesEqual(knownMatch.Key, root1)) { throw new ArgumentException(string.Format("Node '{0}' must be contained in the old tree.".NeedsLocalization(), knownMatch.Key), "knownMatches"); } if (!comparer.TreesEqual(knownMatch.Value, root2)) { throw new ArgumentException(string.Format("Node '{0}' must be contained in the new tree.".NeedsLocalization(), knownMatch.Value), "knownMatches"); } if (!oneToTwo.ContainsKey(knownMatch.Key)) { Add(knownMatch.Key, knownMatch.Value); } } } ComputeMatch(nodes1, nodes2); }
internal Match(TNode root1, TNode root2, TreeComparer <TNode> nodeComparer, IEnumerable <KeyValuePair <TNode, TNode> > knownMatches) { this.root1 = root1; this.root2 = root2; this.comparer = nodeComparer; int labelCount = nodeComparer.LabelCount; // Calculate chains (not including root node): int count1, count2; List <TNode>[] nodes1, nodes2; CategorizeNodesByLabels(root1, labelCount, out nodes1, out count1); CategorizeNodesByLabels(root2, labelCount, out nodes2, out count2); // Calculate match: this.oneToTwo = new Dictionary <TNode, TNode>(count1); this.twoToOne = new Dictionary <TNode, TNode>(count2); if (knownMatches != null) { foreach (var knownMatch in knownMatches) { if (comparer.GetLabel(knownMatch.Key) != comparer.GetLabel(knownMatch.Value)) { throw new ArgumentException(string.Format(WorkspacesResources.MatchingNodesMustHaveTheSameLabel, knownMatch.Key, knownMatch.Value), "knownMatches"); } if (!comparer.TreesEqual(knownMatch.Key, root1)) { throw new ArgumentException(string.Format(WorkspacesResources.NodeMustBeContainedInTheOldTree, knownMatch.Key), "knownMatches"); } if (!comparer.TreesEqual(knownMatch.Value, root2)) { throw new ArgumentException(string.Format(WorkspacesResources.NodeMustBeContainedInTheNewTree, knownMatch.Value), "knownMatches"); } if (!oneToTwo.ContainsKey(knownMatch.Key)) { Add(knownMatch.Key, knownMatch.Value); } } } ComputeMatch(nodes1, nodes2); }
internal Match(TNode root1, TNode root2, TreeComparer <TNode> comparer, IEnumerable <KeyValuePair <TNode, TNode> > knownMatches) { _root1 = root1; _root2 = root2; _comparer = comparer; int labelCount = comparer.LabelCount; // Calculate chains (not including root node): int count1, count2; List <TNode>[] nodes1, nodes2; CategorizeNodesByLabels(comparer, root1, labelCount, out nodes1, out count1); CategorizeNodesByLabels(comparer, root2, labelCount, out nodes2, out count2); _oneToTwo = new Dictionary <TNode, TNode>(); _twoToOne = new Dictionary <TNode, TNode>(); // Root nodes always match. Add them before adding known matches to make sure we always have root mapping. TryAdd(root1, root2); if (knownMatches != null) { foreach (var knownMatch in knownMatches) { if (comparer.GetLabel(knownMatch.Key) != comparer.GetLabel(knownMatch.Value)) { throw new ArgumentException(string.Format(WorkspacesResources.MatchingNodesMustHaveTheSameLabel, knownMatch.Key, knownMatch.Value), nameof(knownMatches)); } if (!comparer.TreesEqual(knownMatch.Key, root1)) { throw new ArgumentException(string.Format(WorkspacesResources.NodeMustBeContainedInTheOldTree, knownMatch.Key), nameof(knownMatches)); } if (!comparer.TreesEqual(knownMatch.Value, root2)) { throw new ArgumentException(string.Format(WorkspacesResources.NodeMustBeContainedInTheNewTree, knownMatch.Value), nameof(knownMatches)); } // skip pairs whose key or value is already mapped: TryAdd(knownMatch.Key, knownMatch.Value); } } ComputeMatch(nodes1, nodes2); }
internal Match(TNode root1, TNode root2, TreeComparer <TNode> comparer, IEnumerable <KeyValuePair <TNode, TNode> > knownMatches) { _root1 = root1; _root2 = root2; _comparer = comparer; var labelCount = comparer.LabelCount; CategorizeNodesByLabels(comparer, root1, labelCount, out var nodes1, out _); CategorizeNodesByLabels(comparer, root2, labelCount, out var nodes2, out _); _oneToTwo = new Dictionary <TNode, TNode>(); _twoToOne = new Dictionary <TNode, TNode>(); // Root nodes always match. Add them before adding known matches to make sure we always have root mapping. TryAdd(root1, root2); if (knownMatches != null) { foreach (var knownMatch in knownMatches) { if (comparer.GetLabel(knownMatch.Key) != comparer.GetLabel(knownMatch.Value)) { throw new ArgumentException(string.Format(WorkspacesResources.Matching_nodes_0_and_1_must_have_the_same_label, knownMatch.Key, knownMatch.Value), nameof(knownMatches)); } if (!comparer.TreesEqual(knownMatch.Key, root1)) { throw new ArgumentException(string.Format(WorkspacesResources.Node_0_must_be_contained_in_the_old_tree, knownMatch.Key), nameof(knownMatches)); } if (!comparer.TreesEqual(knownMatch.Value, root2)) { throw new ArgumentException(string.Format(WorkspacesResources.Node_0_must_be_contained_in_the_new_tree, knownMatch.Value), nameof(knownMatches)); } // skip pairs whose key or value is already mapped: TryAdd(knownMatch.Key, knownMatch.Value); } } ComputeMatch(nodes1, nodes2); }
internal Edit(EditKind kind, TreeComparer <TNode> comparer, TNode oldNode, TNode newNode) { Debug.Assert((oldNode == null || oldNode.Equals(default)) == (kind == EditKind.Insert));