/// <summary> /// 生成指定类型的 Switch 代码块,使用差异位匹配算法。 /// </summary> /// <typeparam name="T">指定类型</typeparam> /// <param name="ilGen">ILGenerator IL 指令生成器</param> /// <param name="emitLoadValue">生成加载 Switch 参数的指令的委托</param> /// <param name="comparer">差异位比较器</param> /// <param name="cases">case 标签块集合</param> /// <param name="defaultLabel">默认标签块</param> /// <param name="emitLoadItem">生成加载指定 Case 块值的指定的委托</param> public static void DifferenceSwitch <T>(ILGenerator ilGen, Action <ILGenerator> emitLoadValue, Action <ILGenerator, T> emitLoadItem, IDifferenceComparer <T> comparer, CaseInfo <T>[] cases, Label defaultLabel) { var lengthGroup = new LengthGroup <T>(cases, comparer); if (lengthGroup.GetDepth() > DifferenceSwitchMaxDepth) { throw new ArgumentException("Groups too deep."); } var lengthCases = new CaseInfo <int> [lengthGroup.Groups.Count]; for (int i = 0; i < lengthCases.Length; i++) { lengthCases[i] = new CaseInfo <int>(lengthGroup.Groups[i].length, ilGen.DefineLabel()) { Tag = lengthGroup.Groups[i].group }; } Switch(ilGen, (ilGen2) => { emitLoadValue(ilGen2); comparer.EmitGetLength(ilGen2); }, lengthCases, defaultLabel); DifferenceCasesProcess(ilGen, emitLoadValue, emitLoadItem, comparer, defaultLabel, lengthCases); }
private static void DifferenceSwitch(ILGenerator iLGen, Action <ILGenerator> emitLdcValue, MethodInfo stringEqualsMethod, MethodInfo stringCharAtMethod, CaseInfo <string>[] cases, Label defaultLabel, Action <ILGenerator, string> itemLdcValue) { var lengthGroup = new StringLengthGroup <CaseInfo <string> >(cases, item => item.Value); if (lengthGroup.GetDepth() > DifferenceSwitchMaxDepth) { throw new ArgumentException("Groups too deep."); } var lengthCases = new CaseInfo <int> [lengthGroup.Groups.Count]; for (int i = 0; i < lengthCases.Length; i++) { lengthCases[i] = new CaseInfo <int>(lengthGroup.Groups[i].Key, iLGen.DefineLabel()) { Tag = lengthGroup.Groups[i].Value }; } Switch(iLGen, (ilGen2) => { emitLdcValue(ilGen2); ilGen2.Call(StringGetLengthMethod); }, lengthCases, defaultLabel); DifferenceCasesProcess(iLGen, emitLdcValue, stringEqualsMethod, stringCharAtMethod, itemLdcValue, defaultLabel, lengthCases); }
private static void DifferenceCasesProcess <TString>( ILGenerator iLGen, Action <ILGenerator> emitLoadValue, Action <ILGenerator, TString> emitLoadItem, IDifferenceComparer <TString> comparer, Label defaultLabel, CaseInfo <int>[] differenceCases) { foreach (var item in differenceCases) { iLGen.MarkLabel(item.Label); if (item.Tag is SingleGroup <TString> singleGroup) { if (SwitchDoNotVerify) { iLGen.Branch(singleGroup.Value.Label); } else { emitLoadValue(iLGen); emitLoadItem(iLGen, singleGroup.Value.Value); comparer.EmitEquals(iLGen); iLGen.BranchTrue(singleGroup.Value.Label); iLGen.Branch(defaultLabel); } } else if (item.Tag is DifferenceGroup <TString> differenceGroup) { var charCases = new CaseInfo <int> [differenceGroup.Groups.Count]; for (int i = 0; i < charCases.Length; i++) { charCases[i] = new CaseInfo <int>(differenceGroup.Groups[i].chr, iLGen.DefineLabel()) { Tag = differenceGroup.Groups[i].group }; } Switch(iLGen, (ilGen2) => { emitLoadValue(ilGen2); ilGen2.LoadConstant(differenceGroup.Index); comparer.EmitElementAt(iLGen); }, charCases, defaultLabel); DifferenceCasesProcess(iLGen, emitLoadValue, emitLoadItem, comparer, defaultLabel, charCases); } else { throw new NotSupportedException(); } } }
private static void DifferenceCasesProcess( ILGenerator iLGen, Action <ILGenerator> emitLdcValue, MethodInfo stringEqualsMethod, MethodInfo stringCharAtMethod, Action <ILGenerator, string> itemLdcValue, Label defaultLabel, CaseInfo <int>[] differenceCases) { foreach (var item in differenceCases) { iLGen.MarkLabel(item.Label); if (item.Tag is StringSingleGroup <CaseInfo <string> > singleGroup) { emitLdcValue(iLGen); itemLdcValue(iLGen, singleGroup.Value.Value); iLGen.Call(stringEqualsMethod); iLGen.Emit(OpCodes.Brtrue, singleGroup.Value.Label); } else if (item.Tag is StringDifferenceGroup <CaseInfo <string> > differenceGroup) { var charCases = new CaseInfo <int> [differenceGroup.Groups.Count]; for (int i = 0; i < charCases.Length; i++) { charCases[i] = new CaseInfo <int>(differenceGroup.Groups[i].Key, iLGen.DefineLabel()) { Tag = differenceGroup.Groups[i].Value }; } Switch(iLGen, (ilGen2) => { emitLdcValue(ilGen2); ilGen2.LoadConstant(differenceGroup.Index); ilGen2.Call(stringCharAtMethod); }, charCases, defaultLabel); DifferenceCasesProcess(iLGen, emitLdcValue, stringEqualsMethod, stringCharAtMethod, itemLdcValue, defaultLabel, charCases); } else { throw new NotSupportedException(); } } }
/// <summary> /// 生成 Switch(String) 代码块。 /// </summary> /// <param name="iLGen">ILGenerator IL 指令生成器</param> /// <param name="emitLdcValue">生成加载 Switch 参数的指令的委托</param> /// <param name="cases">case 标签块集合</param> /// <param name="defaultLabel">默认标签块</param> /// <param name="ignoreCase">是否忽略大小写</param> private static void HashSwitch(this ILGenerator iLGen, Action <ILGenerator> emitLdcValue, CaseInfo <string>[] cases, Label defaultLabel, bool ignoreCase = false) { Func <string, int> funcGetHashCode; Func <string, string, bool> funcEquals; if (ignoreCase) { funcGetHashCode = StringHelper.GetUpperedHashCode; funcEquals = StringHelper.IgnoreCaseEqualsByUpper; cases = (CaseInfo <string>[])cases.Clone(); for (int i = 0; i < cases.Length; i++) { cases[i] = new CaseInfo <string>(cases[i].Value.ToUpper(), cases[i].Label); } } else { funcGetHashCode = StringHelper.GetHashCode; funcEquals = StringHelper.Equals; } foreach (var item in cases) { item.HashCode = funcGetHashCode(item.Value); } Switch( iLGen, emitLdcValue, funcGetHashCode.Method, funcEquals.Method, cases, defaultLabel, (tILGen, value) => tILGen.Emit(OpCodes.Ldstr, value)); }
/// <summary> /// 生成 Switch(String) 代码块。字符串差异位置比较,通常情况下这比 Hash 比较要快。 /// </summary> /// <param name="ilGen">ILGenerator IL 指令生成器</param> /// <param name="loadValue">生成加载 Switch 参数的指令的委托</param> /// <param name="cases">case 标签块集合</param> /// <param name="defaultLabel">默认标签块</param> /// <param name="ignoreCase">是否忽略大小写</param> private static void DifferenceSwitch(this ILGenerator ilGen, Action <ILGenerator> loadValue, CaseInfo <string>[] cases, Label defaultLabel, bool ignoreCase = false) { if (ignoreCase) { cases = TypeHelper.Clone(cases); for (int i = 0; i < cases.Length; i++) { cases[i] = new CaseInfo <string>(cases[i].Value.ToUpper(), cases[i].Label); } DifferenceSwitch( ilGen, loadValue, ((Func <string, string, bool>)StringHelper.IgnoreCaseEqualsByUpper).Method, StringUpperCharArMethod, cases, defaultLabel, ItemLdcValue); } else { DifferenceSwitch( ilGen, loadValue, ((Func <string, string, bool>)StringHelper.Equals).Method, StringCharAtMethod, cases, defaultLabel, ItemLdcValue); } void ItemLdcValue(ILGenerator il, string value) { il.Emit(OpCodes.Ldstr, value); } }
/// <summary> /// 生成 Switch(String) 代码块。字符串差异位置比较,通常情况下这比 Hash 比较要快。 /// </summary> /// <param name="ILGen">ILGenerator IL 指令生成器</param> /// <param name="EmitLdcValue">生成加载 Switch 参数的指令的委托</param> /// <param name="Cases">case 标签块集合</param> /// <param name="DefaultLabel">默认标签块</param> /// <param name="IgnoreCase">是否忽略大小写</param> private static void DifferenceSwitch(this ILGenerator ILGen, Action <ILGenerator> EmitLdcValue, CaseInfo <string>[] Cases, Label DefaultLabel, bool IgnoreCase = false) { Action <ILGenerator, string> ItemLdcValue = (tILGen, value) => { tILGen.Emit(OpCodes.Ldstr, value); }; if (IgnoreCase) { Cases = (CaseInfo <string>[])Cases.Clone(); for (int i = 0; i < Cases.Length; i++) { Cases[i] = new CaseInfo <string>(Cases[i].Value.ToUpper(), Cases[i].Label); } DifferenceSwitch( ILGen, EmitLdcValue, ((Func <string, string, bool>)StringHelper.IgnoreCaseEquals).Method, StringUpperCharArMethod, Cases, DefaultLabel, ItemLdcValue); } else { DifferenceSwitch( ILGen, EmitLdcValue, ((Func <string, string, bool>)StringHelper.Equals).Method, StringCharAtMethod, Cases, DefaultLabel, ItemLdcValue); } }
/// <summary> /// 生成 Switch(String) 代码块。 /// </summary> /// <param name="iLGen">ILGenerator IL 指令生成器</param> /// <param name="emitLdcValue">生成加载 Switch 参数的指令的委托</param> /// <param name="cases">case 标签块集合</param> /// <param name="defaultLabel">默认标签块</param> /// <param name="ignoreCase">是否忽略大小写</param> private static void HashSwitch(this ILGenerator iLGen, Action <ILGenerator> emitLdcValue, CaseInfo <string>[] cases, Label defaultLabel, bool ignoreCase = false) { Action <ILGenerator, string> itemLdcValue = (tILGen, value) => { tILGen.Emit(OpCodes.Ldstr, value); }; if (ignoreCase) { cases = (CaseInfo <string>[])cases.Clone(); for (int i = 0; i < cases.Length; i++) { cases[i] = new CaseInfo <string>(cases[i].Value.ToUpper(), cases[i].Label); } Switch( iLGen, emitLdcValue, ((Func <string, int>)StringHelper.IgnoreCaseGetHashCode).Method, ((Func <string, string, bool>)StringHelper.IgnoreCaseEquals).Method, cases, defaultLabel, itemLdcValue); } else { Switch( iLGen, emitLdcValue, ((Func <string, int>)StringHelper.GetHashCode).Method, ((Func <string, string, bool>)StringHelper.Equals).Method, cases, defaultLabel, itemLdcValue); } }
/// <summary> /// 与另一个 Case 块信息比较 HashCode 的大小。 /// </summary> /// <param name="other">Case 块信息</param> /// <returns>返回大于 0 则比它大,小于 0 则比它小,否则一样大</returns> public int CompareTo(CaseInfo <T> other) { return(HashCode.CompareTo(other.HashCode)); }