| File: Internal\GrammarBuilding\BuilderElements.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Speech.Internal.SrgsParser; using System.Speech.Recognition; using System.Text; namespace System.Speech.Internal.GrammarBuilding { [DebuggerDisplay("{DebugSummary}")] internal abstract class BuilderElements : GrammarBuilderBase { #region Constructors internal BuilderElements() { } #endregion #region Public Methods public override bool Equals([NotNullWhen(true)] object? obj) { if (obj is not BuilderElements refObj) { return false; } // Easy out if the number of elements do not match if (refObj.Count != Count || refObj.Items.Count != Items.Count) { return false; } // Deep recursive search for equality for (int i = 0; i < Items.Count; i++) { if (!Items[i].Equals(refObj.Items[i])) { return false; } } return true; } public override int GetHashCode() { return base.GetHashCode(); } #endregion #region Internal Methods /// <summary> /// Optimization for a element tree /// </summary> protected void Optimize(Collection<RuleElement> newRules) { // Create an dictionary of [Count of elements, list of elements] SortedDictionary<int, Collection<BuilderElements?>> dict = new(); GetDictionaryElements(dict); // The dictionary is sorted from the smallest buckets to the largest. // Revert the order in the keys arrays int[] keys = new int[dict.Keys.Count]; int index = keys.Length - 1; foreach (int key in dict.Keys) { keys[index--] = key; } // Look for each bucket from the largest to the smallest for (int i = 0; i < keys.Length && keys[i] >= 3; i++) { Collection<BuilderElements?> gb = dict[keys[i]]; for (int j = 0; j < gb.Count; j++) { RuleElement? newRule = null; RuleRefElement? ruleRef = null; BuilderElements? thisOne = gb[j]; for (int k = j + 1; k < gb.Count; k++) { BuilderElements? current = gb[k]; if (thisOne != null && thisOne.Equals(current)) { BuilderElements parent = current.Parent!; if (current is SemanticKeyElement) // if current is already a ruleref. There is no need to create a new one { // Simply set the ruleref of the current element to the ruleref of the org element. parent.Items[parent.Items.IndexOf(current)] = thisOne; } else { // Create a rule to store the common elements if (newRule == null) { newRule = new RuleElement(current, "_"); newRules.Add(newRule); } // Create a ruleref and attach the if (ruleRef == null) { ruleRef = new RuleRefElement(newRule); thisOne.Parent!.Items[thisOne.Parent.Items.IndexOf(thisOne)] = ruleRef; } parent.Items[current.Parent!.Items.IndexOf(current)] = ruleRef; } // current.RemoveDictionaryElements(dict); gb[k] = null; } } } } } #endregion #region Internal Methods internal void Add(string phrase) { _items.Add(new GrammarBuilderPhrase(phrase)); } internal void Add(GrammarBuilder builder) { foreach (GrammarBuilderBase item in builder.InternalBuilder.Items) { _items.Add(item); } } internal void Add(GrammarBuilderBase item) { _items.Add(item); } internal void CloneItems(BuilderElements builders) { foreach (GrammarBuilderBase item in builders.Items) { _items.Add(item); } } internal void CreateChildrenElements(IElementFactory elementFactory, IRule parent, IdentifierCollection ruleIds) { foreach (GrammarBuilderBase builder in Items) { IElement? element = builder.CreateElement(elementFactory, parent, parent, ruleIds); if (element != null) { element.PostParse(parent); elementFactory.AddElement(parent, element); } } } internal void CreateChildrenElements(IElementFactory elementFactory, IItem parent, IRule rule, IdentifierCollection ruleIds) { foreach (GrammarBuilderBase builder in Items) { IElement? element = builder.CreateElement(elementFactory, parent, rule, ruleIds); if (element != null) { element.PostParse(parent); elementFactory.AddElement(parent, element); } } } internal override int CalcCount(BuilderElements? parent) { base.CalcCount(parent); int c = 1; foreach (GrammarBuilderBase item in Items) { c += item.CalcCount(this); } Count = c; return c; } #endregion #region Internal Properties internal List<GrammarBuilderBase> Items { get { return _items; } } internal override string DebugSummary { get { StringBuilder sb = new(); foreach (GrammarBuilderBase item in _items) { if (sb.Length > 0) { sb.Append(' '); } sb.Append(item.DebugSummary); } return sb.ToString(); } } #endregion #region Private Method private void GetDictionaryElements(SortedDictionary<int, Collection<BuilderElements?>> dict) { // Recursive search from a matching subtree foreach (GrammarBuilderBase item in Items) { BuilderElements? current = item as BuilderElements; // Go deeper if the number of children is greater the element to compare against. if (current != null) { if (!dict.TryGetValue(current.Count, out Collection<BuilderElements?>? builderElements)) { builderElements = new Collection<BuilderElements?>(); dict.Add(current.Count, builderElements); } builderElements.Add(current); current.GetDictionaryElements(dict); } } } private void RemoveDictionaryElements(SortedDictionary<int, Collection<BuilderElements?>> dict) { // Recursive search from a matching subtree foreach (GrammarBuilderBase item in Items) { BuilderElements? current = item as BuilderElements; // Go deeper if the number of children is greater the element to compare against. if (current != null) { // Recursively remove all elements current.RemoveDictionaryElements(dict); dict[current.Count].Remove(current); } } } #endregion #region Private Fields // List of builder elements private readonly List<GrammarBuilderBase> _items = new(); #endregion } }