Did you realize that you're using a shared cache, which is already filled
with delegates when you run the fourth step?

On Sat, Mar 7, 2009 at 16:45, webpaul <[email protected]> wrote:

>
> Until I know how you want to handle multi key dictionaries in your
> code base I'm not going to submit a patch. Below is how I did it with
> a class I usually use for that, more details at:
> http://www.codeproject.com/KB/recipes/ClassKey.aspx
>
> If anyone is interested, the LINQ expressions used in the LCG have a
> checked/unchecked version which is why it didn't have the overflow
> issue. As far as I can tell type converters don't have that feature
> and using an unchecked block doesn't stop it from throwing an
> exception. When the type converters are cached they are better than
> the cached LCG unless I'm doing something wrong here.
>
> Performance from worst to best, with the original test rows plus one
> more for overflow condition:
>
> 10K iterations * 5 tests per iteration:
>
> LCG compiled each time - 8043ms
> TypeConverter with try/catch : 869ms
> LCG cached: 143ms
> TypeConverter without try/catch (exception on overflow): 82ms
> Type converter with try/catch cached: 23ms
>
>    class Program
>    {
>        static void Main(string[] args)
>        {
>            RunComparisons(CreateComparerLCG);
>            RunComparisons(CreateComparerTypeConverter);
>             RunComparisons(CreateComparerLCGCachedClass);
>            RunComparisons(CreateComparerTypeConverterCached);
>         }
>
>        //Comparison types
>
>        private static Func<object, object, bool>
> CreateComparerTypeConverter(Type firstType, Type secondType)
>        {
>            if (firstType == secondType)
>                return Equals;
>
>            TypeConverter converterFirstType =
> TypeDescriptor.GetConverter(firstType);
>            TypeConverter converterSecondType =
> TypeDescriptor.GetConverter(secondType);
>
>            return delegate(object first, object second)
>            {
>                try
>                {
>                    return object.Equals(
>                        first,
>                        converterFirstType.ConvertTo(second,
> firstType)
>                    );
>                }
>                catch (OverflowException)
>                {
>                    return object.Equals(
>                        second,
>                        converterSecondType.ConvertTo(first,
> secondType)
>                    );
>                }
>            };
>        }
>
>        private static Func<object, object, bool> CreateComparerLCG
> (Type firstType, Type secondType)
>        {
>            if (firstType == secondType)
>                return Equals;
>
>            var firstParameter = Expression.Parameter(typeof(object),
> "first");
>            var secondParameter = Expression.Parameter(typeof(object),
> "second");
>
>            var equalExpression = Expression.Equal(Expression.Convert
> (firstParameter, firstType),
>                Expression.Convert(Expression.Convert(secondParameter,
> secondType), firstType));
>
>            return Expression.Lambda<Func<object, object, bool>>
> (equalExpression, firstParameter, secondParameter).Compile();
>        }
>
>         private class CacheKey : ClassKey<CacheKey>
>        {
>            public Type FirstType = null;
>            public Type SecondType = null;
>
>            public override object[] GetKeyValues()
>            {
>                return new object[] { FirstType, SecondType };
>            }
>        }
>
>        private class ComparerCacheClass : Dictionary<CacheKey,
> Func<object, object, bool>> { }
>        private static readonly ComparerCacheClass comparerCacheClass
> = new ComparerCacheClass();
>         private static Func<object, object, bool>
> CreateComparerLCGCachedClass(Type firstType, Type secondType)
>         {
>            if (firstType == secondType)
>                return Equals;
>
>            var firstParameter = Expression.Parameter(typeof(object),
> "first");
>            var secondParameter = Expression.Parameter(typeof(object),
> "second");
>
>            var equalExpression = Expression.Equal(Expression.Convert
> (firstParameter, firstType),
>                Expression.Convert(Expression.Convert(secondParameter,
> secondType), firstType));
>
>             Func<object, object, bool> compareExpression = null;
>            CacheKey key = new CacheKey { FirstType = firstType,
> SecondType = secondType };
>            if (!comparerCacheClass.TryGetValue(key, out
> compareExpression))
>            {
>                compareExpression = Expression.Lambda<Func<object,
> object, bool>>(equalExpression, firstParameter,
> secondParameter).Compile();
>                 comparerCacheClass.Add(key, compareExpression);
>            }
>
>            return compareExpression;
>         }
>
>        private static Func<object, object, bool>
> CreateComparerTypeConverterCached(Type firstType, Type secondType)
>         {
>            if (firstType == secondType)
>                return Equals;
>
>             Func<object, object, bool> compareExpression = null;
>            CacheKey key = new CacheKey { FirstType = firstType,
> SecondType = secondType };
>            if (!comparerCacheClass.TryGetValue(key, out
> compareExpression))
>             {
>                TypeConverter converterFirstType =
> TypeDescriptor.GetConverter(firstType);
>                TypeConverter converterSecondType =
> TypeDescriptor.GetConverter(secondType);
>
>                 compareExpression = delegate(object first, object
> second)
>                {
>                    try
>                    {
>                        return object.Equals(
>                            first,
>                            converterFirstType.ConvertTo(second,
> firstType)
>                        );
>                    }
>                    catch (OverflowException)
>                    {
>                        return object.Equals(
>                            second,
>                            converterSecondType.ConvertTo(first,
> secondType)
>                        );
>                    }
>                };
>
>                 comparerCacheClass.Add(key, compareExpression);
>            }
>
>            return compareExpression;
>         }
>
>        private static void RunComparisons(Func<Type, Type,
> Func<object, object, bool>> createComparer)
>        {
>            List<Comparison> comparisonsToMake = new List<Comparison>
> {
>                new Comparison { item = (byte)1, otherItem = (int)1 },
>                new Comparison { item = (int)1, otherItem = (long)1 },
>                new Comparison { item = (long)1, otherItem = (float)
> 1 },
>                new Comparison { item = (float)1, otherItem = (double)
> 1 },
>                new Comparison { item = (byte)byte.MaxValue, otherItem
> = (int)int.MaxValue, expectedValue = false },
>            };
>
>            Program program = new Program();
>
>            Stopwatch watch = new Stopwatch();
>            watch.Start();
>            for (int i = 0; i < 10000; i++)
>            {
>                foreach (var comparison in comparisonsToMake)
>                {
>                    if (program.Compare(comparison, createComparer) !=
> comparison.expectedValue)
>                        throw new ApplicationException("Comparison
> didn't work");
>                }
>            };
>            watch.Stop();
>            Console.WriteLine("All comparisons took " +
> watch.ElapsedMilliseconds + "ms");
>        }
>
>        private class Comparison
>        {
>            public object item;
>            public object otherItem;
>            public bool expectedValue = true;
>        }
>
>        private bool Compare(Comparison comparison, Func<Type, Type,
> Func<object, object, bool>> createComparer)
>        {
>            object item = comparison.item;
>            object otherItem = comparison.otherItem;
>
>            if (item == null | otherItem == null)
>                return item == null & otherItem == null;
>
>            var equalityComparer = createComparer(item.GetType(),
> otherItem.GetType());
>
>            return equalityComparer(item, otherItem);
>        }
>
>    }
>
>
> On Mar 7, 8:36 am, Simone Busoli <[email protected]> wrote:
> > Sorry Paul, I'm not going to reply anymore. Write a test, write a patch
> and
> > submit it if you think that using type converters is a better option.
> >
> >
> >
> > On Sat, Mar 7, 2009 at 15:32, webpaul <[email protected]> wrote:
> >
> > > Type converter is still faster than dictionary cached LCG (without
> > > overflow problem solved) and I'm not even caching the type converter
> > > yet... The LCG solution does handle the overflow condition gracefully
> > > and I don't fully understand how it isn't overflowing, can you explain
> > > how what you are doing doesn't fail when converting int.MaxValue to a
> > > byte?
> >
> > > Also, how do you guys handle multi-key dictionaries typically? I have
> > > a way but am curious how you usually do it.
> >
> > > On Mar 6, 10:02 am, Simone Busoli <[email protected]> wrote:
> > > > Try caching the LCG comparer, you'll be surprised.
> >
> > > > On Fri, Mar 6, 2009 at 16:46, webpaul <[email protected]> wrote:
> >
> > > > > This one takes 1000ms vs 6500ms but it handles one of the types
> being
> > > > > an overflow for the other. I couldn't find a way to detect if there
> > > > > will be an overflow for a specific value without actually catching
> the
> > > > > overflow exception which makes this take much longer. Any ideas?
> >
> > > > >    class Program
> > > > >    {
> > > > >        static void Main(string[] args)
> > > > >        {
> > > > >            RunComparisons(CreateComparerLCG);
> > > > >             RunComparisons(CreateComparerTypeConverter);
> > > > >         }
> >
> > > > >        //Comparison types
> >
> > > > >        private static Func<object, object, bool>
> > > > > CreateComparerTypeConverter(Type firstType, Type secondType)
> > > > >        {
> > > > >            if (firstType == secondType)
> > > > >                return Equals;
> >
> > > > >            TypeConverter converterFirstType =
> > > > > TypeDescriptor.GetConverter(firstType);
> > > > >            TypeConverter converterSecondType =
> > > > > TypeDescriptor.GetConverter(secondType);
> >
> > > > >            return delegate(object first, object second)
> > > > >            {
> > > > >                 try
> > > > >                {
> > > > >                    return object.Equals(
> > > > >                        first,
> > > > >                        converterFirstType.ConvertTo(second,
> > > > > firstType)
> > > > >                    );
> > > > >                }
> > > > >                catch (OverflowException)
> > > > >                {
> > > > >                    return object.Equals(
> > > > >                        second,
> > > > >                        converterSecondType.ConvertTo(first,
> > > > > secondType)
> > > > >                    );
> > > > >                 }
> > > > >            };
> > > > >        }
> >
> > > > >        private static Func<object, object, bool> CreateComparerLCG
> > > > > (Type firstType, Type secondType)
> > > > >        {
> > > > >            if (firstType == secondType)
> > > > >                return Equals;
> >
> > > > >            var firstParameter =
> Expression.Parameter(typeof(object),
> > > > > "first");
> > > > >            var secondParameter =
> Expression.Parameter(typeof(object),
> > > > > "second");
> >
> > > > >            var equalExpression =
> Expression.Equal(Expression.Convert
> > > > > (firstParameter, firstType),
> > > > >
>  Expression.Convert(Expression.Convert(secondParameter,
> > > > > secondType), firstType));
> >
> > > > >            return Expression.Lambda<Func<object, object, bool>>
> > > > > (equalExpression, firstParameter, secondParameter).Compile();
> > > > >        }
> >
> > > > >        private static void RunComparisons(Func<Type, Type,
> > > > > Func<object, object, bool>> createComparer)
> > > > >        {
> > > > >            List<Comparison> comparisonsToMake = new
> List<Comparison>
> > > > > {
> > > > >                new Comparison { item = (byte)1, otherItem = (int)1
> },
> > > > >                new Comparison { item = (int)1, otherItem = (long)1
> },
> > > > >                new Comparison { item = (long)1, otherItem = (float)
> > > > > 1 },
> > > > >                new Comparison { item = (float)1, otherItem =
> (double)
> > > > > 1 },
> > > > >                 new Comparison { item = (byte)byte.MaxValue,
> otherItem
> > > > > = (int)int.MaxValue, expectedValue = false },
> > > > >             };
> >
> > > > >            Program program = new Program();
> >
> > > > >            Stopwatch watch = new Stopwatch();
> > > > >            watch.Start();
> > > > >            for (int i = 0; i < 10000; i++)
> > > > >            {
> > > > >                foreach (var comparison in comparisonsToMake)
> > > > >                {
> > > > >                     if (program.Compare(comparison, createComparer)
> !=
> > > > > comparison.expectedValue)
> > > > >                         throw new ApplicationException("Comparison
> > > > > didn't work");
> > > > >                }
> > > > >            };
> > > > >            watch.Stop();
> > > > >            Console.WriteLine("All comparisons took " +
> > > > > watch.ElapsedMilliseconds + "ms");
> > > > >        }
> >
> > > > >        private class Comparison
> > > > >        {
> > > > >            public object item;
> > > > >            public object otherItem;
> > > > >             public bool expectedValue = true;
> > > > >         }
> >
> > > > >        private bool Compare(Comparison comparison, Func<Type, Type,
> > > > > Func<object, object, bool>> createComparer)
> > > > >        {
> > > > >            object item = comparison.item;
> > > > >            object otherItem = comparison.otherItem;
> >
> > > > >            if (item == null | otherItem == null)
> > > > >                return item == null & otherItem == null;
> >
> > > > >            var equalityComparer = createComparer(item.GetType(),
> > > > > otherItem.GetType());
> >
> > > > >            return equalityComparer(item, otherItem);
> > > > >        }
> >
> > > > >    }
> >
> > > > > On Mar 6, 9:23 am, webpaul <[email protected]> wrote:
> > > > > > This does it in 93ms vs. 6500ms on my box, could be improved with
> a
> > > > > > Dictionary as well. Also, it always converts to the first type so
> if
> > > > > > you compare byte.MaxValue with int.MaxValue you get an exception.
> It
> > > > > > should convert to the largest type so I'll see what I can do on
> that
> > > > > > as well.
> >
> > > > > >         private static Func<object, object, bool>
> > > > > > CreateComparerTypeConverter(Type firstType, Type secondType)
> > > > > >         {
> > > > > >             if (firstType == secondType)
> > > > > >                 return Equals;
> >
> > > > > >             TypeConverter converterFirstType =
> > > > > > TypeDescriptor.GetConverter(firstType);
> > > > > >             TypeConverter converterSecondType =
> > > > > > TypeDescriptor.GetConverter(firstType);
> >
> > > > > >             return delegate(object first, object second)
> > > > > >             {
> > > > > >                 return
> > > > > >                     object.Equals(
> > > > > >                         converterFirstType.ConvertTo(first,
> > > > > > firstType),
> > > > > >                         converterFirstType.ConvertTo(
> > > > > >                             converterSecondType.ConvertTo(second,
> > > > > > secondType),
> > > > > >                             firstType
> > > > > >                         )
> > > > > >                     )
> > > > > >                 ;
> > > > > >             };
> > > > > >         }
> >
> > > > > > On Mar 6, 9:10 am, webpaul <[email protected]> wrote:
> >
> > > > > > > It's pretty slow as is - takes 6.5 seconds for 10K iterations.
> I'm
> > > > > > > going to try it a few different ways and see which is fastest.
> >
> > > > > > >     class Program
> > > > > > >     {
> > > > > > >         static void Main(string[] args)
> > > > > > >         {
> > > > > > >             RunComparisons(CreateComparerLCG);
> > > > > > >         }
> >
> > > > > > >         //Comparison types
> >
> > > > > > >         private static Func<object, object, bool>
> CreateComparerLCG
> > > > > > > (Type firstType, Type secondType)
> > > > > > >         {
> > > > > > >             if (firstType == secondType)
> > > > > > >                 return Equals;
> >
> > > > > > >             var firstParameter =
> > > Expression.Parameter(typeof(object),
> > > > > > > "first");
> > > > > > >             var secondParameter =
> > > Expression.Parameter(typeof(object),
> > > > > > > "second");
> >
> > > > > > >             var equalExpression =
> > > Expression.Equal(Expression.Convert
> > > > > > > (firstParameter, firstType),
> >
> > > Expression.Convert(Expression.Convert(secondParameter,
> > > > > > > secondType), firstType));
> >
> > > > > > >             return Expression.Lambda<Func<object, object,
> bool>>
> > > > > > > (equalExpression, firstParameter, secondParameter).Compile();
> > > > > > >         }
> >
> > > > > > >         private static void RunComparisons(Func<Type, Type,
> > > > > > > Func<object, object, bool>> createComparer)
> > > > > > >         {
> > > > > > >             List<Comparison> comparisonsToMake = new
> > > List<Comparison>
> > > > > > > {
> > > > > > >                 new Comparison { item = (byte)1, otherItem =
> (int)1
> > > },
> > > > > > >                 new Comparison { item = (int)1, otherItem =
> (long)1
> > > },
> > > > > > >                 new Comparison { item = (long)1, otherItem =
> > > (float)
> > > > > > > 1 },
> > > > > > >                 new Comparison { item = (float)1, otherItem =
> > > (double)
> > > > > > > 1 },
> > > > > > >             };
> >
> > > > > > >             Program program = new Program();
> >
> > > > > > >             Stopwatch watch = new Stopwatch();
> > > > > > >             watch.Start();
> > > > > > >             for (int i = 0; i < 10000; i++)
> > > > > > >             {
> > > > > > >                 foreach (var comparison in comparisonsToMake)
> > > > > > >                 {
> > > > > > >                     if (!program.Compare(comparison,
> > > createComparer))
> > > > > > >                         throw new
> ApplicationException("Comparison
> > > > > > > didn't work");
> > > > > > >                 }
> > > > > > >             };
> > > > > > >             watch.Stop();
> > > > > > >             Console.WriteLine("All comparisons took " +
> > > > > > > watch.ElapsedMilliseconds + "ms");
> > > > > > >         }
> >
> > > > > > >         private class Comparison
> > > > > > >         {
> > > > > > >             public object item;
> >
> > ...
> >
> > read more ยป- Hide quoted text -
> >
> > - Show quoted text -
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Rhino Tools Dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/rhino-tools-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to