/// <summary> /// Returns a set containing all the types in <paramref name="ns" /> /// after merging using the specified <see cref="UnionComparer" />. For /// large sets, this operation may require significant time and memory. /// The returned set is always a copy of the original. /// </summary> /// <param name="ns">The namespaces to contain in the set.</param> /// <param name="comparer">The comparer to use for the set.</param> internal static IAnalysisSet CreateUnion(IEnumerable <AnalysisProxy> ns, UnionComparer comparer) { bool dummy; // TODO: Replace Trim() call with more intelligent enumeration. return(new AnalysisSetDetails.AnalysisHashSet(ns.UnionIter(comparer, out dummy), comparer).Trim()); }
/// <summary> /// Returns <paramref name="set"/> with the specified comparer. If the /// comparer does not need to be changed, <paramref name="set"/> is /// returned unmodified. /// </summary> /// <param name="set">The set to convert to a union.</param> /// <param name="comparer">The comparer to use for the set.</param> /// <param name="wasChanged">Returns True if the contents of the /// returned set are different to <paramref name="set"/>.</param> internal static IAnalysisSet AsUnion(this IAnalysisSet set, UnionComparer comparer, out bool wasChanged) { if ((set is AnalysisSetDetails.AnalysisSetOneUnion || set is AnalysisSetDetails.AnalysisSetTwoUnion || set is AnalysisSetDetails.AnalysisSetEmptyUnion || set is AnalysisSetDetails.AnalysisHashSet) && set.Comparer == comparer) { wasChanged = false; return(set); } wasChanged = true; var ns = set as AnalysisProxy; if (ns != null) { return(CreateUnion(ns, comparer)); } var ns2 = set as AnalysisSetDetails.AnalysisSetTwoObject; if (ns2 != null) { if (ns2.Value1 == null) { if (ns2.Value2 == null) { wasChanged = false; return(AnalysisSetEmptyUnion.Instances[comparer.Strength]); } wasChanged = false; return(new AnalysisSetOneUnion(ns2.Value2, comparer)); } else if (ns2.Value2 == null) { wasChanged = false; return(new AnalysisSetOneUnion(ns2.Value1, comparer)); } if (comparer.Equals(ns2.Value1, ns2.Value2)) { bool dummy; return(new AnalysisSetDetails.AnalysisSetOneUnion(comparer.MergeTypes(ns2.Value1, ns2.Value2, out dummy), comparer)); } else { return(new AnalysisSetDetails.AnalysisSetTwoUnion(ns2.Value1, ns2.Value2, comparer)); } } return(new AnalysisSetDetails.AnalysisHashSet(set, comparer)); }
internal static IEnumerable <AnalysisProxy> UnionIter(this IEnumerable <AnalysisProxy> items, UnionComparer comparer, out bool wasChanged) { #endif wasChanged = false; var asSet = items as IAnalysisSet; if (asSet != null && asSet.Comparer == comparer) { return(items); } var newItems = new List <AnalysisProxy>(); var anyMerged = true; while (anyMerged) { anyMerged = false; var matches = new Dictionary <AnalysisProxy, List <AnalysisProxy> >(comparer); foreach (var ns in items) { List <AnalysisProxy> list; if (matches.TryGetValue(ns, out list)) { if (list == null) { matches[ns] = list = new List <AnalysisProxy>(); } list.Add(ns); } else { matches[ns] = null; } } newItems.Clear(); foreach (var keyValue in matches) { var item = keyValue.Key; if (keyValue.Value != null) { foreach (var other in keyValue.Value) { bool merged; #if FULL_VALIDATION Validation.Assert(comparer.Equals(item, other)); #endif item = comparer.MergeTypes(item, other, out merged); if (merged) { anyMerged = true; wasChanged = true; } } } newItems.Add(item); } items = newItems; } return(items); }
private static IEnumerable <AnalysisWrapper> UnionIterInternal(IEnumerable <AnalysisWrapper> items, UnionComparer comparer, out bool wasChanged) {
/// <summary> /// Merges the provided sequence using the specified <see /// cref="UnionComparer"/>. /// </summary> #if FULL_VALIDATION internal static IEnumerable <AnalysisWrapper> UnionIter(this IEnumerable <AnalysisWrapper> items, UnionComparer comparer, out bool wasChanged) { var originalItems = items.ToList(); var newItems = UnionIterInternal(items, comparer, out wasChanged).ToList(); Validation.Assert(newItems.Count <= originalItems.Count); if (wasChanged) { Validation.Assert(newItems.Count < originalItems.Count); foreach (var x in newItems) { foreach (var y in newItems) { if (object.ReferenceEquals(x, y)) { continue; } Validation.Assert(!comparer.Equals(x, y)); Validation.Assert(!comparer.Equals(y, x)); } } } return(newItems); }
/// <summary> /// Returns a set containing only <paramref name="ns" /> that uses the /// specified <see cref="UnionComparer" />. /// /// This is different to casting from <see cref="AnalysisProxy" /> to <see /// cref="IAnalysisSet" />, because the implementation in <see /// cref="AnalysisProxy" /> always uses <see cref="ObjectComparer" />. /// </summary> /// <param name="ns">The namespace to contain in the set.</param> /// <param name="comparer">The comparer to use for the set.</param> internal static IAnalysisSet CreateUnion(AnalysisProxy ns, UnionComparer comparer) { return(new AnalysisSetDetails.AnalysisSetOneUnion(ns, comparer)); }
/// <summary> /// Returns an empty set that uses the specified <see /// cref="UnionComparer" />. /// </summary> /// <param name="comparer">The comparer to use for the set.</param> internal static IAnalysisSet CreateUnion(UnionComparer comparer) { return(AnalysisSetDetails.AnalysisSetEmptyUnion.Instances[comparer.Strength]); }