Example #1
0
        /// <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);
        }
Example #2
0
        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);
        }
Example #3
0
        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();
                }
            }
        }
Example #4
0
        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();
                }
            }
        }
Example #5
0
        /// <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));
        }
Example #6
0
        /// <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);
            }
        }
Example #7
0
        /// <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);
            }
        }
Example #8
0
        /// <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);
            }
        }
Example #9
0
 /// <summary>
 /// 与另一个 Case 块信息比较 HashCode 的大小。
 /// </summary>
 /// <param name="other">Case 块信息</param>
 /// <returns>返回大于 0 则比它大,小于 0 则比它小,否则一样大</returns>
 public int CompareTo(CaseInfo <T> other)
 {
     return(HashCode.CompareTo(other.HashCode));
 }