300 lines
9.7 KiB
C#
300 lines
9.7 KiB
C#
|
//-----------------------------------------------------------------------------
|
||
|
// 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<EnvironmentUpdateMapEntry> variableEntries;
|
||
|
IList<EnvironmentUpdateMapEntry> privateVariableEntries;
|
||
|
IList<EnvironmentUpdateMapEntry> 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<EnvironmentUpdateMapEntry> SerializedVariableEntries
|
||
|
{
|
||
|
get { return this.variableEntries; }
|
||
|
set { this.variableEntries = value; }
|
||
|
}
|
||
|
|
||
|
[DataMember(EmitDefaultValue = false, Name = "privateVariableEntries")]
|
||
|
internal IList<EnvironmentUpdateMapEntry> SerializedPrivateVariableEntries
|
||
|
{
|
||
|
get { return this.privateVariableEntries; }
|
||
|
set { this.privateVariableEntries = value; }
|
||
|
}
|
||
|
|
||
|
[DataMember(EmitDefaultValue = false, Name = "argumentEntries")]
|
||
|
internal IList<EnvironmentUpdateMapEntry> 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<EnvironmentUpdateMapEntry> VariableEntries
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this.variableEntries == null)
|
||
|
{
|
||
|
this.variableEntries = new List<EnvironmentUpdateMapEntry>();
|
||
|
}
|
||
|
|
||
|
return this.variableEntries;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IList<EnvironmentUpdateMapEntry> PrivateVariableEntries
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this.privateVariableEntries == null)
|
||
|
{
|
||
|
this.privateVariableEntries = new List<EnvironmentUpdateMapEntry>();
|
||
|
}
|
||
|
|
||
|
return this.privateVariableEntries;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IList<EnvironmentUpdateMapEntry> ArgumentEntries
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this.argumentEntries == null)
|
||
|
{
|
||
|
this.argumentEntries = new List<EnvironmentUpdateMapEntry>();
|
||
|
}
|
||
|
|
||
|
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<EnvironmentUpdateMapEntry> Merge(int finalCount, IList<EnvironmentUpdateMapEntry> first,
|
||
|
IList<EnvironmentUpdateMapEntry> second)
|
||
|
{
|
||
|
List<EnvironmentUpdateMapEntry> result = new List<EnvironmentUpdateMapEntry>();
|
||
|
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<EnvironmentUpdateMapEntry> first,
|
||
|
IList<EnvironmentUpdateMapEntry> 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<EnvironmentUpdateMapEntry> entries, int newIndex)
|
||
|
{
|
||
|
foreach (EnvironmentUpdateMapEntry environmentEntry in entries)
|
||
|
{
|
||
|
if (environmentEntry.NewOffset == newIndex)
|
||
|
{
|
||
|
return environmentEntry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|