<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx</link><description>Jomo Fisher—I’ve run into a performance problem several times in my career that I’ve never found a truly satisfying answer for until now. The problem can be distilled down to this: Look up a value based on a string key. The set of strings is fixed and</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#1980208</link><pubDate>Wed, 28 Mar 2007 23:38:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1980208</guid><dc:creator>Jeff</dc:creator><description>&lt;P&gt;That's pretty impressive performance for a VM-based language. &amp;nbsp;The C++ equivelent, 1 million iterations, runs in about 55 ms, on a Pentium 4, 3.4 Ghz. &amp;nbsp;Here's the code:&lt;/P&gt;
&lt;P&gt;struct KeyValue {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;const char* key;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;inline bool operator &amp;lt; (const KeyValue&amp;amp; that) const {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;return strcmp(this-&amp;gt;key, that.key) &amp;lt; 0;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;static const KeyValue kvs[] = {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"bashful", 6},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"doc", 7},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"dopey", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"grumpy", 2},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"happy", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sleepy", 8},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sneezy", 2},&lt;/P&gt;
&lt;P&gt;}, * const kvs_end = kvs + (sizeof(kvs) / sizeof(0[kvs]));&lt;/P&gt;
&lt;P&gt;inline int Lookup(const char* s) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;KeyValue key = { s };&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return std::lower_bound(kvs, kvs_end, key)-&amp;gt;value;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;int _tmain(int argc, _TCHAR* argv[])&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp;LARGE_INTEGER begin, end, frequency;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;begin);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;const KeyValue* k = kvs;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int total = 0; &amp;nbsp;// Just so the compiler doesn't completely optimize out the for loop.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;for (int i = 0; i &amp;lt; 1000000; ++i) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;total &amp;nbsp;+= Lookup(k-&amp;gt;key);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;if (++k == kvs_end)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;k = kvs;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;end);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceFrequency(&amp;amp;frequency);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;__int64 ms = (end.QuadPart - begin.QuadPart) * 1000 / frequency.QuadPart;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Total:\t" &amp;lt;&amp;lt; total &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Milliseconds:\t" &amp;lt;&amp;lt; ms &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;One minor benefit of the C++ code is that there is no overhead of creating a lookup table before the first call to Lookup().&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#1989932</link><pubDate>Thu, 29 Mar 2007 21:43:06 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1989932</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Hi Jeff,&lt;/p&gt;
&lt;p&gt;I tried your code on my machine and amazingly got exactly 55ms. That makes your orange look a little more like my apple. &lt;/p&gt;
&lt;p&gt;Your comment made me realize my implementation has one more feature that I could possibly throw away: there's an array bounds check on the string index operations. I think I could get rid of this by emitting 'unsafe' code. Unfortunately, I think I'd have to bypass the expression compiler to do this.&lt;/p&gt;
&lt;p&gt;I seem to be within spitting distance of optimized C++, that's pretty cool considering how amazing the VS C++ optimizer is.&lt;/p&gt;
&lt;p&gt;Jomo&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#1990041</link><pubDate>Thu, 29 Mar 2007 22:09:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1990041</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Here's my test code in case anyone wants to reproduce my result:&lt;/p&gt;
&lt;p&gt;/*&lt;/p&gt;
&lt;p&gt;Use of included script samples are subject to the terms specified at &lt;a rel="nofollow" target="_new" href="http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx"&gt;http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Written by Jomo Fisher&lt;/p&gt;
&lt;p&gt;*/&lt;/p&gt;
&lt;p&gt;using System;&lt;/p&gt;
&lt;p&gt;using System.Collections.Generic;&lt;/p&gt;
&lt;p&gt;using System.Linq;&lt;/p&gt;
&lt;p&gt;using System.Text;&lt;/p&gt;
&lt;p&gt;using System.Reflection;&lt;/p&gt;
&lt;p&gt;using FastSwitch;&lt;/p&gt;
&lt;p&gt;namespace ConsoleApplication1 {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;class Program {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;static void Main(string[] args) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var dict = new Dictionary&amp;lt;string, int&amp;gt; {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&amp;quot;happy&amp;quot;, 9}, {&amp;quot;sneezy&amp;quot;, 2},&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&amp;quot;doc&amp;quot;, 7}, {&amp;quot;sleepy&amp;quot;, 8},&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&amp;quot;dopey&amp;quot;, 9}, {&amp;quot;grumpy&amp;quot;, 2},&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&amp;quot;bashful&amp;quot;, 6}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;};&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const int count = 1000000;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DateTime start = DateTime.Now;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (int i = 0; i &amp;lt; count; ++i) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var v = dict[&amp;quot;happy&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;sneezy&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;doc&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;sleepy&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;dopey&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;grumpy&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = dict[&amp;quot;bashful&amp;quot;];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;TimeSpan elapsed = DateTime.Now - start;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Console.WriteLine(&amp;quot;Dictionary: {0} ms&amp;quot;, elapsed.TotalMilliseconds);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var compiled = SwitchCompiler.CreateSwitch(dict);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;start = DateTime.Now;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (int i = 0; i &amp;lt; count; ++i) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var v = compiled(&amp;quot;doc&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 7);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;happy&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 9);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;sneezy&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 2);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;sleepy&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 8);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;dopey&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 9);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;grumpy&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 2);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;v = compiled(&amp;quot;bashful&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;System.Diagnostics.Debug.Assert(v == 6);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;elapsed = DateTime.Now - start;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Console.WriteLine(&amp;quot;Compiled: {0} ms&amp;quot;, elapsed.TotalMilliseconds);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
</description></item><item><title>Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#1996394</link><pubDate>Sat, 31 Mar 2007 02:34:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1996394</guid><dc:creator>DotNetKicks.com</dc:creator><description>&lt;p&gt;You've been kicked (a good thing) - Trackback from DotNetKicks.com&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#1999790</link><pubDate>Sat, 31 Mar 2007 15:52:33 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1999790</guid><dc:creator>tom</dc:creator><description>&lt;P&gt;Looks like you want a perfect hash or a minimal perfect hash? See e.g. &lt;A href="http://burtleburtle.net/bob/hash/perfect.html" target=_new rel=nofollow&gt;http://burtleburtle.net/bob/hash/perfect.html&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;I don't know about a c# implementation though.&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2000018</link><pubDate>Sat, 31 Mar 2007 16:36:11 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2000018</guid><dc:creator>Justin</dc:creator><description>&lt;P&gt;The c++ code and c# code are timing 2 different things.&lt;/P&gt;
&lt;P&gt;the c++ code is cycling through each key for a total of 1,000,000 lookups. &amp;nbsp;the c# code is looking each key up 1,000,000 times for a total of 7,000,000 lookups.&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2012751</link><pubDate>Mon, 02 Apr 2007 19:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2012751</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Justin,&lt;/p&gt;
&lt;p&gt;You're right. I should have noticed the C++ code was doing 1/7th of the lookups as the C# code. When I adjust the C++ code, it dutifully reports 385ms which is pretty close to what the plain old .NET dictionary was doing.&lt;/p&gt;
&lt;p&gt;So I guess the LINQ algorithm is in the cat-bird seat, at least for a the time-being.&lt;/p&gt;
&lt;p&gt;I also noticed the C++ answer requires that the set of keys be sorted alphabetically before lookups can commence, so there *is* a little preparation time.&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2012799</link><pubDate>Mon, 02 Apr 2007 19:24:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2012799</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Tom,&lt;/p&gt;
&lt;p&gt;I had considered a minimal perfect hash (and I had even looked at the exact page you sent me). I still think the LINQ algorithm should perform better in many cases because that perfect hashing algorithm is O(n) on the number of bytes in the input key. The LINQ algorithm is O(log N) on the number of bytes in the key. In particular, I think the LINQ algorithm will outpace the other when the size of the keys is large and the length of the keys is non-uniform.&lt;/p&gt;
&lt;p&gt;Of course the big-O notation can hide a potentially large constant factor, but I don't really see why it would in this case here.&lt;/p&gt;
&lt;p&gt;Also, keep in mind that that particular minimal perfect hash implementation is throwing away a feature that I wanted to keep: It can't easily accomodate key sets that are available only at run time.&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2021148</link><pubDate>Wed, 04 Apr 2007 00:28:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2021148</guid><dc:creator>Jeff</dc:creator><description>&lt;P&gt;The C++ compiler optimized out the entire loop in my first version. &amp;nbsp;I added the total variable, and it still optimized out the whole loop. &amp;nbsp;I added the cout statement at the bottom and it finally executed the code.&lt;/P&gt;
&lt;P&gt;Any sign the C# compiler is optimizing out the whole loop in the C# code?&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2021398</link><pubDate>Wed, 04 Apr 2007 01:15:50 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2021398</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;The C# compiler is definitely not removing the loop--for one, it has no way to determine whether the delegate has side-effects that need to be preserved. &lt;/p&gt;
&lt;p&gt;This can be seen by increasing the number of iterations--2M loops run in twice the time as 1M.&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2021813</link><pubDate>Wed, 04 Apr 2007 02:37:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2021813</guid><dc:creator>Jeff</dc:creator><description>&lt;P&gt;Wow, your switch compiler and the .Net VM is very impressive indeed. &amp;nbsp;My fastest run of the following C++ code was 88 ms. &amp;nbsp;Note also that I kind of cheated and used std::find instead of std::lower_bound, because when there are only 1 or 2 elements in the vector, std::find runs much faster.&lt;/P&gt;
&lt;P&gt;#include "stdafx.h"&lt;/P&gt;
&lt;P&gt;struct KeyValue {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;const char* key;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int value;&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;struct CharValue {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int char_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;bool terminal_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;union {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;int value_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;size_t next_index_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;vector&amp;lt;CharValue&amp;gt;* next_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;};&lt;/P&gt;
&lt;P&gt;&amp;nbsp;ptrdiff_t char_step_;&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;inline bool operator &amp;lt; (const CharValue&amp;amp; value, int c) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return value.char_ &amp;lt; c;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;inline bool operator &amp;lt; (int c, const CharValue&amp;amp; value) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return c &amp;lt; value.char_;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;inline bool operator == (const CharValue&amp;amp; value, int c) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return value.char_ == c;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;static const KeyValue kvs[] = {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"bashful", 6},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"doc", 7},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"dopey", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"grumpy", 2},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"happy", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sleepy", 8},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sneezy", 2},&lt;/P&gt;
&lt;P&gt;}, * const kvs_end = kvs + (sizeof(kvs) / sizeof(0[kvs]));&lt;/P&gt;
&lt;P&gt;class KnownSetTrie {&lt;/P&gt;
&lt;P&gt;public:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;typedef vector&amp;lt;CharValue&amp;gt; CharMap;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;vector&amp;lt;CharMap&amp;gt; tree_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;ptrdiff_t first_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;KnownSetTrie(Iter begin, Iter end) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;first_step_ = Compile(begin, end, 0) - 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;// Now that the tree_ is stable, convert indices to node pointers.&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;for(vector&amp;lt;CharMap&amp;gt;::iterator i = tree_.begin(); i != tree_.end(); ++i) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;for (CharMap::iterator j = i-&amp;gt;begin(); j != i-&amp;gt;end(); ++j)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!j-&amp;gt;terminal_)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;j-&amp;gt;next_ = &amp;amp;tree_[j-&amp;gt;next_index_];&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;ptrdiff_t Compile(Iter begin, Iter end, ptrdiff_t char_index) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;CharMap map;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;Iter start = begin, i = begin + 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;while (true) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;CharValue value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;value.char_ = start-&amp;gt;key[char_index];&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (i != end &amp;amp;&amp;amp; i-&amp;gt;key[char_index] == start-&amp;gt;key[char_index]) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;do {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;++i;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} while (i != end &amp;amp;&amp;amp; i-&amp;gt;key[char_index] == start-&amp;gt;key[char_index]);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.terminal_ = false;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.char_step_ = Compile(start, i, char_index + 1);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.next_index_ = tree_.size() - 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} else {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.terminal_ = true;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.value_ = start-&amp;gt;value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;map.push_back(value);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (i == end)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;start = i++;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;if (1 == map.size() &amp;amp;&amp;amp; !map.front().terminal_) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;// Pass through node:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;return map.front().char_step_ + 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;tree_.push_back(map);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;return 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;inline int Lookup(const char* s) const {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;const CharMap* node = &amp;amp;tree_.back();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;s += first_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;while (true) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;const CharMap::const_iterator value = find(node-&amp;gt;begin(), node-&amp;gt;end(), *s);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (value-&amp;gt;terminal_)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return value-&amp;gt;value_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;s += value-&amp;gt;char_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;node = value-&amp;gt;next_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;int _tmain(int argc, _TCHAR* argv[])&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp;KnownSetTrie trie(kvs, kvs_end);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;LARGE_INTEGER begin, end, frequency;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;begin);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int total = 0; &amp;nbsp;// Just so the compiler doesn't completely optimize out the for loop.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;for (int i = 0; i &amp;lt; 1000000; ++i) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;for (const KeyValue* k = kvs; k != kvs_end; ++k)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;total &amp;nbsp;+= trie.Lookup(k-&amp;gt;key);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;end);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceFrequency(&amp;amp;frequency);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;__int64 ms = (end.QuadPart - begin.QuadPart) * 1000 / frequency.QuadPart;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Total:\t" &amp;lt;&amp;lt; total &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Milliseconds:\t" &amp;lt;&amp;lt; ms &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;</description></item><item><title>LINQ is seemingly more powerful than simple ORM</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2024702</link><pubDate>Wed, 04 Apr 2007 12:47:30 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2024702</guid><dc:creator>CedarLogic - Shawn Cicoria</dc:creator><description>&lt;p&gt;It seems the LINQ guys have done a great job of optimization inside of the LINQ namespace (System.Linq)....&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2026033</link><pubDate>Wed, 04 Apr 2007 18:52:04 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2026033</guid><dc:creator>Jeff</dc:creator><description>&lt;P&gt;I got the C++ code down to 70 ms. &amp;nbsp;It took a __fastcall and some fun struct packing, though.&lt;/P&gt;
&lt;P&gt;I can't wait to use C# .Net!&lt;/P&gt;
&lt;P&gt;#include "stdafx.h"&lt;/P&gt;
&lt;P&gt;struct KeyValue {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;const char* key;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int value;&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;struct CharValue {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int char_ : 8;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int terminal_ : 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int char_step_ : 23;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;union {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;int value_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;size_t next_index_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;vector&amp;lt;CharValue&amp;gt;* next_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;};&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;inline bool operator &amp;lt; (const CharValue&amp;amp; value, int c) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return value.char_ &amp;lt; c;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;inline bool operator &amp;lt; (int c, const CharValue&amp;amp; value) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return c &amp;lt; value.char_;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;inline bool operator == (const CharValue&amp;amp; value, int c) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;return value.char_ == c;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;static const KeyValue kvs[] = {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"bashful", 6},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"doc", 7},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"dopey", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"grumpy", 2},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"happy", 9},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sleepy", 8},&lt;/P&gt;
&lt;P&gt;&amp;nbsp;{"sneezy", 2},&lt;/P&gt;
&lt;P&gt;}, * const kvs_end = kvs + (sizeof(kvs) / sizeof(0[kvs]));&lt;/P&gt;
&lt;P&gt;class KnownSetTrie {&lt;/P&gt;
&lt;P&gt;public:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;typedef vector&amp;lt;CharValue&amp;gt; CharMap;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;vector&amp;lt;CharMap&amp;gt; tree_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;ptrdiff_t first_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;CharMap* root_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;KnownSetTrie(Iter begin, Iter end) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;first_step_ = Compile(begin, end, 0) - 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;// Now that the tree_ is stable, convert indices to node pointers.&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;for(vector&amp;lt;CharMap&amp;gt;::iterator i = tree_.begin(); i != tree_.end(); ++i) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;for (CharMap::iterator j = i-&amp;gt;begin(); j != i-&amp;gt;end(); ++j)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!j-&amp;gt;terminal_)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;j-&amp;gt;next_ = &amp;amp;tree_[j-&amp;gt;next_index_];&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;root_ = &amp;amp;tree_.back();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;ptrdiff_t Compile(Iter begin, Iter end, ptrdiff_t char_index) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;CharMap map;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;Iter start = begin, i = begin + 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;while (true) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;CharValue value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;value.char_ = start-&amp;gt;key[char_index];&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (i != end &amp;amp;&amp;amp; i-&amp;gt;key[char_index] == start-&amp;gt;key[char_index]) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;do {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;++i;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} while (i != end &amp;amp;&amp;amp; i-&amp;gt;key[char_index] == start-&amp;gt;key[char_index]);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.terminal_ = false;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.char_step_ = Compile(start, i, char_index + 1);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.next_index_ = tree_.size() - 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} else {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.terminal_ = true;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value.value_ = start-&amp;gt;value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;map.push_back(value);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (i == end)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;start = i++;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;if (1 == map.size() &amp;amp;&amp;amp; !map.front().terminal_) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;// Pass through node:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;return map.front().char_step_ + 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;tree_.push_back(map);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;return 1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int __fastcall Lookup(const char* s) const {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;const CharMap* node = root_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;s += first_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;while (true) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;const CharMap::const_iterator value = find(node-&amp;gt;begin(), node-&amp;gt;end(), *s);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (value-&amp;gt;terminal_)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return value-&amp;gt;value_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;s += value-&amp;gt;char_step_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;node = value-&amp;gt;next_;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;};&lt;/P&gt;
&lt;P&gt;int _tmain(int argc, _TCHAR* argv[])&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp;KnownSetTrie trie(kvs, kvs_end);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;LARGE_INTEGER begin, end, frequency;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;begin);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;int total = 0; &amp;nbsp;// Just so the compiler doesn't completely optimize out the for loop.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;for (int i = 0; i &amp;lt; 1000000; ++i) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;for (const KeyValue* k = kvs; k != kvs_end; ++k)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;total += trie.Lookup(k-&amp;gt;key);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceCounter(&amp;amp;end);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;QueryPerformanceFrequency(&amp;amp;frequency);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;__int64 ms = (end.QuadPart - begin.QuadPart) * 1000 / frequency.QuadPart;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Total:\t" &amp;lt;&amp;lt; total &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;cout &amp;lt;&amp;lt; "Milliseconds:\t" &amp;lt;&amp;lt; ms &amp;lt;&amp;lt; endl;&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;</description></item><item><title>LINQ is seemingly more powerful than simple ORM</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2026305</link><pubDate>Wed, 04 Apr 2007 20:02:32 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2026305</guid><dc:creator>CedarLogic&lt;br /&gt;Shawn Cicoria</dc:creator><description>&lt;p&gt;It seems the LINQ guys have done a great job of optimization inside of the LINQ namespace (System.Linq).&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2026412</link><pubDate>Wed, 04 Apr 2007 20:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2026412</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Hey Jeff,&lt;/p&gt;
&lt;p&gt;That's a really nice solution. I was wondering whether a trie could help here. &lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2028342</link><pubDate>Thu, 05 Apr 2007 04:13:21 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2028342</guid><dc:creator>lb</dc:creator><description>&lt;p&gt;Okay, this is insane. How could you rate grumpy and sneezy as a 2? Unless of course 1 is the best and 10 is the worst. &lt;/p&gt;
&lt;p&gt;This &amp;quot;SwitchCompiler.CreateSwitch&amp;quot; is absolutely amazing. It's a best of both world's sort of solution -- we can focus on the high level problem, and have Linq provide optimisations that would otherwise be utterly unmaintainable and difficult to perform manually.&lt;/p&gt;
&lt;p&gt;Brilliant stuff. Thank you.&lt;/p&gt;
&lt;p&gt;lb&lt;/p&gt;</description></item><item><title>Community Convergence XXIV</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2058423</link><pubDate>Mon, 09 Apr 2007 09:41:13 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2058423</guid><dc:creator>Charlie Calvert's Community Blog</dc:creator><description>&lt;p&gt;Recently my time has been taken up with a series of internal issues involving Beta1, C# Samples and various&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2065032</link><pubDate>Tue, 10 Apr 2007 01:37:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2065032</guid><dc:creator>Jeff</dc:creator><description>&lt;p&gt;A faster solution than a trie is a hand-built binary search tree, which is what I imagine case statement compiler does. &amp;nbsp;This code runs around 55 ms, and doesn't cheat like my earlier code with __fastcalls or std::find() in place of std::lower_bound():&lt;/p&gt;
&lt;p&gt;Sorry for turning this into a language shoot-out, but this looked like such an interesting case to play with. &amp;nbsp;And again the .Net runtime performs astoundingly well.&lt;/p&gt;
&lt;p&gt;#include &amp;quot;stdafx.h&amp;quot;&lt;/p&gt;
&lt;p&gt;struct KeyValue {&lt;/p&gt;
&lt;p&gt; &amp;nbsp;const char* key;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;int value;&lt;/p&gt;
&lt;p&gt;};&lt;/p&gt;
&lt;p&gt;static const KeyValue kvs[] = {&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;bashful&amp;quot;, 6},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;doc&amp;quot;, 7},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;dopey&amp;quot;, 9},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;grumpy&amp;quot;, 2},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;happy&amp;quot;, 9},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;sleepy&amp;quot;, 8},&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&amp;quot;sneezy&amp;quot;, 2},&lt;/p&gt;
&lt;p&gt;}, * const kvs_end = kvs + (sizeof(kvs) / sizeof(0[kvs]));&lt;/p&gt;
&lt;p&gt;struct DTreeNode;&lt;/p&gt;
&lt;p&gt;struct DTreeStep {&lt;/p&gt;
&lt;p&gt; &amp;nbsp;bool terminal;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;union {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;int retval;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;int char_step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;};&lt;/p&gt;
&lt;p&gt; &amp;nbsp;union {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;DTreeNode* next;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;size_t next_index;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;};&lt;/p&gt;
&lt;p&gt;};&lt;/p&gt;
&lt;p&gt;struct DTreeNode {&lt;/p&gt;
&lt;p&gt; &amp;nbsp;char c;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;DTreeStep less_step, ge_step;&lt;/p&gt;
&lt;p&gt;};&lt;/p&gt;
&lt;p&gt;class DTree {&lt;/p&gt;
&lt;p&gt;public:&lt;/p&gt;
&lt;p&gt; &amp;nbsp;vector&amp;lt;DTreeNode&amp;gt; nodes_;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;DTreeStep root_step_;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;DTree(Iter begin, Iter end) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;root_step_ = Compile(begin, end, 0);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;// Convert indices into pointers.&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;for (vector&amp;lt;DTreeNode&amp;gt;::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!i-&amp;gt;less_step.terminal)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;i-&amp;gt;less_step.next = &amp;amp;*(nodes_.begin() + i-&amp;gt;less_step.next_index);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!i-&amp;gt;ge_step.terminal)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;i-&amp;gt;ge_step.next = &amp;amp;*(nodes_.begin() + i-&amp;gt;ge_step.next_index);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;root_step_.next = &amp;amp;*(nodes_.begin() + root_step_.next_index);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;template &amp;lt;typename Iter&amp;gt;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;DTreeStep Compile(Iter begin, Iter end, ptrdiff_t char_index) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;ptrdiff_t count = end - begin;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;DTreeStep step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;if (1 == count) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;step.terminal = true;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;step.retval = begin-&amp;gt;value;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;return step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;Iter middle = begin + (end - begin) / 2,&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;middle_begin = middle, middle_end = middle + 1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;while (true) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (middle_begin == begin)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;Iter prior = middle_begin - 1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (prior-&amp;gt;key[char_index] == middle-&amp;gt;key[char_index])&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;middle_begin = prior;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;else&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;while (true) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (middle_end == end)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (middle_end-&amp;gt;key[char_index] == middle-&amp;gt;key[char_index])&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;++middle_end;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;else&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;const ptrdiff_t less_count = middle_begin - begin,&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;equal_count = middle_end - middle_begin,&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;greater_count = end - middle_end;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;if (0 == less_count) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (0 == greater_count) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// All middles, pass through&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;step = Compile(begin, end, char_index + 1);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;step.char_step += 1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;} else {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// middles and greaters&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;middle_begin = middle_end;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;DTreeNode node;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;node.c = middle_end-&amp;gt;key[char_index];&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;node.less_step = Compile(begin, middle_begin, char_index);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;node.ge_step = Compile(middle_begin, end, char_index);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;step.terminal = false;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;step.char_step = 0;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;step.next_index = nodes_.size();&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;nodes_.push_back(node);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;return step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;int Lookup(const char* s) const {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;const DTreeStep* step = &amp;amp;root_step_;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;while (true) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;const DTreeNode* node = step-&amp;gt;next;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;step = *s &amp;lt; node-&amp;gt;c ? &amp;amp;node-&amp;gt;ge_step : &amp;amp;node-&amp;gt;less_step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (step-&amp;gt;terminal)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return step-&amp;gt;retval;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;s += step-&amp;gt;char_step;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt;};&lt;/p&gt;
&lt;p&gt;int _tmain(int argc, _TCHAR* argv[])&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp;DTree dtree(kvs, kvs_end);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;LARGE_INTEGER begin, end, frequency;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;QueryPerformanceCounter(&amp;amp;begin);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;int total = 0; &amp;nbsp;// Just so the compiler doesn't completely optimize out the for loop.&lt;/p&gt;
&lt;p&gt; &amp;nbsp;for (int i = 0; i &amp;lt; 1000000; ++i) {&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;for (const KeyValue* k = kvs; k != kvs_end; ++k)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;total += dtree.Lookup(k-&amp;gt;key);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;QueryPerformanceCounter(&amp;amp;end);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;QueryPerformanceFrequency(&amp;amp;frequency);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;__int64 ms = (end.QuadPart - begin.QuadPart) * 1000 / frequency.QuadPart;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;cout &amp;lt;&amp;lt; &amp;quot;Total:\t&amp;quot; &amp;lt;&amp;lt; total &amp;lt;&amp;lt; endl;&lt;/p&gt;
&lt;p&gt; &amp;nbsp;cout &amp;lt;&amp;lt; &amp;quot;Milliseconds:\t&amp;quot; &amp;lt;&amp;lt; ms &amp;lt;&amp;lt; endl;&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2111845</link><pubDate>Fri, 13 Apr 2007 11:55:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2111845</guid><dc:creator>Zan</dc:creator><description>&lt;P&gt;ahh, I have no idea how you lot managed to get such results on 3.4 ghz machines for the standard dictionary tests.&lt;/P&gt;
&lt;P&gt;heres my code.. using standard generic dictionary and I get wihout fail 92-93ms lookup times for 1 million loops.&lt;/P&gt;
&lt;P&gt;I havent tried the linq version on my machine as I'm only running .net 2.0 &amp;nbsp;but even comparing the results for linq here (even though this is distorted due to difference in machines used) the difference is a max of 20%.. &amp;nbsp;nothing like the 900% claimed.&lt;/P&gt;
&lt;P&gt;by the way.. &amp;nbsp;my tests were all run on a p4 2.4 ghz machine... &amp;nbsp; i'm sure using a cpu that clocks 30% faster will also reduce the performance gap between my results and those posted in the original statement.&lt;/P&gt;
&lt;P&gt;PS. &amp;nbsp;dont use datetime for monitoring performance as datetime is not updated every tick.. &amp;nbsp;my experience is that datetime as a +/- difference of 30-40 ms on a good day vs the stopwatch class.&lt;/P&gt;
&lt;P&gt;anyway heres the code I run my tests with.&lt;/P&gt;
&lt;P&gt;Dictionary&amp;lt;string, int&amp;gt; index = new Dictionary&amp;lt;string, int&amp;gt;();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("happy", 9);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("sneezy", 2);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("doc", 7);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("sleepy", 8);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("dopey", 9);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;index.Add("grumpy", 2);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int found = 0; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Stopwatch sw = new Stopwatch();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sw.Start();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (int i = 0; i &amp;lt; 1000000; i++)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;found = index["doc"];&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;long elapsed = sw.ElapsedMilliseconds;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sw.Stop();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sw = null;&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2158204</link><pubDate>Tue, 17 Apr 2007 02:45:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2158204</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Zan,&lt;/p&gt;
&lt;p&gt;Your test is only looking up one value in a loop. Our tests are looking up seven values in a loop. You can see the actual test code in the comments above. If you adjust your test to match you'll get ~650ms.&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#2795040</link><pubDate>Tue, 22 May 2007 18:44:30 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2795040</guid><dc:creator>Gilles Michard</dc:creator><description>&lt;P&gt;I found that using KeyValuePair&amp;lt;string,TR&amp;gt; instead of Case&amp;lt;TR&amp;gt; allows to expose the function CreateSwitch to have a IEnumerable&amp;lt;KeyValuePair&amp;lt;string,TR&amp;gt;&amp;gt; parameter&lt;/P&gt;
&lt;P&gt;this allows these uses:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;public static Func&amp;lt;string, TR&amp;gt; CreateSwitch&amp;lt;TR&amp;gt;(this IEnumerable&amp;lt;string&amp;gt; strings, Func&amp;lt;string, TR&amp;gt; func)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return CreateSwitch(from s in strings select new KeyValuePair&amp;lt;string, TR&amp;gt;(s, func(s)));&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;public static Func&amp;lt;string, IEnumerable&amp;lt;TR&amp;gt;&amp;gt; EnumerableInvert&amp;lt;TR&amp;gt;(this IEnumerable&amp;lt;TR&amp;gt; values, Func&amp;lt;TR, string&amp;gt; name)&lt;/P&gt;
&lt;P&gt;I added the fllowing check in the function:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;public static Func&amp;lt;string, TR&amp;gt; CreateSwitch&amp;lt;TR&amp;gt;(this IEnumerable&amp;lt;KeyValuePair&amp;lt;string, TR&amp;gt;&amp;gt; caseDict)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (caseDict.Count() != caseDict.Distinct().Count())&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;throw new ArgumentException("duplicate names");&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var cases = caseDict.ToArray();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var p = Expression.Parameter(typeof(string), "p");&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var expr = Expression.Lambda&amp;lt;Func&amp;lt;string, TR&amp;gt;&amp;gt;(&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;BuildStringLength( p, cases.ToOrderedArray(s =&amp;gt; s.Key.Length), 0, cases.Length &amp;nbsp;- 1),&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;new ParameterExpression[] { p }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var del = expr.Compile();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return del;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return CreateSwitch(from v in values group v by name(v) into byname select new KeyValuePair&amp;lt;string, IEnumerable&amp;lt;TR&amp;gt;&amp;gt;(byname.Key, byname));&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;public static Func&amp;lt;string,TR&amp;gt; Invert&amp;lt;TR&amp;gt;(this IEnumerable&amp;lt;TR&amp;gt; values, Func&amp;lt;TR, string&amp;gt; name)&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return CreateSwitch(from v in values group v by name(v) into byname select new KeyValuePair&amp;lt;string, TR&amp;gt;(byname.Key, byname.First()));&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;public static Func&amp;lt;string, TR&amp;gt; ParseEnum&amp;lt;TR&amp;gt;()&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//where TR: Enum&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return CreateSwitch(from v in (TR[])Enum.GetValues(typeof(TR)).OfType&amp;lt;TR&amp;gt;() select new KeyValuePair&amp;lt;string, TR&amp;gt;(Enum.GetName(typeof(TR), v), v));&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/P&gt;</description></item><item><title>LINQ to SQL Beta2 Performance Numbers and the Dynamic Compilation Pattern</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#3730344</link><pubDate>Fri, 06 Jul 2007 18:58:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3730344</guid><dc:creator>Jomo Fisher -- C#, LINQ and Whatnot</dc:creator><description>&lt;p&gt;Rico Mariani has been posting about LINQ to SQL perfomance and has finally posted the performance numbers&lt;/p&gt;
</description></item><item><title>LINQ to SQL Beta2 Performance Numbers and the Dynamic Compilation Pattern</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#3731512</link><pubDate>Fri, 06 Jul 2007 19:56:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3731512</guid><dc:creator>Noticias externas</dc:creator><description>&lt;p&gt;Rico Mariani has been posting about LINQ to SQL perfomance and has finally posted the performance numbers&lt;/p&gt;
</description></item><item><title>The Least You Need to Know about C# 3.0</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#4017820</link><pubDate>Tue, 24 Jul 2007 00:38:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4017820</guid><dc:creator>Jomo Fisher -- C#, LINQ and Whatnot</dc:creator><description>&lt;p&gt;Jomo Fisher—A lot of people (myself included) have written about LINQ in the next version of C#. LINQ&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#4242430</link><pubDate>Sun, 05 Aug 2007 20:19:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4242430</guid><dc:creator>Raptor-75</dc:creator><description>&lt;p&gt;Great stuff Jomo!&lt;/p&gt;
&lt;p&gt;Unfortunately it doesn't work with this dictionary:&lt;/p&gt;
&lt;p&gt;{&amp;quot;Ado&amp;quot;, i++},&lt;/p&gt;
&lt;p&gt;{&amp;quot;A2o&amp;quot;, i++},&lt;/p&gt;
&lt;p&gt;{&amp;quot;A2i&amp;quot;, i++},&lt;/p&gt;
&lt;p&gt;{&amp;quot;B2o&amp;quot;, i++},&lt;/p&gt;
&lt;p&gt;{&amp;quot;AdoX&amp;quot;, i++},&lt;/p&gt;
&lt;p&gt;{&amp;quot;AdPX&amp;quot;, i++}&lt;/p&gt;
&lt;p&gt;It crashes with an IndexOutOfRangeException in BuildStringChar() because it gets a set of strings that are of different lengths. It seems to me that both your if statements that deal with middle are incorrect. If I replace middle with upper in those and in both calls to FirstDifferentDown() it almost works.&lt;/p&gt;
&lt;p&gt;Another problem I had to fix is that ToOrderedArray() orders the strings in a way that is not consistent with the Char comparisons in the resulting delegate. In this case it breaks down because 'o' &amp;lt; 'P' is false while &amp;quot;AdoX&amp;quot;.CompareTo(&amp;quot;AdPX&amp;quot;) is -1. My solution was to make a new ToOrderedArray() that takes an IComparer&amp;lt;string&amp;gt; and passes it on to OrderBy(). I then pass it the Instance member from this class:&lt;/p&gt;
&lt;p&gt;internal class StringCharComparer : IComparer&amp;lt;string&amp;gt;&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;public static StringCharComparer Instance = new StringCharComparer();&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;public int Compare(string x, string y)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (int i = 0; i &amp;lt; Math.Min(x.Length, y.Length); i++)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (x[i] &amp;gt; y[i])&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else if (x[i] &amp;lt; y[i])&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return -1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (x.Length == y.Length)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else if (x.Length &amp;gt; y.Length)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return -1;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;By the way, it was pure luck that the dictionaries I tried exposed these bugs.&lt;/p&gt;
&lt;p&gt;Thoughts?&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#4312062</link><pubDate>Thu, 09 Aug 2007 19:14:22 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4312062</guid><dc:creator>Jomo Fisher</dc:creator><description>&lt;p&gt;Raptor, I think you're right on both accounts. Thanks for pointing this out. &lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#4616965</link><pubDate>Tue, 28 Aug 2007 22:27:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4616965</guid><dc:creator>Some One</dc:creator><description>&lt;p&gt;Nice, one thing I did was add the optimized Lookup into the testing for comparison. This is where one decides if the lookup is a dynamic list and if the dictionary will change over time. Even though the optimized Lookup is hard to maintain and debug that would be OK if it list was static and did not change over time. But if it does change then one has choices to build a Compiled Expression versus a conventional way. The new idea would be to take a conversional way of doing something and turning it into an Expression that could be compiled and may have performance gains. I like how you take something as simple as a lookup that one might think as being optimized but showing that by building an optimized expression the performance can be even faster.&lt;/p&gt;
&lt;p&gt;Dictionary: 700.07 ms &amp;nbsp;~ 7.8x slower&lt;/p&gt;
&lt;p&gt;Compiled: 170.017 ms &amp;nbsp; ~ 1.89 - 2x slower&lt;/p&gt;
&lt;p&gt;Lookup: 90.009 ms &lt;/p&gt;
&lt;p&gt;Dictionary: 700.07 ms &amp;nbsp;~ &lt;/p&gt;
&lt;p&gt;Compiled: 170.017 ms &amp;nbsp; ~ 4.12x faster&lt;/p&gt;
&lt;p&gt;Thanx for the Expresion Building logic that helps whith how all various static methods in System.Linq.Expressions are used to build a dynamic function.&lt;/p&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#5950339</link><pubDate>Wed, 07 Nov 2007 07:13:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5950339</guid><dc:creator>Paul Westcott</dc:creator><description>&lt;P&gt;Nothing really to add of value, but kind of interesting. If you define the following class:&lt;/P&gt;
&lt;P&gt;class EqualityCompareStrings : IEqualityComparer&amp;lt;string&amp;gt;&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;public bool Equals(string x, string y) { return string.Equals(x, y); }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp;public int GetHashCode(string obj) { return obj.GetHashCode(); }&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;And then create the dictionary with an instance of that class like&lt;/P&gt;
&lt;P&gt;Dictionary&amp;lt;string, int&amp;gt; dict = new Dictionary&amp;lt;string, int&amp;gt;(new EqualityCompareStrings());&lt;/P&gt;
&lt;P&gt;Then you get (from my test!) a time on the non-SwitchCompiler code of about 80%.&lt;/P&gt;
&lt;P&gt;So as I said nothing really to do with the anything much, although considering how often strings are used as keys it might be a trivial optimization to put into System.Collections.Generic.EqualityComparer&amp;lt;T&amp;gt;. CreateComparer() to handle it as a special case...&lt;/P&gt;
&lt;P&gt;Assuming that I haven't done anything wrong :-)&lt;/P&gt;
&lt;P&gt;(But then you might as well use the Jomo special SwitchCompiler - but if you want to keep using Dictionary&amp;lt;string, ...&amp;gt;)&lt;/P&gt;</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#6852446</link><pubDate>Mon, 24 Dec 2007 14:18:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6852446</guid><dc:creator>Gustavo Guerra</dc:creator><description>&lt;p&gt;Hello&lt;/p&gt;
&lt;p&gt;I've also hit on the bug that Raptor-75 pointed out. Using his StringCharComparer dindn't solve it all. If you have a complete fix can you please post it?&lt;/p&gt;
&lt;p&gt;Best Regards,&lt;/p&gt;
&lt;p&gt;Gustavo Guerra&lt;/p&gt;</description></item><item><title>Using LINQ to 'Hand-Optimize' Your Code</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#8377801</link><pubDate>Fri, 11 Apr 2008 05:23:51 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8377801</guid><dc:creator>Jonathan Rupp</dc:creator><description>&lt;p&gt;On my current project, we're in a 'make it faster' mode right now.&amp;amp;#160; We've already knocked out a&lt;/p&gt;
</description></item><item><title>StaticStringDictionary - Fast Switching with LINQ revisited</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#8904149</link><pubDate>Thu, 28 Aug 2008 23:58:41 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8904149</guid><dc:creator>Code Beside</dc:creator><description>&lt;p&gt;StaticStringDictionary - Fast Switching with LINQ revisited&lt;/p&gt;
</description></item><item><title>re: Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#8904155</link><pubDate>Fri, 29 Aug 2008 00:01:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8904155</guid><dc:creator>Gustavo Guerra</dc:creator><description>&lt;p&gt;Hi, I posted a version that fixed the bugs found by Raptor-75 in my blog: &lt;a rel="nofollow" target="_new" href="http://blog.codebeside.org/archive/2008/08/28/staticstringdictionary-fast-switching-with-linq-revisited.aspx"&gt;http://blog.codebeside.org/archive/2008/08/28/staticstringdictionary-fast-switching-with-linq-revisited.aspx&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Update on Fast Switching with LINQ</title><link>http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx#8905470</link><pubDate>Fri, 29 Aug 2008 18:44:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8905470</guid><dc:creator>Jomo Fisher -- Sharp Things</dc:creator><description>&lt;p&gt;Jomo Fisher—A while back I wrote about using LINQ to get close-to-the-metal performance in a particular&lt;/p&gt;
</description></item></channel></rss>