//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.DynamicUpdate { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime; using System.Runtime.Serialization; using System.ComponentModel; [DataContract] internal class EnvironmentUpdateMap { IList variableEntries; IList privateVariableEntries; IList argumentEntries; public EnvironmentUpdateMap() { } [DataMember(EmitDefaultValue = false)] public int NewArgumentCount { get; set; } [DataMember(EmitDefaultValue = false)] public int OldArgumentCount { get; set; } [DataMember(EmitDefaultValue = false)] public int NewVariableCount { get; set; } [DataMember(EmitDefaultValue = false)] public int OldVariableCount { get; set; } [DataMember(EmitDefaultValue = false)] public int NewPrivateVariableCount { get; set; } [DataMember(EmitDefaultValue = false)] public int OldPrivateVariableCount { get; set; } [DataMember(EmitDefaultValue = false)] public int RuntimeDelegateArgumentCount { get; set; } [DataMember(EmitDefaultValue = false, Name = "variableEntries")] internal IList SerializedVariableEntries { get { return this.variableEntries; } set { this.variableEntries = value; } } [DataMember(EmitDefaultValue = false, Name = "privateVariableEntries")] internal IList SerializedPrivateVariableEntries { get { return this.privateVariableEntries; } set { this.privateVariableEntries = value; } } [DataMember(EmitDefaultValue = false, Name = "argumentEntries")] internal IList SerializedArgumentEntries { get { return this.argumentEntries; } set { this.argumentEntries = value; } } internal bool IsAdditionToNoSymbols { get { return (this.OldArgumentCount + this.OldVariableCount + this.OldPrivateVariableCount + this.RuntimeDelegateArgumentCount) == 0 && (this.NewArgumentCount + this.NewVariableCount + this.NewPrivateVariableCount + this.RuntimeDelegateArgumentCount) > 0; } } internal bool HasVariableEntries { get { return this.variableEntries != null && this.variableEntries.Count > 0; } } internal bool HasPrivateVariableEntries { get { return this.privateVariableEntries != null && this.privateVariableEntries.Count > 0; } } internal bool HasArgumentEntries { get { return this.argumentEntries != null && this.argumentEntries.Count > 0; } } public IList VariableEntries { get { if (this.variableEntries == null) { this.variableEntries = new List(); } return this.variableEntries; } } public IList PrivateVariableEntries { get { if (this.privateVariableEntries == null) { this.privateVariableEntries = new List(); } return this.privateVariableEntries; } } public IList ArgumentEntries { get { if (this.argumentEntries == null) { this.argumentEntries = new List(); } return this.argumentEntries; } } internal static EnvironmentUpdateMap Merge(EnvironmentUpdateMap first, EnvironmentUpdateMap second, DynamicUpdateMap.MergeErrorContext errorContext) { if (first == null || second == null) { return first ?? second; } ThrowIfMapsIncompatible(first, second, errorContext); EnvironmentUpdateMap result = new EnvironmentUpdateMap { OldArgumentCount = first.OldArgumentCount, NewArgumentCount = second.NewArgumentCount, OldVariableCount = first.OldVariableCount, NewVariableCount = second.NewVariableCount, OldPrivateVariableCount = first.OldPrivateVariableCount, NewPrivateVariableCount = second.NewPrivateVariableCount, }; result.variableEntries = Merge(result.NewVariableCount, first.VariableEntries, second.VariableEntries); result.privateVariableEntries = Merge(result.NewPrivateVariableCount, first.PrivateVariableEntries, second.PrivateVariableEntries); result.argumentEntries = Merge(result.NewArgumentCount, first.ArgumentEntries, second.ArgumentEntries); if (result.OldArgumentCount != result.NewArgumentCount || result.OldVariableCount != result.NewVariableCount || result.OldPrivateVariableCount != result.NewPrivateVariableCount || result.HasArgumentEntries || result.HasVariableEntries || result.HasPrivateVariableEntries) { return result; } else { return null; } } internal int? GetOldVariableIndex(int newIndex) { EnvironmentUpdateMapEntry environmentEntry = FindByNewIndex(this.VariableEntries, newIndex); if (environmentEntry != null) { return environmentEntry.IsAddition ? (int?)null : environmentEntry.OldOffset; } return null; } internal int? GetNewVariableIndex(int oldIndex) { foreach (EnvironmentUpdateMapEntry environmentEntry in this.VariableEntries) { if (environmentEntry.OldOffset == oldIndex) { return environmentEntry.NewOffset; } } return null; } internal int? GetNewPrivateVariableIndex(int oldIndex) { foreach (EnvironmentUpdateMapEntry environmentEntry in this.PrivateVariableEntries) { if (environmentEntry.OldOffset == oldIndex) { return environmentEntry.NewOffset; } } return null; } static void ThrowIfMapsIncompatible(EnvironmentUpdateMap first, EnvironmentUpdateMap second, DynamicUpdateMap.MergeErrorContext errorContext) { if (first.NewArgumentCount != second.OldArgumentCount || first.NewVariableCount != second.OldVariableCount || first.NewPrivateVariableCount != second.OldPrivateVariableCount) { errorContext.Throw(SR.InvalidMergeMapEnvironmentCount( first.NewArgumentCount, first.NewVariableCount, first.NewPrivateVariableCount, second.OldArgumentCount, second.OldVariableCount, second.OldPrivateVariableCount)); } } static IList Merge(int finalCount, IList first, IList second) { List result = new List(); for (int i = 0; i < finalCount; i++) { EnvironmentUpdateMapEntry resultEntry = MergeEntry(i, first, second); if (resultEntry != null) { result.Add(resultEntry); } } return result.Count > 0 ? result : null; } static EnvironmentUpdateMapEntry MergeEntry(int finalIndex, IList first, IList second) { EnvironmentUpdateMapEntry secondEntry = FindByNewIndex(second, finalIndex); EnvironmentUpdateMapEntry firstEntry; if (secondEntry != null) { firstEntry = secondEntry.IsAddition ? null : FindByNewIndex(first, secondEntry.OldOffset); } else { firstEntry = FindByNewIndex(first, finalIndex); } return EnvironmentUpdateMapEntry.Merge(firstEntry, secondEntry); } static EnvironmentUpdateMapEntry FindByNewIndex(IList entries, int newIndex) { foreach (EnvironmentUpdateMapEntry environmentEntry in entries) { if (environmentEntry.NewOffset == newIndex) { return environmentEntry; } } return null; } } }