tag:blogger.com,1999:blog-31088288858236189402023-11-26T10:18:28.975+01:00Landman CodeMy name is Davy Landman and I'm a developer. While working I develop mainly in ASP.NET and Winforms using the C# language, while sometimes developing Win32 applications in Delphi.
When not working and coding the utilities the inner geek wants, I use a mix of C#, Delphi, BASM and Matlab.
In this blog I post about some interesting code I found or created, mainly sharing it for reference later and anyone else who would like it.Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-3108828885823618940.post-81438932982036025942010-08-24T16:15:00.003+02:002010-08-24T16:32:31.797+02:00Protection your EntityCollections from outside abuse by wrapping them as IEnumerable<p>
In the <a href="http://landman-code.blogspot.com/2010/08/adding-support-for-enum-properties-on.html">previous post</a> I introduced a wrapping extension for Entity Framework, and used enumerations as example, but there are is one more powerful feature which this offers, you can hide your internal details from outside users.
</p>
<p>
Why would for instance some external piece of code need to have access to the <a href="http://msdn.microsoft.com/en-us/library/bb337024.aspx">EntityCollection.Remove</a> method when the only one with access should be the entity itself or perhaps the aggregate root.
Entity Framework forces you to use EntityCollections for relations were most of the times a IEnumerable would be a much better abstraction.
</p>
<p>
In our projects we have code such as the following to wrap these EntityCollections:
</p>
<pre class="Source"><span style="color: navy;">public</span> <span style="color: navy;">partial</span> <span style="color: navy;">class</span> <span style="color: rgb(166, 83, 0);">Order</span>
{
<span style="color: navy;">public</span> <span style="color: rgb(214, 107, 0);">IEnumerable</span><<span style="color: rgb(166, 83, 0);">OrderDetail</span>> <span style="color: maroon;">Details</span>
{
<span style="color: navy;">get</span>
{
<span style="color: green;">// Lazy loading in EF1</span>
<span style="color: navy;">if</span> (!<span style="color: maroon;">DbDetails</span>.<span style="color: maroon;">IsLoaded</span> && !(<span style="color: navy;">this</span>.<span style="color: maroon;">IsDetached</span>() || <span style="color: navy;">this</span>.<span style="color: maroon;">IsNew</span>()))
<span style="color: maroon;">DbDetails</span>.<span style="color: maroon;">Load</span>();
<span style="color: navy;">return</span> <span style="color: maroon;">DbDetails</span>;
}
}
}
</pre>
<p>
Using this collection in any kind of query will trigger NotSupportedException from Entity Framework the same as the previous post.
But when using the <a href="http://github.com/DavyLandman/EFWrappableFields">EFWrappableFields</a> extension the queries are also translated to use the DbDetails when translating to SQL and thereby solves the problem and provides the possibility of hiding the real EntityCollection behind a safe IEnumerable interface.
</p>
<p>
So have fun with this extension, and when you can improve the code, <a href="http://github.com/DavyLandman/EFWrappableFields">please fork me at Github</a>.
</p>Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com4tag:blogger.com,1999:blog-3108828885823618940.post-58199107600688138722010-08-24T14:14:00.017+02:002010-08-28T12:04:24.321+02:00Adding support for enum properties on your entities in Entity Framework<p>
While Entity Frameworks is a reasonably nice ORM and the push of Microsoft behind a technology sure helps adoption from the corporate people, there are some seriously annoying limitations.
The heavy dependencies can be abstracted away by (ab)using interfaces and other object oriented constructs.
But some limitations are deeply nested within the assumptions of Entity Framework and are hard to work around.
</p>
<p>
One that has annoyed me very much was that (before POCO support) only certain types of properties are allowed.
Using any other property type gives annoying NotSupportedExceptions, or the designer does not allow it.
This became very apparent with enumerations, there are multiple use cases for enumerations in a data model and should cause no real harm to the queries to cast a integer back and forth to a enum, but EF only likes scalar type in the expressions to be converted to SQL.
You'll enjoy messages such as "LINQ to Entities only supports casting Entity Data Model primitive types.".
While I can understand that supporting enumerations is apparently very hard to solve (for the EF team that is), they could have added a way to offer wrapping the access to these fields so the external users of the entities do not have to share intimate internal details.
</p>
<p>
Assuming you have a Order entity and you hide the Status field in your entity behdind DbStatus and create a custom property which casts the Integer to a enum and back. As follows:
</p>
<pre class="Source"><span style="color:navy;">public</span> <span style="color:navy;">enum</span> <span style="color: rgb(166, 83, 0);">OrderState</span>
{
<span style="color:maroon;">Unknown</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">0</span>,
<span style="color:maroon;">InProcess</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">1</span>,
<span style="color:maroon;">Approved</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">2</span>,
<span style="color:maroon;">Backordered</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">3</span>,
<span style="color:maroon;">Rejected</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">4</span>,
<span style="color:maroon;">Shipped</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">5</span>,
<span style="color:maroon;">Cancelled</span> = <span style="background: none repeat scroll 0% 0% rgb(230, 255, 255);">6</span>
}
<span style="color:navy;">public</span> <span style="color:navy;">partial</span> <span style="color:navy;">class</span> <span style="color: rgb(166, 83, 0);">Order</span>
{
<span style="color:navy;">public</span> <span style="color: rgb(166, 83, 0);">OrderState</span> <span style="color:maroon;">Status</span>
{
<span style="color:navy;">get</span> { <span style="color:navy;">return</span> (<span style="color: rgb(166, 83, 0);">OrderState</span>)<span style="color:maroon;">DbStatus</span>; }
<span style="color:navy;">set</span> { <span style="color:maroon;">DbStatus</span> = (<span style="color:navy;">int</span>)<span style="color:navy;">value</span>; }
}
}</pre>
<p>
If you would then write a Query such as:
</p>
<pre class="Source"><span style="color:navy;">var</span> <span style="color:maroon;">approvedOrders</span> = <span style="color:navy;">new</span> <span style="color: rgb(166, 83, 0);">EFTestDatabaseEntities</span>().<span style="color:maroon;">Orders</span>.<span style="color:maroon;">Where</span>(<span style="color:maroon;">o</span> => <span style="color:maroon;">o</span>.<span style="color:maroon;">Status</span> == <span style="color: rgb(166, 83, 0);">OrderState</span>.<span style="color:maroon;">Approved</span>).<span style="color:maroon;">ToList</span>();
</pre>
<p>You would get a nice exception:</p>
<blockquote>System.NotSupportedException : The specified type member 'Status' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.</blockquote>
<p>
So I created an extension which adds wrapping support to Entity Framework 1 (and 4), this wrapping offers a way to support these queries by changing the actual query just before EF starts translating the expression tree to SQL.
This in itself is not that big of a challenge, but Entity Framework being closed and inextensible as it is, it took some time (<a href="http://stackoverflow.com/questions/1839901/how-to-wrap-entity-framework-to-intercept-the-linq-expression-just-before-executi">and a StackOverflow question</a>) to find the right place to inject this logic.
</p>
<p>
After using it for a few projects I thought I should share this with the community, so I created a Github project to <a href="http://github.com/DavyLandman/EFWrappableFields" alt="EFWrappableFields source code">host the source code</a>, and share it with the rest of the world suffering from Entity Framework.
The change required to be able to wrap is that the original ObjectQuery must be replaced with a instance of WrappedFieldsObjectQuery containing the original ObjectQuery.
When your using a pattern such as repository, this change should only have to be in one file in perhaps a few places.
</p>
<p>
The previous example than becomes:
</p>
<pre class="Source"><span style="color: navy;">var</span> <span style="color: maroon;">approvedOrders</span> = <span style="color: navy;">new</span> <span style="color: rgb(166, 83, 0);">WrappedFieldsObjectQuery</span><<span style="color: rgb(166, 83, 0);">Order</span>>(<span style="color: navy;">new</span> <span style="color: rgb(166, 83, 0);">EFTestDatabaseEntities</span>().<span style="color: maroon;">Orders</span>)
.<span style="color: maroon;">Where</span>(<span style="color: maroon;">o</span> => <span style="color: maroon;">o</span>.<span style="color: maroon;">Status</span> == <span style="color: rgb(166, 83, 0);">OrderState</span>.<span style="color: maroon;">Approved</span>).<span style="color: maroon;">ToList</span>();
</pre>
<p>
And will now run and replace the Status field in the Expression tree to the DbStatus field in the model just before the translation to SQL.
The way this works is by convention, the WrappedFieldsObjectQuery tries to find for every property used if there is an property with the "Db" perfix and than replaces the reference with that one.
So if the wrapped field was named WrappedStatus, this wouldn't have worked, but it avoids any clutter on the Entity site with either attributes or interfaces.
</p>
<p>
You can get the source <a class="" href="http://github.com/DavyLandman/EFWrappableFields">here</a>. (you can also download compiled dll's for EF 1 and EF 4 from <a href="http://github.com/DavyLandman/EFWrappableFields/downloads">Github</a>)
Both Entity Framework 1 and Entity Framework 4 are supported, but for EF4 I've only tested it with the generate model from database.
I added EF4 support while I haven't used it yet in any project, but I will investigate soon if EF4 offers better ways to do this, and if POCO even needs this kind of extension.
</p>
<p style="font-size:0.8em">ps. you can also use this wrapper to protect your relations (such as collections) to other entities, <a href="http://landman-code.blogspot.com/2010/08/protection-your-entitycollections-from.html" alt="Entity relations protection">see my other post describing this</a>.</p>
Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com7tag:blogger.com,1999:blog-3108828885823618940.post-54884443416918825942009-02-25T14:40:00.002+01:002009-02-26T09:20:43.643+01:00C# SuperFastHash and MurmurHash2 implementations<p><img src="http://farm1.static.flickr.com/159/437760198_1df1b71cc8_m.jpg" class="BlogTitleImage" title="paint paint paint by Natashalatrasha on http://www.flickr.com/photos/ladouseur/437760198/" alt="paint paint paint by Natashalatrasha on http://www.flickr.com/photos/ladouseur/437760198/" />I’ve been emailed about a <a href="http://www.azillionmonkeys.com/qed/hash.html" target="_blank">SuperFastHash</a> C# implementation, and I felt like doing low level stuff, since I’m knees deep in DDD at the moment. So I looked at my <a href="http://landman-code.blogspot.com/2008/06/superfasthash-from-paul-hsieh.html" target="_blank">Pascal and BASM implementation of SuperFastHash</a> and figured, I could totally make this in C#. Searching around if nobody else had done it already (then I could just send a link to that site as reply), I saw some articles analyzing <a href="http://www.team5150.com/~andrew/blog/2007/03/hash_algorithm_attacks.html" target="_blank">SuperFastHash</a> and <a href="http://floodyberry.wordpress.com/2007/03/29/breaking-superfasthash/" target="_blank">breaking it</a>. During that search I also found another Hasher called <a href="http://murmurhash.googlepages.com/" target="_blank">MurmurHash2</a> which passes some test very nicely and is a lot faster than SuperFastHash. But it seems that this hash is <a href="http://groups.google.com/group/sci.crypt/browse_thread/thread/aa1f3b6e8d50d8aa " target="_blank">too</a> <a href="http://groups.google.co.uk/group/sci.crypt/browse_thread/thread/56aaa4c236c7b095" target="_blank">simple</a> and does have some <a href="http://groups.google.com/group/sci.crypt/browse_thread/thread/aa1f3b6e8d50d8aa/ad6e127fecd46fba?#ad6e127fecd46fba" target="_blank">vurnabilities</a> as well, so I’ve implemented both in c# and left you with the choice. Important to know, these hashes are for hashtables and not meant for verifying or cryptology. </p> <p>I'll discuss each hash separately and discuss my different implementation, in the end I’ll post the final implementation and let you chose yourself.</p> <h3>SuperFastHash</h3> <p>This one I already knew, so I implemented this one very fast to the following simple implementation. This implementation is very standard .NET code which just a few optimizations.</p> <pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">SuperFastHashSimple </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = <span style="color: #2b91af">Convert</span>.ToUInt32(dataLength);
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(<span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex + 2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
currentIndex += 4;
numberOfLoops--;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3: hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex + 2]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2: hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1: hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}</pre>
<p>The most performance was lost with the <span class="Source"><span style="color: #2b91af">BitConverter</span>.ToUInt16</span> which is implemented as a unsafe pointer cast, but does some checking before the cast, the next step was to inline the byte to UInt16 conversion.</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">SuperFastHashInlineBitConverter </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)((<span style="color: #2b91af">UInt32</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
numberOfLoops--;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex] << 8);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}</pre>
<p>This is the fastest no-hacks managed implementation of the SuperFastHash, but the result will change if the Endianness changes. I’ve been looking for a way to cast the byte array to a int array without have to do <span class="Source">Marshal.Copy</span>, I found a <a href="http://mark-dot-net.blogspot.com/2008/06/wavebuffer-casting-byte-arrays-to-float.html" target="_blank">dirty hack using FieldOffset(0)</a>, I have no idea if this hack is going to be supported on new versions of the CLR so using this is a risk. The only strange part is that the UInts.Length is the length of the bytes array, but the index is of the UInt16 array, so the max index for that array is UInts.Length / sizeof(UInt16). Below is the implementation of this hack.</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">SuperFastHashUInt16Hack </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
[<span style="color: #2b91af">StructLayout</span>(<span style="color: #2b91af">LayoutKind</span>.Explicit)]
<span style="color: green">// no guarantee this will remain working
</span><span style="color: blue">struct </span><span style="color: #2b91af">BytetoUInt16Converter
</span>{
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">Byte</span>[] Bytes;
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">UInt16</span>[] UInts;
}
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: #2b91af">UInt16</span>[] arrayHack = <span style="color: blue">new </span><span style="color: #2b91af">BytetoUInt16Converter </span>{ Bytes = dataToHash }.UInts;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += arrayHack[currentIndex++];
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(arrayHack[currentIndex++] << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
numberOfLoops--;
}
currentIndex *= 2; <span style="color: green">// fix the length
</span><span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex] << 8);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}</pre>
<p>The last stap was to go to unsafe land and do real pointer stuff.. This implementation looks a lot like the original c implementation</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">SuperFastHashUnsafe </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public unsafe </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: blue">fixed </span>(<span style="color: blue">byte</span>* firstByte = &(dataToHash[0]))
{
<span style="color: green">/* Main loop */
</span><span style="color: #2b91af">UInt16</span>* data = (<span style="color: #2b91af">UInt16</span>*)firstByte;
<span style="color: blue">for </span>(; numberOfLoops > 0; numberOfLoops--)
{
hash += *data;
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(*(data + 1) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2;
hash += hash >> 11;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3: hash += *data;
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)(*(((<span style="color: #2b91af">Byte</span>*)(data))+2))) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2: hash += *data;
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += *((<span style="color: #2b91af">Byte</span>*)data);
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}</pre>
<h3>MurmurHash2</h3>
<p>The next algorithm was MurmurHash2, the code is very simple, the only dificult part was the fall-trough case which luckely isn't supported in c#, below is the first implementation.</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">MurmurHash2Simple </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(length >= 4)
{
<span style="color: #2b91af">UInt32 </span>k = <span style="color: #2b91af">BitConverter</span>.ToUInt32(data, currentIndex);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
currentIndex += 4;
length -= 4;
}
<span style="color: blue">switch </span>(length)
{
<span style="color: blue">case </span>3:
h ^= <span style="color: #2b91af">BitConverter</span>.ToUInt16(data, currentIndex);
h ^= (<span style="color: #2b91af">UInt32</span>)data[currentIndex + 2] << 16;
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= <span style="color: #2b91af">BitConverter</span>.ToUInt16(data, currentIndex);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= data[currentIndex];
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}</pre>
<p>I've applied the same optimalizations as discussed with SuperFastHash so here is the fastest no-hacks managed implementation.</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">MurmurHash2InlineBitConverter </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(length >= 4)
{
<span style="color: #2b91af">UInt32 </span>k = (<span style="color: #2b91af">UInt32</span>)(data[currentIndex++] | data[currentIndex++] << 8 | data[currentIndex++] << 16 | data[currentIndex++] << 24);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
length -= 4;
}
<span style="color: blue">switch </span>(length)
{
<span style="color: blue">case </span>3:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex++] << 8);
h ^= (<span style="color: #2b91af">UInt32</span>)(data[currentIndex] << 16);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex] << 8);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= data[currentIndex];
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}</pre>
<p>The dirty hack which I’ve already discussed worked miracles here as well. I've also added a different looping logic (stolen from SuperFastHash), this added a nice speed increase for the unsafe version.</p>
<pre class="Source Boxed"><span style="color: blue"> public class </span><span style="color: #2b91af">MurmurHash2Unsafe </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public unsafe </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>remainingBytes = length & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = length >> 2; <span style="color: green">// div 4
</span><span style="color: blue">fixed </span>(<span style="color: blue">byte</span>* firstByte = &(data[0]))
{
<span style="color: #2b91af">UInt32</span>* realData = (<span style="color: #2b91af">UInt32</span>*)firstByte;
<span style="color: blue">while </span>(numberOfLoops != 0)
{
<span style="color: #2b91af">UInt32 </span>k = *realData;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
numberOfLoops--;
realData++;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
h ^= (<span style="color: #2b91af">UInt16</span>)(*realData);
h ^= ((<span style="color: #2b91af">UInt32</span>)(*(((<span style="color: #2b91af">Byte</span>*)(realData)) + 2))) << 16;
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= (<span style="color: #2b91af">UInt16</span>)(*realData);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= *((<span style="color: #2b91af">Byte</span>*)realData);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}</pre>
<h3>Measurements</h3>
<p>I've implemented the same test case for the native version of SuperFastHash and MurmurHash2, the measured speed will be used as reference speed. SuperFastHash was clocked at a rate of 1611 MB/s and MurmurHash2 was clocked at 2312 MB/s.</p>
<p>I've based the tests on the speed test used on the <a href="http://murmurhash.googlepages.com/statistics" target="_blank">MurmurHash2 page</a>, I'm not sure they test every property of the hash function, but it's a nice way to compare the performance.</p>
<pre class="Source"> <span style="color: blue">var </span>data = <span style="color: blue">new </span><span style="color: #2b91af">Byte</span>[256 * 1024];
<span style="color: blue">new </span><span style="color: #2b91af">Random</span>().NextBytes(data);
<span style="color: #2b91af">Thread</span>.CurrentThread.Priority = <span style="color: #2b91af">ThreadPriority</span>.Highest;
<span style="color: #2b91af">Process</span>.GetCurrentProcess().PriorityClass = <span style="color: #2b91af">ProcessPriorityClass</span>.RealTime;
<span style="color: blue">if </span>(<span style="color: #2b91af">Environment</span>.ProcessorCount > 1)
{
<span style="color: #2b91af">Process</span>.GetCurrentProcess().ProcessorAffinity =
<span style="color: blue">new </span><span style="color: #2b91af">IntPtr</span>(1 << (<span style="color: #2b91af">Environment</span>.ProcessorCount - 1));
}
<span style="color: blue">foreach </span>(<span style="color: blue">var </span>testSubject <span style="color: blue">in </span>toTest)
{
<span style="color: #2b91af">Stopwatch </span>timer = <span style="color: #2b91af">Stopwatch</span>.StartNew();
<span style="color: blue">for </span>(<span style="color: blue">int </span>i = 0; i < 9999; i++)
{
testSubject.Value.Hash(data);
}
timer.Stop();
<span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"{0}:\t\t{1:F2} MB/s ({2})"</span>, testSubject.Key,
(data.Length * (1000.0 / (timer.ElapsedMilliseconds / 9999.0)))
/ (1024.0 * 1024.0),
timer.ElapsedMilliseconds);
}</pre>
<p>The test is pretty simple, test 256k random data 9999 times and extract the MB/s from it. (A test with 1k random data 99999 times showed the same speeds, so my implementations are stable enough). Below are the results for the different c# implementations.</p>
<table style="margin: 0.3em auto; width: 40em" cellspacing="0" cellpadding="2" border="0"><thead>
<tr>
<th width="55%">Function</th>
<th width="20%">Speed</th>
<th width="25%">Relative to native</th>
</tr>
</thead><tbody>
<tr>
<td>SuperFastHashSimple</td>
<td>281 MB/s</td>
<td>0.17x</td>
</tr>
<tr>
<td>SuperFastHashInlineBitConverter</td>
<td>780 MB/s</td>
<td>0.48x</td>
</tr>
<tr>
<td>SuperFastHashUInt16Hack</td>
<td>1204 MB/s</td>
<td>0.75x</td>
</tr>
<tr>
<td>SuperFastHashUnsafe</td>
<td>1308 MB/s</td>
<td>0.82x</td>
</tr>
<tr>
<td>MurmurHash2Simple</td>
<td>486 MB/s</td>
<td>0.21x</td>
</tr>
<tr>
<td>MurmurHash2InlineBitConverter</td>
<td>759 MB/s</td>
<td>0.32x</td>
</tr>
<tr>
<td>MurmurHash2UInt32Hack</td>
<td>1430 MB/s</td>
<td>0.62x</td>
</tr>
<tr>
<td>MurmurHash2Unsafe</td>
<td>2196 MB/s</td>
<td>0.95x</td>
</tr>
</tbody></table>
<p>In conclusion the managed SuperFastHash implementation is only 25% slower than the unmanaged implementation, and if you really like speed you can get the Unsafe implementation at only 18% slower than unmanged. The MurmurHash2 managed implementation is 38% slower than the unmanaged (but still as fast as the unmanaged SuperFastHash) and the unsafe implementation is only 5% slower than the unmanaged version, I call that a nice result!</p>
<h3>Final code</h3>
<p>Here is the complete unit with all the above functions, as always you can also <a href="http://davy.landman.googlepages.com/IHashAlgorithm.cs" target="_blank">download</a> <a title="Download C# SuperFastHash implementation" href="http://davy.landman.googlepages.com/SuperFastHash.cs" target="_blank">it</a> <a title="Download C# MurmurHash2 implementation" href="http://davy.landman.googlepages.com/MurmurHash2.cs" target="_blank">directly</a>.</p>
<h4>IHashingAlgorithm.cs</h4>
<pre class="Source"><span style="color: blue">using </span>System;
<span style="color: blue">namespace </span>HashTableHashing
{
<span style="color: blue">public interface </span><span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data);
}
<span style="color: blue">public interface </span><span style="color: #2b91af">ISeededHashAlgorithm </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed);
}
}</pre>
<h4>SuperFastHash.cs</h4>
<pre class="Source Boxed"><span style="color: green">/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is HashTableHashing.SuperFastHash.
*
* The Initial Developer of the Original Code is
* Davy Landman.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
</span><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Runtime.InteropServices;
<span style="color: blue">namespace </span>HashTableHashing
{
<span style="color: blue">public class </span><span style="color: #2b91af">SuperFastHashSimple </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = <span style="color: #2b91af">Convert</span>.ToUInt32(dataLength);
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(<span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex + 2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
currentIndex += 4;
numberOfLoops--;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3: hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex + 2]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2: hash += <span style="color: #2b91af">BitConverter</span>.ToUInt16(dataToHash, currentIndex);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1: hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">SuperFastHashInlineBitConverter </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)((<span style="color: #2b91af">UInt32</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
numberOfLoops--;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex] << 8);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">SuperFastHashUInt16Hack </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
[<span style="color: #2b91af">StructLayout</span>(<span style="color: #2b91af">LayoutKind</span>.Explicit)]
<span style="color: green">// no guarantee this will remain working
</span><span style="color: blue">struct </span><span style="color: #2b91af">BytetoUInt16Converter
</span>{
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">Byte</span>[] Bytes;
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">UInt16</span>[] UInts;
}
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: #2b91af">UInt16</span>[] arrayHack = <span style="color: blue">new </span><span style="color: #2b91af">BytetoUInt16Converter </span>{ Bytes = dataToHash }.UInts;
<span style="color: blue">while </span>(numberOfLoops > 0)
{
hash += arrayHack[currentIndex++];
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(arrayHack[currentIndex++] << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
numberOfLoops--;
}
currentIndex *= 2; <span style="color: green">// fix the length
</span><span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex++] << 8);
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)dataToHash[currentIndex]) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
hash += (<span style="color: #2b91af">UInt16</span>)(dataToHash[currentIndex++] | dataToHash[currentIndex] << 8);
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += dataToHash[currentIndex];
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">SuperFastHashUnsafe </span>: <span style="color: #2b91af">IHashAlgorithm
</span>{
<span style="color: blue">public unsafe </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] dataToHash)
{
<span style="color: #2b91af">Int32 </span>dataLength = dataToHash.Length;
<span style="color: blue">if </span>(dataLength == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>hash = (<span style="color: #2b91af">UInt32</span>)dataLength;
<span style="color: #2b91af">Int32 </span>remainingBytes = dataLength & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = dataLength >> 2; <span style="color: green">// div 4
</span><span style="color: blue">fixed </span>(<span style="color: blue">byte</span>* firstByte = &(dataToHash[0]))
{
<span style="color: green">/* Main loop */
</span><span style="color: #2b91af">UInt16</span>* data = (<span style="color: #2b91af">UInt16</span>*)firstByte;
<span style="color: blue">for </span>(; numberOfLoops > 0; numberOfLoops--)
{
hash += *data;
<span style="color: #2b91af">UInt32 </span>tmp = (<span style="color: #2b91af">UInt32</span>)(*(data + 1) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2;
hash += hash >> 11;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3: hash += *data;
hash ^= hash << 16;
hash ^= ((<span style="color: #2b91af">UInt32</span>)(*(((<span style="color: #2b91af">Byte</span>*)(data))+2))) << 18;
hash += hash >> 11;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2: hash += *data;
hash ^= hash << 11;
hash += hash >> 17;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
hash += *((<span style="color: #2b91af">Byte</span>*)data);
hash ^= hash << 10;
hash += hash >> 1;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
}
<span style="color: green">/* Force "avalanching" of final 127 bits */
</span>hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
<span style="color: blue">return </span>hash;
}
}
}</pre>
<h4>MurmurHash2.cs</h4>
<pre class="Source Boxed"><span style="color: green">/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is HashTableHashing.MurmurHash2.
*
* The Initial Developer of the Original Code is
* Davy Landman.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
</span><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Runtime.InteropServices;
<span style="color: blue">namespace </span>HashTableHashing
{
<span style="color: blue">public class </span><span style="color: #2b91af">MurmurHash2Simple </span>: <span style="color: #2b91af">ISeededHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(length >= 4)
{
<span style="color: #2b91af">UInt32 </span>k = <span style="color: #2b91af">BitConverter</span>.ToUInt32(data, currentIndex);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
currentIndex += 4;
length -= 4;
}
<span style="color: blue">switch </span>(length)
{
<span style="color: blue">case </span>3:
h ^= <span style="color: #2b91af">BitConverter</span>.ToUInt16(data, currentIndex);
h ^= (<span style="color: #2b91af">UInt32</span>)data[currentIndex + 2] << 16;
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= <span style="color: #2b91af">BitConverter</span>.ToUInt16(data, currentIndex);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= data[currentIndex];
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">MurmurHash2InlineBitConverter </span>: <span style="color: #2b91af">ISeededHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: blue">while </span>(length >= 4)
{
<span style="color: #2b91af">UInt32 </span>k = (<span style="color: #2b91af">UInt32</span>)(data[currentIndex++] | data[currentIndex++] << 8 | data[currentIndex++] << 16 | data[currentIndex++] << 24);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
length -= 4;
}
<span style="color: blue">switch </span>(length)
{
<span style="color: blue">case </span>3:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex++] << 8);
h ^= (<span style="color: #2b91af">UInt32</span>)(data[currentIndex] << 16);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex] << 8);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= data[currentIndex];
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">MurmurHash2UInt32Hack </span>: <span style="color: #2b91af">ISeededHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
[<span style="color: #2b91af">StructLayout</span>(<span style="color: #2b91af">LayoutKind</span>.Explicit)]
<span style="color: blue">struct </span><span style="color: #2b91af">BytetoUInt32Converter
</span>{
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">Byte</span>[] Bytes;
[<span style="color: #2b91af">FieldOffset</span>(0)]
<span style="color: blue">public </span><span style="color: #2b91af">UInt32</span>[] UInts;
}
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>currentIndex = 0;
<span style="color: green">// array will be length of Bytes but contains Uints
// therefore the currentIndex will jump with +1 while length will jump with +4
</span><span style="color: #2b91af">UInt32</span>[] hackArray = <span style="color: blue">new </span><span style="color: #2b91af">BytetoUInt32Converter </span>{ Bytes = data }.UInts;
<span style="color: blue">while </span>(length >= 4)
{
<span style="color: #2b91af">UInt32 </span>k = hackArray[currentIndex++];
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
length -= 4;
}
currentIndex *= 4; <span style="color: green">// fix the length
</span><span style="color: blue">switch </span>(length)
{
<span style="color: blue">case </span>3:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex++] << 8);
h ^= (<span style="color: #2b91af">UInt32</span>)data[currentIndex] << 16;
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= (<span style="color: #2b91af">UInt16</span>)(data[currentIndex++] | data[currentIndex] << 8);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= data[currentIndex];
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">MurmurHash2Unsafe </span>: <span style="color: #2b91af">ISeededHashAlgorithm
</span>{
<span style="color: blue">public </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data)
{
<span style="color: blue">return </span>Hash(data, 0xc58f1a7b);
}
<span style="color: blue">const </span><span style="color: #2b91af">UInt32 </span>m = 0x5bd1e995;
<span style="color: blue">const </span><span style="color: #2b91af">Int32 </span>r = 24;
<span style="color: blue">public unsafe </span><span style="color: #2b91af">UInt32 </span>Hash(<span style="color: #2b91af">Byte</span>[] data, <span style="color: #2b91af">UInt32 </span>seed)
{
<span style="color: #2b91af">Int32 </span>length = data.Length;
<span style="color: blue">if </span>(length == 0)
<span style="color: blue">return </span>0;
<span style="color: #2b91af">UInt32 </span>h = seed ^ (<span style="color: #2b91af">UInt32</span>)length;
<span style="color: #2b91af">Int32 </span>remainingBytes = length & 3; <span style="color: green">// mod 4
</span><span style="color: #2b91af">Int32 </span>numberOfLoops = length >> 2; <span style="color: green">// div 4
</span><span style="color: blue">fixed </span>(<span style="color: blue">byte</span>* firstByte = &(data[0]))
{
<span style="color: #2b91af">UInt32</span>* realData = (<span style="color: #2b91af">UInt32</span>*)firstByte;
<span style="color: blue">while </span>(numberOfLoops != 0)
{
<span style="color: #2b91af">UInt32 </span>k = *realData;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
numberOfLoops--;
realData++;
}
<span style="color: blue">switch </span>(remainingBytes)
{
<span style="color: blue">case </span>3:
h ^= (<span style="color: #2b91af">UInt16</span>)(*realData);
h ^= ((<span style="color: #2b91af">UInt32</span>)(*(((<span style="color: #2b91af">Byte</span>*)(realData)) + 2))) << 16;
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>2:
h ^= (<span style="color: #2b91af">UInt16</span>)(*realData);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">case </span>1:
h ^= *((<span style="color: #2b91af">Byte</span>*)realData);
h *= m;
<span style="color: blue">break</span>;
<span style="color: blue">default</span>:
<span style="color: blue">break</span>;
}
}
<span style="color: green">// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
</span>h ^= h >> 13;
h *= m;
h ^= h >> 15;
<span style="color: blue">return </span>h;
}
}
}</pre>Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com18tag:blogger.com,1999:blog-3108828885823618940.post-28856431987782410072009-02-23T16:30:00.001+01:002009-02-23T18:40:32.784+01:00Adding StructureMaps Registry functionality and a static wrapper to Unity<p><img class="BlogTitleImage" src="http://farm3.static.flickr.com/2144/2347430057_61cf64352a_m.jpg" alt="connected by CRASH-candy on flickr http://flickr.com/photos/crash-candy/2347430057/" title="connected by CRASH-candy on flickr http://flickr.com/photos/crash-candy/2347430057/" /><a href="http://www.martinfowler.com/articles/injection.html" target="_blank">Inversion of Control</a> (IoC) is a nice abstract design principle to get decoupling in a software architecture, Jeremy D. Miller has <a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/09/13/131897.aspx" target="_blank">two</a> <a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/09/20/132290.aspx" target="_blank">nice</a> articles about what IoC is and when to use it. I’ve used IoC primarily for decoupling parts of a system, whether it be to allow better unit testing or just less to reduce the coupling in the system. Jeremy D. Miller <a href="http://elegantcode.com/2009/02/19/code-cast-23-jeremy-miller-on-structuremap/ " target="_blank">actually</a> created the first .NET IoC container when he was really writing a ORM, he created such a flexible configuration layer that he stopped and started reading about IoC in the java world. He looked at his colleagues at ThoughtWorks who developed <a href="http://docs.codehaus.org/display/PICO/Home " target="_blank">PicoContainer</a> and saw that he could use the configuration layer to create a IoC container for .NET, he called this container <a href="http://structuremap.sourceforge.net/" target="_blank">StructureMap</a>, since than <a href="http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx" target="_blank">a lot of</a> IoC containers where created for .NET. In my company we’ve got the (very limiting) policy to use the Microsoft solution if it’s available and most of the times when there isn’t one we don’t use it at all. So we’ve got to use <a href="http://www.codeplex.com/unity" target="_blank">Unity</a>, which has some cool features, but still has to mature a bit. In this post I’ll talk about a few extensions I’ve made for the Unity container.</p> <h3>A static (singleton) wrapper for unity </h3> <p>Most IoC containers allow to write statements such as <span class="Source"><span style="color: #2b91af">IoC</span>.Resolve<<span style="color: #2b91af">ILogger</span>>()</span> but for Unity the P&P team wanted support for multiple containers existing next to each other, which in large systems might be a good solution but for smaller systems is just a hassle to pass around the reference to the container. So you’ll see a lot of <span class="Source"><span style="color: #2b91af">IoC</span>.Instance.Resolve<<span style="color: #2b91af">ILogger</span>>()</span> singleton’s being created, in my opinion the .Instance. is a bit ugly and redundant. I’d like to be able to write <span class="Source"><span style="color: #2b91af">IoC</span>.Resolve<<span style="color: #2b91af">ILogger</span>>()</span>, so I had to create a static class IoC and add static methods to wrap the unity container. Below is my wrapper code.</p> <pre class="Source Boxed Large"><span style="color: green">/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Unity.Single.IoC.
*
* The Initial Developer of the Original Code is
* Davy Landman.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
</span><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Collections.Generic;
<span style="color: blue">using </span>Microsoft.Practices.Unity;
<span style="color: blue">namespace </span>Unity.Single
{
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="T:Unity.Single.IoC"]/*'/>
</span><span style="color: blue">public sealed class </span><span style="color: #2b91af">IoC
</span>{
<span style="color: blue">#region </span>Lazy-Singleton
<span style="color: blue">private </span>IoC() { }
<span style="color: blue">private static </span><span style="color: #2b91af">IUnityContainer </span>instance
{
<span style="color: blue">get
</span>{
<span style="color: blue">return </span><span style="color: #2b91af">Nested</span>.instance;
}
}
<span style="color: blue">class </span><span style="color: #2b91af">Nested
</span>{
<span style="color: blue">static </span>Nested()
{
}
<span style="color: blue">internal static readonly </span><span style="color: #2b91af">IUnityContainer </span>instance = <span style="color: blue">new </span><span style="color: #2b91af">UnityContainer</span>();
}
<span style="color: blue">#endregion
#region </span>IoC Wrapper functions
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.BuildUp``1(``0)"]/*'/>
</span><span style="color: blue">public static </span>T BuildUp<T>(T existing)
{
<span style="color: blue">return </span>instance.BuildUp<T>(existing);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.BuildUp``1(``0,System.String)"]/*'/>
</span><span style="color: blue">public static </span>T BuildUp<T>(T existing, <span style="color: blue">string </span>name)
{
<span style="color: blue">return </span>instance.BuildUp<T>(existing, name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.BuildUp(System.Type,System.Object)"]/*'/>
</span><span style="color: blue">public static object </span>BuildUp(<span style="color: #2b91af">Type </span>t, <span style="color: blue">object </span>existing)
{
<span style="color: blue">return </span>instance.BuildUp(t, existing);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.BuildUp(System.Type,System.Object,System.String)"]/*'/>
</span><span style="color: blue">public static object </span>BuildUp(<span style="color: #2b91af">Type </span>t, <span style="color: blue">object </span>existing, <span style="color: blue">string </span>name)
{
<span style="color: blue">return </span>instance.BuildUp(t, existing, name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Resolve``1"]/*'/>
</span><span style="color: blue">public static </span>T Resolve<T>()
{
<span style="color: blue">return </span>instance.Resolve<T>();
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Resolve``1(System.String)"]/*'/>
</span><span style="color: blue">public static </span>T Resolve<T>(<span style="color: blue">string </span>name)
{
<span style="color: blue">return </span>instance.Resolve<T>(name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Resolve(System.Type)"]/*'/>
</span><span style="color: blue">public static object </span>Resolve(<span style="color: #2b91af">Type </span>t)
{
<span style="color: blue">return </span>instance.Resolve(t);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Resolve(System.Type,System.String)"]/*'/>
</span><span style="color: blue">public static object </span>Resolve(<span style="color: #2b91af">Type </span>t, <span style="color: blue">string </span>name)
{
<span style="color: blue">return </span>instance.Resolve(t, name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.ResolveAll``1"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IEnumerable</span><T> ResolveAll<T>()
{
<span style="color: blue">return </span>instance.ResolveAll<T>();
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.ResolveAll(System.Type)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IEnumerable</span><<span style="color: blue">object</span>> ResolveAll(<span style="color: #2b91af">Type </span>t)
{
<span style="color: blue">return </span>instance.ResolveAll(t);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Teardown(System.Object)"]/*'/>
</span><span style="color: blue">public static void </span>Teardown(<span style="color: blue">object </span>o)
{
instance.Teardown(o);
}
<span style="color: blue">#endregion
</span><span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC
</span><span style="color: gray">/// </summary>
</span><span style="color: blue">public static class </span><span style="color: #2b91af">Configure
</span>{
<span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC using by calling the supplied configurator.
</span><span style="color: gray">/// </summary>
/// <typeparam name="TConfigurator"></span><span style="color: green">The configurator to use</span><span style="color: gray"></typeparam>
</span><span style="color: blue">public static void </span>From<TConfigurator>() <span style="color: blue">where </span>TConfigurator : <span style="color: #2b91af">IUnityContainerConfigurator</span>, <span style="color: blue">new</span>()
{
From(<span style="color: blue">new </span>TConfigurator());
}
<span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC using by calling the supplied configurator.
</span><span style="color: gray">/// </summary>
/// <param name="configurationInterface"></span><span style="color: green">The configurator instance to use</span><span style="color: gray"></param>
</span><span style="color: blue">public static void </span>From(<span style="color: #2b91af">IUnityContainerConfigurator </span>configurationInterface)
{
configurationInterface.Configure(instance);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance``1(``0)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance<TInterface>(TInterface instance)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance<TInterface>(instance);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance``1(System.String,``0)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance<TInterface>(<span style="color: blue">string </span>name, TInterface instance)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance<TInterface>(name, instance);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance(System.Type,System.Object)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance(<span style="color: #2b91af">Type </span>t, <span style="color: blue">object </span>instance)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance(t, instance);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance``1(``0,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance<TInterface>(TInterface instance, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance<TInterface>(instance, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance``1(System.String,``0,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance<TInterface>(<span style="color: blue">string </span>name, TInterface instance, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance<TInterface>(name, instance, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance(System.Type,System.Object,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance(<span style="color: #2b91af">Type </span>t, <span style="color: blue">object </span>instance, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance(t, instance, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance(System.Type,System.String,System.Object)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance(<span style="color: #2b91af">Type </span>t, <span style="color: blue">string </span>name, <span style="color: blue">object </span>instance)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance(t, name, instance);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterInstance(System.Type,System.String,System.Object,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterInstance(<span style="color: #2b91af">Type </span>t, <span style="color: blue">string </span>name, <span style="color: blue">object </span>instance, <span style="color: #2b91af">LifetimeManager </span>lifetime)
{
<span style="color: blue">return </span><span style="color: #2b91af">IoC</span>.instance.RegisterInstance(t, name, instance, lifetime);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``2"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<TFrom, TTo>() <span style="color: blue">where </span>TTo : TFrom
{
<span style="color: blue">return </span>instance.RegisterType<TFrom, TTo>();
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``1(Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<T>(<span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType<T>(lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``2(Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<TFrom, TTo>(<span style="color: #2b91af">LifetimeManager </span>lifetimeManager) <span style="color: blue">where </span>TTo : TFrom
{
<span style="color: blue">return </span>instance.RegisterType<TFrom, TTo>(lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``2(System.String)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<TFrom, TTo>(<span style="color: blue">string </span>name) <span style="color: blue">where </span>TTo : TFrom
{
<span style="color: blue">return </span>instance.RegisterType<TFrom, TTo>(name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``1(System.String,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<T>(<span style="color: blue">string </span>name, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType<T>(name, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType``2(System.String,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType<TFrom, TTo>(<span style="color: blue">string </span>name, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager) <span style="color: blue">where </span>TTo : TFrom
{
<span style="color: blue">return </span>instance.RegisterType<TFrom, TTo>(name, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>t, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType(t, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,System.Type)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>from, <span style="color: #2b91af">Type </span>to)
{
<span style="color: blue">return </span>instance.RegisterType(from, to);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,System.String,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>t, <span style="color: blue">string </span>name, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType(t, name, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,System.Type,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>from, <span style="color: #2b91af">Type </span>to, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType(from, to, lifetimeManager);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,System.Type,System.String)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>from, <span style="color: #2b91af">Type </span>to, <span style="color: blue">string </span>name)
{
<span style="color: blue">return </span>instance.RegisterType(from, to, name);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Configure.RegisterType(System.Type,System.Type,System.String,Microsoft.Practices.Unity.LifetimeManager)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>RegisterType(<span style="color: #2b91af">Type </span>from, <span style="color: #2b91af">Type </span>to, <span style="color: blue">string </span>name, <span style="color: #2b91af">LifetimeManager </span>lifetimeManager)
{
<span style="color: blue">return </span>instance.RegisterType(from, to, name, lifetimeManager);
}
}
<span style="color: blue">public static class </span><span style="color: #2b91af">Enterprise
</span>{
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Enterprise.AddExtension(Microsoft.Practices.Unity.UnityContainerExtension)"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>AddExtension(<span style="color: #2b91af">UnityContainerExtension </span>extension)
{
<span style="color: blue">return </span>instance.AddExtension(extension);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Enterprise.AddNewExtension``1"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>AddNewExtension<TExtension>() <span style="color: blue">where </span>TExtension : <span style="color: #2b91af">UnityContainerExtension</span>, <span style="color: blue">new</span>()
{
<span style="color: blue">return </span>instance.AddNewExtension<TExtension>();
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Enterprise.Configure``1"]/*'/>
</span><span style="color: blue">public static </span>TConfigurator Configure<TConfigurator>() <span style="color: blue">where </span>TConfigurator : <span style="color: #2b91af">IUnityContainerExtensionConfigurator
</span>{
<span style="color: blue">return </span>instance.Configure<TConfigurator>();
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Enterprise.Configure(System.Type)"]/*'/>
</span><span style="color: blue">public static object </span>Configure(<span style="color: #2b91af">Type </span>configurationInterface)
{
<span style="color: blue">return </span>instance.Configure(configurationInterface);
}
<span style="color: gray">/// <include file='IoCComments.xml' path='doc/members/member[@name="M:Unity.Single.IoC.Enterprise.CreateChildContainer"]/*'/>
</span><span style="color: blue">public static </span><span style="color: #2b91af">IUnityContainer </span>CreateChildContainer()
{
<span style="color: blue">return </span>instance.CreateChildContainer();
}
}
}
<span style="color: gray">/// <summary>
/// </span><span style="color: green">An interface which must be implemented to create a configurator class for the UnityContainer.
</span><span style="color: gray">/// </summary>
</span><span style="color: blue">public interface </span><span style="color: #2b91af">IUnityContainerConfigurator
</span>{
<span style="color: gray">/// <summary>
/// </span><span style="color: green">This method will be called to actually configure the container.
</span><span style="color: gray">/// </summary>
/// <param name="destination"></span><span style="color: green">The container to configure.</span><span style="color: gray"></param>
</span><span style="color: blue">void </span>Configure(<span style="color: #2b91af">IUnityContainer </span>destination);
}
}</pre>
<p>The XML comments are in <a class="File XML" href="http://davy.landman.googlepages.com/IoCComments.xml" target="_blank">a separate file</a> because they are from unity which has a MsPL which is not compliant with the license I’ve chosen, separating them also reduces the documentation clutter. Just place the comment file in the same directory as the source (<a class="CS File" title="Download the Unity.Single directly" href="http://davy.landman.googlepages.com/IoC.cs" target="_blank">which can also be downloaded directly</a>).</p>
<p>I’ve divided the functions in three parts: basic stuff (Resolving and Building), configuration and more Enterprisy (really not fond of the name, if someone knows a better name please do tell) functionality. Below is a sample of the usage of this IoC wrapper.</p>
<pre class="Source"><span style="color: blue">using </span>System;
<span style="color: blue">using </span>Unity.Single;
<span style="color: blue">namespace </span>TestApplication
{
<span style="color: blue">public interface </span><span style="color: #2b91af">ILogger
</span>{
<span style="color: blue">void </span>Write(<span style="color: blue">string </span>message);
}
<span style="color: blue">public class </span><span style="color: #2b91af">Logger1 </span>: <span style="color: #2b91af">ILogger
</span>{
<span style="color: blue">public void </span>Write(<span style="color: blue">string </span>message)
{
<span style="color: #2b91af">Console</span>.Write(<span style="color: #a31515">"Logger1: {0}"</span>, message);
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">Logger2 </span>: <span style="color: #2b91af">ILogger
</span>{
<span style="color: blue">public void </span>Write(<span style="color: blue">string </span>message)
{
<span style="color: #2b91af">Console</span>.Write(<span style="color: #a31515">"Logger2: {0}"</span>, message);
}
}
<span style="color: blue">class </span><span style="color: #2b91af">Program
</span>{
<span style="color: blue">static void </span>Main(<span style="color: blue">string</span>[] args)
{
<span style="color: #2b91af">IoC</span>.<span style="color: #2b91af">Configure</span>.RegisterType<<span style="color: #2b91af">ILogger</span>, <span style="color: #2b91af">Logger1</span>>();
<span style="color: #2b91af">IoC</span>.Resolve<<span style="color: #2b91af">ILogger</span>>().Write(<span style="color: #a31515">"First call"</span>);
<span style="color: #2b91af">Console</span>.WriteLine();
<span style="color: #2b91af">IoC</span>.<span style="color: #2b91af">Configure</span>.RegisterType<<span style="color: #2b91af">ILogger</span>, <span style="color: #2b91af">Logger2</span>>();
<span style="color: #2b91af">IoC</span>.Resolve<<span style="color: #2b91af">ILogger</span>>().Write(<span style="color: #a31515">"Second call"</span>);
<span style="color: #2b91af">Console</span>.ReadLine();
}
}
}</pre>
<h3>StructureMaps Registry functionality </h3>
<p>I’ve used StructureMap for a few private projects and I really like the <a href="http://structuremap.sourceforge.net/RegistryDSL.htm" target="_blank">Registry DSL</a>, Unity also has a DSL to do the configuration but doesn’t offer the opportunity to group the configuration in separate units of configuration as StructureMaps Registry class does. This will decrease the complexity in your application initialization, the wire-up code does not need to know which Repository should be used for the IRepository interface. The architecture just offers a default configuration for the repositories and the wire-up code passes that configuration to the IoC container. I’ve created a interface which should be implemented to be a configurator. And that just it. I’ve extracted the relevant code below.</p>
<pre class="Source"><span style="color: gray">/// <summary>
/// </span><span style="color: green">An interface which must be implemented to create a configurator class for the UnityContainer.
</span><span style="color: gray">/// </summary>
</span><span style="color: blue">public interface </span><span style="color: #2b91af">IUnityContainerConfigurator
</span>{
<span style="color: gray">/// <summary>
/// </span><span style="color: green">This method will be called to actually configure the container.
</span><span style="color: gray">/// </summary>
/// <param name="destination"></span><span style="color: green">The container to configure.</span><span style="color: gray"></param>
</span><span style="color: blue">void </span>Configure(<span style="color: #2b91af">IUnityContainer </span>destination);
}
<span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC
</span><span style="color: gray">/// </summary>
</span><span style="color: blue">public static class </span><span style="color: #2b91af">Configure
</span>{
<span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC using by calling the supplied configurator.
</span><span style="color: gray">/// </summary>
/// <typeparam name="TConfigurator"></span><span style="color: green">The configurator to use</span><span style="color: gray"></typeparam>
</span><span style="color: blue">public static void </span>From<TConfigurator>()
<span style="color: blue">where </span>TConfigurator : <span style="color: #2b91af">IUnityContainerConfigurator</span>, <span style="color: blue">new</span>()
{
From(<span style="color: blue">new </span>TConfigurator());
}
<span style="color: gray">/// <summary>
/// </span><span style="color: green">Configure the IoC using by calling the supplied configurator.
</span><span style="color: gray">/// </summary>
/// <param name="configurationInterface"></span><span style="color: green">The configurator instance to use</span><span style="color: gray"></param>
</span><span style="color: blue">public static void </span>From(<span style="color: #2b91af">IUnityContainerConfigurator </span>configurationInterface)
{
configurationInterface.Configure(instance);
}
}</pre>
<p>Below is an example usage of this. The build-up application does not need to know which repository to map to the IProductRepository, it leaves that responsibility to the Architecture itself. You can even hide the real Repository implementation because the mapping is done inside the same namespace.  </p>
<pre class="Source"><span style="color: blue">namespace </span>TestApplication.Contract
{
<span style="color: green">// very simple repository
</span><span style="color: blue">public interface </span><span style="color: #2b91af">IRepository</span><T>
{
T Get(<span style="color: #2b91af">Int32 </span>id);
<span style="color: blue">void </span>Add(T newEntity);
<span style="color: #2b91af">IEnumerable</span><T> List();
}
<span style="color: blue">public interface </span><span style="color: #2b91af">IProductRepository </span>: <span style="color: #2b91af">IRepository</span><<span style="color: #2b91af">Product</span>>
{
<span style="color: green">// simple example
</span><span style="color: #2b91af">IEnumerable</span><<span style="color: #2b91af">Product</span>> ListCheaperThan(<span style="color: #2b91af">Decimal </span>maximumPrice);
}
<span style="color: blue">public interface </span><span style="color: #2b91af">IEmail
</span>{
<span style="color: #2b91af">Boolean </span>Send(<span style="color: #2b91af">MailMessage </span>message);
}
}
<span style="color: blue">namespace </span>TestApplication.Architecture.EntityFramework
{
<span style="color: blue">using </span>TestApplication.Contract;
<span style="color: blue">using </span>Unity.Single;
<span style="color: blue">class </span><span style="color: #2b91af">Repository</span><T> : <span style="color: #2b91af">IRepository</span><T>
{
<span style="color: blue">protected </span><span style="color: #2b91af">ObjectContext</span><T> context;
<span style="color: blue">public </span>Repository ()
{
context = <span style="color: blue">new </span><span style="color: #2b91af">ObjectContext</span><T>();
}
<span style="color: blue">#region </span>IRepository<T> Members
<span style="color: blue">public </span>T Get(<span style="color: blue">int </span>id)
{
<span style="color: blue">return </span>context.RetrieveById(id);
}
<span style="color: blue">public void </span>Add(T newEntity)
{
context.Insert(newEntity);
}
<span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span><T> List()
{
<span style="color: blue">return </span>context.EntitySet;
}
<span style="color: blue">#endregion
</span>}
<span style="color: blue">class </span><span style="color: #2b91af">ProductRepository </span>: <span style="color: #2b91af">Repository</span><<span style="color: #2b91af">Product</span>>, <span style="color: #2b91af">IProductRepository
</span>{
<span style="color: blue">#region </span>IProductRepository Members
<span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span><<span style="color: #2b91af">Product</span>> ListCheaperThan(<span style="color: blue">decimal </span>maximumPrice)
{
<span style="color: blue">return </span>context.EntitySet.Where(prod => prod.Price < maximumPrice);
}
<span style="color: blue">#endregion
</span>}
<span style="color: blue">public class </span><span style="color: #2b91af">DefaultConfiguration </span>: <span style="color: #2b91af">IUnityContainerConfigurator
</span>{
<span style="color: blue">public void </span>Configure(Microsoft.Practices.Unity.<span style="color: #2b91af">IUnityContainer </span>destination)
{
destination.RegisterType<<span style="color: #2b91af">IProductRepository</span>, <span style="color: #2b91af">ProductRepository</span>>();
}
}
}
<span style="color: blue">namespace </span>TestApplication.WebInterface
{
<span style="color: blue">using </span>Unity.Single;
<span style="color: blue">using </span>TestApplication.Contract;
<span style="color: blue">using </span>TestApplication.Architecture.EntityFramework;
<span style="color: blue">class </span><span style="color: #2b91af">ASPMailer </span>: <span style="color: #2b91af">IEmail
</span>{
<span style="color: blue">public bool </span>Send(System.Net.Mail.<span style="color: #2b91af">MailMessage </span>message)
{
<span style="color: blue">throw new </span>System.<span style="color: #2b91af">NotImplementedException</span>();
}
}
<span style="color: blue">public class </span><span style="color: #2b91af">Application
</span>{
<span style="color: blue">public void </span>Startup()
{
<span style="color: #2b91af">IoC</span>.<span style="color: #2b91af">Configure</span>.From<<span style="color: #2b91af">DefaultConfiguration</span>>();
<span style="color: #2b91af">IoC</span>.<span style="color: #2b91af">Configure</span>.RegisterType<<span style="color: #2b91af">IEmail</span>, <span style="color: #2b91af">ASPMailer</span>>();
}
}
}</pre>
<p>Have fun :)</p> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0tag:blogger.com,1999:blog-3108828885823618940.post-52194953024277093772008-11-21T15:38:00.001+01:002009-05-08T11:40:23.168+02:00LINQ to Entities string based dynamic OrderBy<p><img class="BlogTitleImage" title="The String Maker picture by hpk on http://flickr.com/photos/hpk/86047888/" alt="The String Maker picture by hpk on http://flickr.com/photos/hpk/86047888/" src="http://farm1.static.flickr.com/36/86047888_c68f81731e_m.jpg" />The problem I kept having was that at some point you’ll need to convert the <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.sortexpression.aspx" target="_blank">GridView.SortExpression</a> from your ASP.NET GridView to a Lamba Expression for your <a href="http://msdn.microsoft.com/en-us/library/system.linq.queryable.orderby.aspx" target="_blank">Queryable.OrderBy</a>. </p> <h3>The challenge </h3> <p>You’ll get the string.</p> <pre class="Source">“OrderDate DESC”</pre>
<p>And you have to translate that to:</p>
<pre class="Source">ObjectContext.Orders.OrderByDescending(order => order.OrderDate)</pre>
<p>In march/may I had spent a half day researching possibilities to solve this automatically. At that point I couldn’t find a clean solution. So I went with a generated solution (using T4 templates) which generated a big switch statement per entity.</p>
<h3>A nice solution</h3>
<p>We jump to november and I was browsing a little bit on <a href="http://stackoverflow.com/" target="_blank">StackOverflow</a> to see if their were some interesting questions. My eye caught the question “<a href="http://stackoverflow.com/questions/307512/how-do-i-apply-orderby-on-an-iqueryable-using-a-string-column-name-within-a-gen#308561" target="_blank">How do I apply OrderBy on an IQueryable using a string column name within a generic extension method?</a>”, and it got me started to solve the sorting challenge. I had some hours available so I thought I’d give it another try. </p>
<p><a href="http://vgermain.wordpress.com/2008/09/23/linq-to-sql-how-to-order-with-a-string-typed-expression/" target="_blank">There</a> <a href="http://www.sql.ru/forum/actualthread.aspx?tid=609485&pg=3" target="_blank">are</a> <a href="http://technoesis.wordpress.com/2008/03/03/linq-to-sql-dynamic-sorting-without-using-complete-dynamic-linq-libraries/" target="_blank">a</a> few other’s who have created a solution using the Expression building method, and I’ve combined it and refactored it to make it match more with the current Entity Framework. I’ve also added support for an infinite amount of child entities.</p>
<pre style="height: 50em" class="Source Boxed"><span style="color: green">/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is LINQExtensions.StringFieldNameSortingSupport.
*
* The Initial Developer of the Original Code is
* Davy Landman.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
</span><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Linq;
<span style="color: blue">using </span>System.Linq.Expressions;
<span style="color: blue">using </span>System.Reflection;
<span style="color: blue">namespace </span>LINQExtensions
{
<span style="color: blue">public static class </span><span style="color: #2b91af">StringFieldNameSortingSupport
</span>{
<span style="color: blue">#region </span>Private expression tree helpers
<span style="color: blue">private static </span><span style="color: #2b91af">LambdaExpression </span>GenerateSelector<TEntity>(<span style="color: #2b91af">String </span>propertyName, <span style="color: blue">out </span><span style="color: #2b91af">Type </span>resultType) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: green">// Create a parameter to pass into the Lambda expression (Entity => Entity.OrderByField).
</span><span style="color: blue">var </span>parameter = <span style="color: #2b91af">Expression</span>.Parameter(<span style="color: blue">typeof</span>(TEntity), <span style="color: #a31515">"Entity"</span>);
<span style="color: green">// create the selector part, but support child properties
</span><span style="color: #2b91af">PropertyInfo </span>property;
<span style="color: #2b91af">Expression </span>propertyAccess;
<span style="color: blue">if </span>(propertyName.Contains(<span style="color: #a31515">'.'</span>))
{
<span style="color: green">// support to be sorted on child fields.
</span><span style="color: #2b91af">String</span>[] childProperties = propertyName.Split(<span style="color: #a31515">'.'</span>);
property = <span style="color: blue">typeof</span>(TEntity).GetProperty(childProperties[0], <span style="color:#2b91af">BindingFlags</span>.Instance | <span style="color:#2b91af">BindingFlags</span>.NonPublic | <span style="color:#2b91af">BindingFlags</span>.Public);
propertyAccess = <span style="color: #2b91af">Expression</span>.MakeMemberAccess(parameter, property);
<span style="color: blue">for </span>(<span style="color: blue">int </span>i = 1; i < childProperties.Length; i++)
{
property = property.PropertyType.GetProperty(childProperties[i], <span style="color:#2b91af">BindingFlags</span>.Instance | <span style="color:#2b91af">BindingFlags</span>.NonPublic | <span style="color:#2b91af">BindingFlags</span>.Public);
propertyAccess = <span style="color: #2b91af">Expression</span>.MakeMemberAccess(propertyAccess, property);
}
}
<span style="color: blue">else
</span>{
property = <span style="color: blue">typeof</span>(TEntity).GetProperty(propertyName, <span style="color:#2b91af">BindingFlags</span>.Instance | <span style="color:#2b91af">BindingFlags</span>.NonPublic | <span style="color:#2b91af">BindingFlags</span>.Public);
propertyAccess = <span style="color: #2b91af">Expression</span>.MakeMemberAccess(parameter, property);
}
resultType = property.PropertyType;
<span style="color: green">// Create the order by expression.
</span><span style="color: blue">return </span><span style="color: #2b91af">Expression</span>.Lambda(propertyAccess, parameter);
}
<span style="color: blue">private static </span><span style="color: #2b91af">MethodCallExpression </span>GenerateMethodCall<TEntity>(<span style="color: #2b91af">IQueryable</span><TEntity> source, <span style="color: blue">string </span>methodName, <span style="color: #2b91af">String </span>fieldName) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">Type </span>type = <span style="color: blue">typeof</span>(TEntity);
<span style="color: #2b91af">Type </span>selectorResultType;
<span style="color: #2b91af">LambdaExpression </span>selector = GenerateSelector<TEntity>(fieldName, <span style="color: blue">out </span>selectorResultType);
<span style="color: #2b91af">MethodCallExpression </span>resultExp = <span style="color: #2b91af">Expression</span>.Call(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Queryable</span>), methodName,
<span style="color: blue">new </span><span style="color: #2b91af">Type</span>[] { type, selectorResultType },
source.Expression, <span style="color: #2b91af">Expression</span>.Quote(selector));
<span style="color: blue">return </span>resultExp;
}
<span style="color: blue">#endregion
public static </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> OrderBy<TEntity>(<span style="color: blue">this </span><span style="color: #2b91af">IQueryable</span><TEntity> source, <span style="color: blue">string </span>fieldName) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">MethodCallExpression </span>resultExp = GenerateMethodCall<TEntity>(source, <span style="color: #a31515">"OrderBy"</span>, fieldName);
<span style="color: blue">return </span>source.Provider.CreateQuery<TEntity>(resultExp) <span style="color: blue">as </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity>;
}
<span style="color: blue">public static </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> OrderByDescending<TEntity>(<span style="color: blue">this </span><span style="color: #2b91af">IQueryable</span><TEntity> source, <span style="color: blue">string </span>fieldName) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">MethodCallExpression </span>resultExp = GenerateMethodCall<TEntity>(source, <span style="color: #a31515">"OrderByDescending"</span>, fieldName);
<span style="color: blue">return </span>source.Provider.CreateQuery<TEntity>(resultExp) <span style="color: blue">as </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity>;
}
<span style="color: blue">public static </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> ThenBy<TEntity>(<span style="color: blue">this </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> source, <span style="color: blue">string </span>fieldName) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">MethodCallExpression </span>resultExp = GenerateMethodCall<TEntity>(source, <span style="color: #a31515">"ThenBy"</span>, fieldName);
<span style="color: blue">return </span>source.Provider.CreateQuery<TEntity>(resultExp) <span style="color: blue">as </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity>;
}
<span style="color: blue">public static </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> ThenByDescending<TEntity>(<span style="color: blue">this </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> source, <span style="color: blue">string </span>fieldName) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">MethodCallExpression </span>resultExp = GenerateMethodCall<TEntity>(source, <span style="color: #a31515">"ThenByDescending"</span>, fieldName);
<span style="color: blue">return </span>source.Provider.CreateQuery<TEntity>(resultExp) <span style="color: blue">as </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity>;
}
<span style="color: blue">public static </span><span style="color: #2b91af">IOrderedQueryable</span><TEntity> OrderUsingSortExpression<TEntity>(<span style="color: blue">this </span><span style="color: #2b91af">IQueryable</span><TEntity> source, <span style="color: blue">string </span>sortExpression) <span style="color: blue">where </span>TEntity : <span style="color: blue">class
</span>{
<span style="color: #2b91af">String</span>[] orderFields = sortExpression.Split(<span style="color: #a31515">','</span>);
<span style="color: #2b91af">IOrderedQueryable</span><TEntity> result = <span style="color: blue">null</span>;
<span style="color: blue">for </span>(<span style="color: blue">int </span>currentFieldIndex = 0; currentFieldIndex < orderFields.Length; currentFieldIndex++)
{
<span style="color: #2b91af">String</span>[] expressionPart = orderFields[currentFieldIndex].Trim().Split(<span style="color: #a31515">' '</span>);
<span style="color: #2b91af">String </span>sortField = expressionPart[0];
<span style="color: #2b91af">Boolean </span>sortDescending = (expressionPart.Length == 2) && (expressionPart[1].Equals(<span style="color: #a31515">"DESC"</span>, <span style="color: #2b91af">StringComparison</span>.OrdinalIgnoreCase));
<span style="color: blue">if </span>(sortDescending)
{
result = currentFieldIndex == 0 ? source.OrderByDescending(sortField) : result.ThenByDescending(sortField);
}
<span style="color: blue">else
</span>{
result = currentFieldIndex == 0 ? source.OrderBy(sortField) : result.ThenBy(sortField);
}
}
<span style="color: blue">return </span>result;
}
}
}</pre>
<p>You can also <a class="CS File" href="http://davy.landman.googlepages.com/LINQExtensions.cs">download this file</a>. All you have to do to use these extensions methods is add a <span class="Source"><span style="color: blue">using </span>LINQExtensions;"</span>.</p>
<p>It's now very simple to write queries like this</p>
<pre class="Source"><span style="color: blue">var </span>result = queryableOrders.OrderBy(<span style="color: #a31515">"Employee.LastName"</span>).ThenByDescending(<span style="color: #a31515">"Freight"</span>).ToList();</pre>
<p>I’ve deliberately kept the parsing of the SortExpression out of these extension methods. In my opinion it should be kept outside of the string field names support. I’ve added a new extension method just for this purpose. </p>
<pre class="Source"><span style="color: blue">var </span>result = queryableOrders.OrderUsingSortExpression(<span style="color: #a31515">"Employee.LastName, Freight DESC"</span>).ToList();</pre>
<h3>Bummer</h3>
<p>When researching for writing this article I found the article <a href="http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx" target="_blank">Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)</a> by the Scott Guthrie, which does exactly as I developed. The only reason I still post this code is that it’s less heavy and not under de Microsoft Permissive License (but under a very flexible triple license). </p>
<p>So decide for yourself, use this code directly or download the samples pack and locate the DynamicLinq folder and use that library (which has some very cool stuff in it).</p> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com12tag:blogger.com,1999:blog-3108828885823618940.post-3386308779588923192008-10-22T16:35:00.002+02:002009-01-21T23:04:53.368+01:00Binding the ObjectContext Life-Cycle to the current ASP.NET request<p><img class="BlogTitleImage" src="http://farm1.static.flickr.com/78/166484190_3fac76afb0_m_d.jpg" alt="This spider thread picture from flickr is from Infinity Rain and has the nc-nd-2.0 license." title="Spider threads by Infinity Rain" width="240" height="180" /> My team has switched (with the coaching of <a href="http://www.class-a.nl/" target="_blank">class-a</a>) to <a href="http://msdn.microsoft.com/en-us/library/cc161164.aspx" target="_blank">LINQ to Entities</a> from the <a href="http://msdn.microsoft.com/en-us/data/aa937723.aspx" target="_blank">ADO.NET Entity Framework</a> for our new applications. Because we came from <a href="http://msdn.microsoft.com/en-us/library/ms171895.aspx" target="_blank">ADO.NET Typed Datasets</a> we hade to revise our architecture. Together with a team member we designed our new architecture (and asked <a href="http://www.alexthissen.nl/blogs/" target="_blank">Alex Thissen</a> to review it). We used a new project to test our architecture and use pair programming to solve problems which arose during the development of the business layer.</p> <p>We encapsulated the <a href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.aspx" target="_blank">ObjectContext</a> from the Entity Framework using the repository pattern. How we did this I might post about later, but now I’m going to discuss something else. </p> <p>The problem was that each entity got it’s own repository, but you have to share the ObjectContext, or nothing works except the stuff that happens on that entity alone. Anyone who uses the LINQ to Entities (or LINQ to SQL) can guess what happened, a lot of Exceptions and non updating data. So there are two ways we could solve it, create an repository factory which would inject the correct ObjectContext or make some kind of singleton access to a ObjectContext. We chose for the second solution because we already had an repository factory which we’re planning to use as a unit of work pattern. So that repository factory couldn’t be a singleton and we still had to solve the same problem of the ObjectContext instances.</p> <p>The singleton pattern I would have normally used was the <a href="http://www.yoda.arachsys.com/csharp/singleton.html" target="_blank">fully lazy instantiation singleton by Jon Skeet</a> which in my opinion should be mentioned in the <a href="http://msdn.microsoft.com/en-us/library/ms998558.aspx" target="_blank">MSDN P&P Article: Implementing Singleton in C#</a>. But we wanted a ObjectContext per request, so it’s not really a singleton but more a more managed life-cycle. Although most of our applications are web based, I’d like it if it could survive outside of ASP.NET. Alex Thissen gave us a sample of how he did it, and we used it for a while. The code he provided is below.</p> <pre class="Source Boxed" style="height: 20em"><span style="color: blue">public class </span><span style="color: #2b91af">DataContextFactory
</span><span>{
</span><span style="color: blue">private const string </span><span>DATACONTEXTKEY = </span><span style="color: #a31515">"NorthwindataContext"</span><span>;
</span><span style="color: blue">private static object </span><span>myLock = </span><span style="color: blue">new object</span><span>();
</span><span style="color: blue">internal static </span><span style="color: #2b91af">NorthwindEntities </span><span>CurrentContext
{
</span><span style="color: blue">get
</span><span>{
</span><span style="color: #2b91af">NorthwindEntities </span><span>context = DataContext;
</span><span style="color: blue">if </span><span>(context == </span><span style="color: blue">null</span><span>)
{
</span><span style="color: blue">lock </span><span>(myLock)
{
</span><span style="color: blue">if </span><span>(context == </span><span style="color: blue">null</span><span>)
{
context = </span><span style="color: blue">new </span><span style="color: #2b91af">NorthwindEntities
</span><span>DataContext = context;
}
}
}
</span><span style="color: blue">return </span><span>context;
}
}
</span><span style="color: blue">private static </span><span style="color: #2b91af">NorthwindEntities </span><span>DataContext
{
</span><span style="color: blue">get
</span><span>{
</span><span style="color: blue">if </span><span>(IsInWebContext)
{
</span><span style="color: blue">return </span><span>(</span><span style="color: #2b91af">NorthwindEntities</span><span>)</span><span style="color: #2b91af">HttpContext</span><span>.Current.Items[DATACONTEXTKEY];
}
</span><span style="color: blue">else
</span><span>{
</span><span style="color: blue">return </span><span>(</span><span style="color: #2b91af">NorthwindEntities</span><span>)</span><span style="color: #2b91af">CallContext</span><span>.GetData(DATACONTEXTKEY);
}
}
</span><span style="color: blue">set
</span><span>{
</span><span style="color: blue">if </span><span>(IsInWebContext)
{
</span><span style="color: #2b91af">HttpContext</span><span>.Current.Items[DATACONTEXTKEY] = </span><span style="color: blue">value</span><span>;
}
</span><span style="color: blue">else
</span><span>{
</span><span style="color: #2b91af">CallContext</span><span>.SetData(DATACONTEXTKEY, </span><span style="color: blue">value</span><span>);
}
}
}
</span><span style="color: blue">private static bool </span><span>IsInWebContext
{
</span><span style="color: blue">get </span><span>{ </span><span style="color: blue">return </span><span style="color: #2b91af">HttpContext</span><span>.Current != </span><span style="color: blue">null</span><span>; }
}
}</span></pre>
<p>We used it in the beginning and it worked. But when I started developing a T4 template for our repositories I looked at the code again and it didn’t feel right, especially the locking. Because both the HttpContext.Current as the CallContext are unique for each thread, so why do we need to lock if only one thread access the same HttpContext.Current or CallContext (please correct me if I'm wrong). A little bit searching on the internet lead me to <a href="http://dotnetslackers.com/community/blogs/simoneb/archive/2007/04/17/ASP.NET-Singleton_2D00_per_2D00_Page-pattern.aspx" target="_blank">SimoneB's post about the ASP.NET Singleton-per-Page pattern</a>, I combined this with the CallContext knowledge in my own DataContextFactory. The code for that factory is located below.</p>
<pre class="Source Boxed" style="height: 33em"><span style="color: blue">internal class </span><span style="color: #2b91af">DataContextFactory
</span><span>{
</span><span style="color: blue">public static </span><span style="color: #2b91af">NorthwindEntities </span><span>CurrentContext
{
</span><span style="color: blue">get
</span><span>{
</span><span style="color: blue">if </span><span>(IsInWebContext)
{
</span><span style="color: green">// support the difference between pages in Server.Transfer
</span><span style="color: #2b91af">Page </span><span>currentPage = </span><span style="color: #2b91af">HttpContext</span><span>.Current.Handler </span><span style="color: blue">as </span><span style="color: #2b91af">Page</span><span>;
</span><span style="color: blue">if</span><span>(currentPage == </span><span style="color: blue">null</span><span>)
</span><span style="color: blue">throw new </span><span style="color: #2b91af">NullReferenceException</span><span>(</span><span style="color: #a31515">"The page is null"</span><span>);
</span><span style="color: blue">return </span><span>(currentPage.Items[</span><span style="color: #a31515">"NorthwindEntitiesSingleton"</span><span>] ??
(currentPage.Items[</span><span style="color: #a31515">"NorthwindEntitiesSingleton"</span><span>] =
</span><span style="color: blue">new </span><span style="color: #2b91af">NorthwindEntities</span><span>())) </span><span style="color: blue">as </span><span style="color: #2b91af">NorthwindEntities</span><span>;
}
</span><span style="color: blue">else
</span><span>{
</span><span style="color: #2b91af">NorthwindEntities </span><span>result = </span><span style="color: #2b91af">CallContext</span><span>.GetData(</span><span style="color: #a31515">"NorthwindEntitiesSingleton"</span><span>) </span><span style="color: blue">as </span><span style="color: #2b91af">NorthwindEntities</span><span>;
</span><span style="color: blue">if </span><span>(result == </span><span style="color: blue">null</span><span>)
{
result = </span><span style="color: blue">new </span><span style="color: #2b91af">NorthwindEntities</span><span>();
</span><span style="color: #2b91af">CallContext</span><span>.SetData(</span><span style="color: #a31515">"NorthwindEntitiesSingleton"</span><span>, result);
}
</span><span style="color: blue">return </span><span>result;
}
}
}
</span><span style="color: blue">private static bool </span><span>IsInWebContext
{
</span><span style="color: blue">get </span><span>{ </span><span style="color: blue">return </span><span style="color: #2b91af">HttpContext</span><span>.Current != </span><span style="color: blue">null</span><span>; }
}
}
</span></pre>
<p>Because our repositories are generated this DataContextFactory is also generated and therefore it has the string copied allover the place. </p>
<p>Our repositories and the repository factory both store the DataContext in a private field, so if the repository instance is stored in a session, the context will remain the same, but if you create a new repository you’ll have the current DataContext.  To make this more transparent we used the following rule: when we need to use the unit of work pattern, we store the repository factory in the session and only request repositories from that factory. If it’s just a simple page, request the desired repository directly. Below is an example of how a repository looks like using the ContextFactory.</p>
<pre class="Source Boxed" style="height: 15em"><span style="color: blue">public partial class </span><span style="color: #2b91af">CategoryRepository</span><span>: </span><span style="color: #2b91af">ICategoryRepository
</span><span>{
</span><span style="color: blue">private </span><span style="color: #2b91af">NorthwindEntities </span><span>context;
</span><span style="color: gray">/// <summary>
/// </span><span style="color: green">Implement this partial method to execute code after the constructor.
</span><span style="color: gray">/// </summary>
</span><span style="color: blue">partial void </span><span>AfterConstructed();
</span><span style="color: blue">public </span><span>CategoryRepository() :
</span><span style="color: blue">this </span><span>(</span><span style="color: #2b91af">DataContextFactory</span><span>.CurrentContext)
{
}
</span><span style="color: blue">internal </span><span>CategoryRepository(</span><span style="color: #2b91af">NorthwindEntities </span><span>context)
{
</span><span style="color: blue">this</span><span>.context = context;
AfterConstructed();
}</span>
<span style="color: green">// The rest</span>
<span>}</span></pre>
<p>I just have one problem I haven’t figured out yet, the DataContext implements IDisposable, so when I’m done with it I should call Dispose to clean the resources. The problem is, I don’t know when to correctly call Dispose. So if anybody has a good idea how to solve this?</p> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com1tag:blogger.com,1999:blog-3108828885823618940.post-18011584042634725902008-07-13T20:03:00.000+02:002009-01-21T23:04:30.239+01:00SuperFastHash from Paul Hsieh Translated to Delphi and Borland Assembler (BASM)<img class="BlogTitleImage" title="Running Cheetah from Don Van Dyke" alt="This cheetah picture from flickr is from Don Van Dyke and has the nc-nd-2.0 license." src="http://farm1.static.flickr.com/66/163374390_68da0dce9b_m.jpg" width="240px" height="138px" /> I've been a member of the FastCode community for a little while. The FastCode community tries to optimize core functions from Delphi using mostly BASM. After they have a very intensive benchmark en validation process the winner is suggested to Borland/CodeGear through a QC report, and is likely included in the next version of Delphi. I even have a few functions which are winners in these benchmarks and have a <a title="FastCode Trim QC report" href="http://qc.borland.com/wc/qcmain.aspx?d=53744" target="_blank">QC report</a> with my function as a suggestion. <h3>How it started</h3> <p>Why this introduction? Well, the community lives in the Borland Newsgroup in the group <a title="Webinterface of the newsgroup" href="http://delphi.newswhat.com/geoxml/forumlistthreads?groupname=borland.public.delphi.language.basm" target="_blank">borland.public.delphi.language.basm</a> and it's also a general discussion place about 'hardcore' optimalizations for a Delphi function. More than a year ago Juhani Suhonen <a title="Newsgroup posting asking for a fast hash function" href="http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.language.basm&messageid=464c7c2b@newsgroups.borland.com" target="_blank">asked</a> for a fast hash to use for his hashtable. I suggested the old but nicely performing elf-hash, but also noted a much better hash function I recently found. It was called <a title="Paul Hsieh's discussion about his Hash function" href="http://www.azillionmonkeys.com/qed/hash.html" target="_blank">SuperFastHash</a> (SFH) and was created by Paul Hsieh to overcome his 'problems' with the hash functions from Bob Jenkins. Juhani asked if somebody could write the SFH function in basm. A few people worked on a basm implementation and posted it.</p> <p>In this post I will roughly describe how I as a fresh assembler optimizer created my version of the SFH function. </p> <h3>The Delphi implementation</h3> <p>I started with a regular Delphi implementation of the algorithm, using the c code from Paul's article as reference. After I got my Delphi implementation compiled and working I looked at the BASM code using the CPU debug view and tried to find points where I could help the Delphi compiler generating better assembly. Below is my initial pascal version. (beware I will post my <strong>final</strong> version later on in this post).</p> <pre class="Source Boxed" style="height: 20em"><code><span class="pas1-reservedword">function</span><span class="pas1-space"> SuperFastHash</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">:</span><span class="pas1-identifier">pointer</span><span class="pas1-symbol">;</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">:</span><span class="pas1-space"> integer</span><span class="pas1-symbol">):</span><span class="pas1-identifier">longword</span><span class="pas1-symbol">;
</span><span class="pas1-comment">// Pascal translation of the SuperFastHash function by Paul Hsieh
// more info: http://www.azillionmonkeys.com/qed/hash.html
// Translation by: Davy Landman
// No warranties, but have fun :)
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">:</span><span class="pas1-space"> longword</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes</span><span class="pas1-symbol">:</span><span class="pas1-space"> integer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> </span><span class="pas1-reservedword">not</span><span class="pas1-space"> Assigned</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">or</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADataLength </span><span class="pas1-symbol"><=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Exit</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">and</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ADataLength </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-comment">// div 4, so var name is not correct anymore..
</span><span class="pas1-space"> </span><span class="pas1-comment">// main loop
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> ADataLength </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^);
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)+</span><span class="pas1-number">2</span><span class="pas1-symbol">))^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> dec</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADataLength</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// end case
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)+</span><span class="pas1-number">2</span><span class="pas1-symbol">))^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">18</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">10</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// avalance
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">5</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">25</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result</span><span class="pas1-symbol">,</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">6</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;</span></code></pre>
<p>Warning this is not final code! </p>
<h3>The BASM implementation</h3>
<p>I posted this and later posted an assembly version of SFH, I used the CPU view and the code suggestions from Bob Gonder to create this BASM code. Using BASM you can control the exact usage of registers and you're able to fine tune the assembly much better (and easier) than writing Delphi code.</p>
<p>My enthusiasm got the better of me and I spent a whole lot of evenings optimizing the Delphi and assembly versions of the SFH function (while I should have been working on my graduation internship paper). The discussion on the newsgroup turned a few interesting corners about the different kind of definitions of a hashing function. Therefor I must note that this function should only be used for a hashtable! It's tuned for giving a good distribution but not for cryptographically or verification usage.</p>
<h3>The final unit</h3>
<p>I think I've posted my final functions in the discussion thread, but recently I created a separate function file including some new parts. For instance, I added an functions for larger data which is the same algorithm, but uses less jumps because I <a href="http://en.wikipedia.org/wiki/Loop_unrolling" target="_blank">unrolled</a> the function. Below is my final unit of the SuperFastHash function.</p>
<pre class="Source Boxed" style="height: 40em"><code><span class="pas1-reservedword">unit</span><span class="pas1-space"> unSuperFastHash</span><span class="pas1-symbol">;
</span><span class="pas1-comment">(*
A Delphi and assembly translation of the SuperFastHash function by
Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html).
I got the idea for translating it due to borland.public.delphi.language.basm.
See the full discussion at:
http://groups.google.com/group/borland.public.delphi.language.basm/
browse_thread/thread/96482ba4d1d5a016/7745466ab714c3b3
***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is SuperFastHash Delphi and BASM translation.
*
* The Initial Developer of the Original Code is
* Davy Landman.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** *)
</span><span class="pas1-reservedword">interface
</span><span class="pas1-comment">{.$define ASMVersion}
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> SuperFastHash</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">:</span><span class="pas1-space"> pointer</span><span class="pas1-symbol">;</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> SuperFastHashLargeData</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">:</span><span class="pas1-space"> pointer</span><span class="pas1-symbol">;</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">implementation
</span><span class="pas1-comment">// Pascal translation of the SuperFastHash function by Paul Hsieh
// more info: http://www.azillionmonkeys.com/qed/hash.html
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> SuperFastHash</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">:</span><span class="pas1-space"> pointer</span><span class="pas1-symbol">;</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-preprocessor">{$ifndef ASMVersion}
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">:</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingDWords</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> </span><span class="pas1-reservedword">not</span><span class="pas1-space"> Assigned</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">or</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADataLength </span><span class="pas1-symbol"><=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Exit</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">and</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-comment">// mod 4
</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-comment">// div 4
</span><span class="pas1-space"> </span><span class="pas1-comment">// main loop
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> </span><span class="pas1-comment">// splitting the pointer math keeps the amount of registers pushed at 2
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> dec</span><span class="pas1-symbol">(</span><span class="pas1-identifier">RemainingDWords</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// Handle end cases
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">);
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));</span><span class="pas1-space"> </span><span class="pas1-comment">// skip to the last byte
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">((</span><span class="pas1-identifier">PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">18</span><span class="pas1-symbol">));
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">10</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// Force "avalanching" of final 127 bits
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">5</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">25</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">6</span><span class="pas1-symbol">);
</span><span class="pas1-preprocessor">{$else}
</span><span class="pas1-reservedword">asm
</span><span class="pas1-space"> </span><span class="pas1-assembler">push</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">push</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// data
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Ret</span><span class="pas1-space"> </span><span class="pas1-comment">// eax is result
</span><span class="pas1-space"> </span><span class="pas1-assembler">xchg</span><span class="pas1-space"> </span><span class="pas1-assembler">edx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// swith data and length
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// length, and hash
</span><span class="pas1-space"> </span><span class="pas1-assembler">jle</span><span class="pas1-space"> </span><span class="pas1-assembler">@Ret
@Start:
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">and</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">3</span><span class="pas1-space"> </span><span class="pas1-comment">// last few bytes
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,</span><span class="pas1-space"> </span><span class="pas1-assembler">2</span><span class="pas1-space"> </span><span class="pas1-comment">// number of DWORD loops
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Last3
@Loop:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">2]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">edx,</span><span class="pas1-space"> </span><span class="pas1-assembler">4
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jnz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Loop
@Last3:
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@OneLeft
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@TwoLeft
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movsx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">byte</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">2]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">18
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">jmp</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
@TwoLeft:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">17
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">jmp</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
@OneLeft:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movsx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">byte</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">10
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">1
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
@Done:
</span><span class="pas1-space"> </span><span class="pas1-comment">// avalanche
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">3
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">5
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">4
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">17
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">25
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">6
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
@Ret:
</span><span class="pas1-space"> </span><span class="pas1-assembler">pop</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">pop</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">ret
</span><span class="pas1-preprocessor">{$endif}
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> SuperFastHashLargeData</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">:</span><span class="pas1-space"> pointer</span><span class="pas1-symbol">;</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-preprocessor">{$ifndef ASMVersion}
</span><span class="pas1-reservedword">type
</span><span class="pas1-space"> TWordArray </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..(</span><span class="pas1-identifier">MaxInt </span><span class="pas1-reservedword">div</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">))</span><span class="pas1-space"> </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> Word</span><span class="pas1-symbol">;
</span><span class="pas1-space"> PWordArray </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-symbol">^</span><span class="pas1-identifier">TWordArray</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">:</span><span class="pas1-space"> Cardinal</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingDWords</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> </span><span class="pas1-reservedword">not</span><span class="pas1-space"> Assigned</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">or</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADataLength </span><span class="pas1-symbol"><=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Exit</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">and</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">;
</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADataLength </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-comment">// div 4
</span><span class="pas1-space"> </span><span class="pas1-comment">// large loop
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">>=</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">2</span><span class="pas1-symbol">];
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">3</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">4</span><span class="pas1-symbol">];
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">5</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">6</span><span class="pas1-symbol">];
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWordArray</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^[</span><span class="pas1-number">7</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-comment">// update the pointer and the counter
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-number">8</span><span class="pas1-space"> </span><span class="pas1-symbol">*</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">)));
</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">:=</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// small loop
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> dec</span><span class="pas1-symbol">(</span><span class="pas1-identifier">RemainingDWords</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// Handle end cases
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">);
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));</span><span class="pas1-space"> </span><span class="pas1-comment">// skip to the last byte
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">((</span><span class="pas1-identifier">PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">18</span><span class="pas1-symbol">));
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> RemainingBytes </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PByte</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">10</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">// Force "avalanching" of final 127 bits
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">3</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">5</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">17</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">25</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">6</span><span class="pas1-symbol">);
</span><span class="pas1-preprocessor">{$else}
</span><span class="pas1-space"> </span><span class="pas1-reservedword">asm
</span><span class="pas1-space"> </span><span class="pas1-assembler">push</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">push</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// test for nil pointer
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Ret</span><span class="pas1-space"> </span><span class="pas1-comment">// eax is also result, so save ret here
</span><span class="pas1-space"> </span><span class="pas1-assembler">xchg</span><span class="pas1-space"> </span><span class="pas1-assembler">edx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// swith data and length
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax</span><span class="pas1-space"> </span><span class="pas1-comment">// length, and hash
</span><span class="pas1-space"> </span><span class="pas1-assembler">jle</span><span class="pas1-space"> </span><span class="pas1-assembler">@Ret
@Start:
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">and</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">3</span><span class="pas1-space"> </span><span class="pas1-comment">// last few bytes
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,</span><span class="pas1-space"> </span><span class="pas1-assembler">2</span><span class="pas1-space"> </span><span class="pas1-comment">// number of DWORD loops
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Last3
@LargeLoop:
</span><span class="pas1-space"> </span><span class="pas1-assembler">cmp</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,$04
</span><span class="pas1-space"> </span><span class="pas1-assembler">jl</span><span class="pas1-space"> </span><span class="pas1-assembler">@Loop
</span><span class="pas1-space"> </span><span class="pas1-comment">// first DWORD
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">2]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-comment">// second DWORD
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">4]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">6]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-comment">// third DWORD
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">8]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">10]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-comment">// fourth DWORD
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">12]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">14]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">edx,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">sub</span><span class="pas1-space"> </span><span class="pas1-assembler">esi,</span><span class="pas1-space"> </span><span class="pas1-assembler">4
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Last3
</span><span class="pas1-space"> </span><span class="pas1-assembler">jmp</span><span class="pas1-space"> </span><span class="pas1-assembler">@LargeLoop
@Loop:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">2]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">edx,</span><span class="pas1-space"> </span><span class="pas1-assembler">4
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jnz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Loop
@Last3:
</span><span class="pas1-space"> </span><span class="pas1-assembler">test</span><span class="pas1-space"> </span><span class="pas1-assembler">edi,</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@OneLeft
</span><span class="pas1-space"> </span><span class="pas1-assembler">dec</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">jz</span><span class="pas1-space"> </span><span class="pas1-assembler">@TwoLeft
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">16
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">movsx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">byte</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx</span><span class="pas1-space"> </span><span class="pas1-assembler">+</span><span class="pas1-space"> </span><span class="pas1-assembler">2]
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">18
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">jmp</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
@TwoLeft:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movzx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">word</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">11
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">17
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">jmp</span><span class="pas1-space"> </span><span class="pas1-assembler">@Done
@OneLeft:
</span><span class="pas1-space"> </span><span class="pas1-assembler">movsx</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">byte</span><span class="pas1-space"> </span><span class="pas1-assembler">ptr</span><span class="pas1-space"> </span><span class="pas1-assembler">[edx]
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">10
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">1
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
@Done:
</span><span class="pas1-space"> </span><span class="pas1-comment">// avalanche
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">3
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">5
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">4
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">17
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shl</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">25
</span><span class="pas1-space"> </span><span class="pas1-assembler">xor</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
</span><span class="pas1-space"> </span><span class="pas1-assembler">mov</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx,</span><span class="pas1-space"> </span><span class="pas1-assembler">eax
</span><span class="pas1-space"> </span><span class="pas1-assembler">shr</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">6
</span><span class="pas1-space"> </span><span class="pas1-assembler">add</span><span class="pas1-space"> </span><span class="pas1-assembler">eax,</span><span class="pas1-space"> </span><span class="pas1-assembler">ecx
@Ret:
</span><span class="pas1-space"> </span><span class="pas1-assembler">pop</span><span class="pas1-space"> </span><span class="pas1-assembler">edi
</span><span class="pas1-space"> </span><span class="pas1-assembler">pop</span><span class="pas1-space"> </span><span class="pas1-assembler">esi
</span><span class="pas1-space"> </span><span class="pas1-assembler">ret
</span><span class="pas1-preprocessor">{$endif}
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">.
</span>
</code></pre>
<p>To use this code you'll only have to download <a class="Delphi File" title="Download the unSuperFashHash file" href="http://davy.landman.googlepages.com/unSuperFastHash.pas" target="_blank">the unit</a> and choose if you want to use the Pascal versions or the Assembly versions. You can switch between this using the <span class="Source">{$define ASMVersion}</span> preprocessor.</p>
<h3>Difference between my version and Paul Hsieh's</h3>
<p>The only difference between my Pascal code and Paul's c code is the pointer mathematics in the core loop. Below is the core loop c code.</p>
<pre class="Source"><code><span class="cpp1-reservedword">for</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(;</span><span class="cpp1-identifier">len</span><span class="cpp1-space"> </span><span class="cpp1-symbol">></span><span class="cpp1-space"> </span><span class="cpp1-number">0</span><span class="cpp1-symbol">;</span><span class="cpp1-space"> </span><span class="cpp1-identifier">len</span><span class="cpp1-symbol">--)</span><span class="cpp1-space"> </span><span class="cpp1-symbol">{
</span><span class="cpp1-space"> </span><span class="cpp1-identifier">hash</span><span class="cpp1-space"> </span><span class="cpp1-symbol">+=</span><span class="cpp1-space"> </span><span class="cpp1-identifier">get16bits</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">data</span><span class="cpp1-symbol">);
</span><span class="cpp1-space"> </span><span class="cpp1-identifier">tmp</span><span class="cpp1-space"> </span><span class="cpp1-symbol">=</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">get16bits</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">data</span><span class="cpp1-symbol">+</span><span class="cpp1-number">2</span><span class="cpp1-symbol">)</span><span class="cpp1-space"> </span><span class="cpp1-symbol"><<</span><span class="cpp1-space"> </span><span class="cpp1-number">11</span><span class="cpp1-symbol">)</span><span class="cpp1-space"> </span><span class="cpp1-symbol">^</span><span class="cpp1-space"> </span><span class="cpp1-identifier">hash</span><span class="cpp1-symbol">;
</span><span class="cpp1-space"> </span><span class="cpp1-identifier">hash</span><span class="cpp1-space"> </span><span class="cpp1-symbol">=</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">hash</span><span class="cpp1-space"> </span><span class="cpp1-symbol"><<</span><span class="cpp1-space"> </span><span class="cpp1-number">16</span><span class="cpp1-symbol">)</span><span class="cpp1-space"> </span><span class="cpp1-symbol">^</span><span class="cpp1-space"> </span><span class="cpp1-identifier">tmp</span><span class="cpp1-symbol">;
</span><span class="cpp1-space"> </span><span class="cpp1-identifier">data</span><span class="cpp1-space"> </span><span class="cpp1-symbol">+=</span><span class="cpp1-space"> </span><span class="cpp1-number">2</span><span class="cpp1-symbol">*</span><span class="cpp1-reservedword">sizeof</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">uint16_t</span><span class="cpp1-symbol">);
</span><span class="cpp1-space"> </span><span class="cpp1-identifier">hash</span><span class="cpp1-space"> </span><span class="cpp1-symbol">+=</span><span class="cpp1-space"> </span><span class="cpp1-identifier">hash</span><span class="cpp1-space"> </span><span class="cpp1-symbol">>></span><span class="cpp1-space"> </span><span class="cpp1-number">11</span><span class="cpp1-symbol">;
}</span>
</code></pre>
<p>And this is my Pascal version of this code.</p>
<pre class="Source"><code><span class="pas1-reservedword">while</span><span class="pas1-space"> RemainingDWords </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
begin
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^;
</span><span class="pas1-space"> </span><span class="pas1-comment">// splitting the pointer math keeps the amount of registers pushed at 2
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> TempPart </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">PWord</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)^</span><span class="pas1-space"> </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> Result</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shl</span><span class="pas1-space"> </span><span class="pas1-number">16</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">xor</span><span class="pas1-space"> TempPart</span><span class="pas1-symbol">;
</span><span class="pas1-space"> AData </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Cardinal</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AData</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">+</span><span class="pas1-space"> SizeOf</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Word</span><span class="pas1-symbol">));
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Result </span><span class="pas1-symbol">+</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Result </span><span class="pas1-reservedword">shr</span><span class="pas1-space"> </span><span class="pas1-number">11</span><span class="pas1-symbol">);
</span><span class="pas1-space"> dec</span><span class="pas1-symbol">(</span><span class="pas1-identifier">RemainingDWords</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;</span>
</code></pre>
<p>Paul's code increments the pointer at the end <span class="Source"><span class="cpp1-identifier">data</span><span class="cpp1-space"> </span><span class="cpp1-symbol">+=</span><span class="cpp1-space"> </span><span class="cpp1-number">2</span><span class="cpp1-symbol">*</span><span class="cpp1-reservedword">sizeof</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">uint16_t</span><span class="cpp1-symbol">);</span></span>, and uses <span class="Source"><span class="cpp1-identifier">get16bits</span><span class="cpp1-space"> </span><span class="cpp1-symbol">(</span><span class="cpp1-identifier">data</span><span class="cpp1-symbol">+</span><span class="cpp1-number">2</span><span class="cpp1-symbol">)</span></span> to get to the second Word while mine increases the data pointer in between, because the Delphi Compiler will not compile <span class="Source">PWord(Pointer(Cardinal(AData)+2))^</span> into <span class="Source"><span class="mygeneral1-keywords1">movzx</span><span class="mygeneral1-space"> </span><span class="mygeneral1-keywords2">ecx</span><span class="mygeneral1-symbol">,</span><span class="mygeneral1-space"> </span><span class="mygeneral1-keywords3">word</span><span class="mygeneral1-space"> </span><span class="mygeneral1-keywords3">ptr</span><span class="mygeneral1-space"> </span><span class="mygeneral1-symbol">[</span><span class="mygeneral1-keywords2">edx</span><span class="mygeneral1-space"> </span><span class="mygeneral1-symbol">+</span><span class="mygeneral1-space"> </span><span class="mygeneral1-number">2</span><span class="mygeneral1-symbol">]</span></span> but will store the intermediate pointer in a extra register which causes performance loss.</p>
<p>The funny thing is, although I tried a lot of different ways to get a better performance I ended up with an implementation almost identical to Paul's. I hadn't found the assembly version he created until after I wrote my own, and I think it's nice to see that apart from the initialization and the case statement they are the same.</p>
<p>Next time I will post my benchmarking code. Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com11tag:blogger.com,1999:blog-3108828885823618940.post-17236496977180422652008-07-09T21:56:00.002+02:002009-01-21T23:07:28.683+01:00My new blogThree years back I created a blog with the idea to post my Delphi snippets on that blog for future reference. But the problem as usual, so many ideas, so little time. It also didn't help that I switched to C# about 1 and a half year ago. I still use Delphi sometimes, but not for my regular work.</p> <p>In my work I've learned a lot about C# and web development (ASP.NET) and it gave me a few ideas to publish about, but the problem was, my blog was called <strong>Delphi</strong> Snippets. So I came up with the *very* original name "Landman Code". </p> <h3>Design</h3> <p>Big difference from the first time was that now I understand html and css enough to make a nice website myself (instead of using a blogspot template). Naturally Because I'm Dutch I wanted a free hosting solution, so I stayed with the nice Google Service called Blogger (or Blogspot?).</p> <p>I started my first design for my blog in Paint.NET. After I got a general idea of what I wanted I started with a basic HTML frame. Being a programmer I like the idea of the separation of content (HTML) and layout (CSS) and I created in my opinion a very clean html template. I always aim to support IE6+ and FF2+ when creating a new website, and off course IE6 got most of my attention. The aim was to have a fluid layout (but with a max width) and also have the layout shape according to the text size instead of a fixed pixel size (apparently called an elastic layout).</p> <h3>Blogspot Template</h3> <p>After I finished my HTML template I started searching for an explanation about the XML templates from blogspot. The furthest I got was the <a title="BlogSpot Help: Layouts Data Tags" href="http://help.blogger.com/bin/answer.py?answer=47270" target="_blank">help from blogger itself</a>.  So "developing" my XML template got a little bit of a drag, and without even an XSD to validate the XML the project had a rest period of about a month. </p> <p>My new method was to find a reasonably clean template and "learn & copy" from that template to create my own template. I found that in the <a href="http://www.blogspottemplate.com/new-blogger-template/nyoba-780.html" target="_blank">Nyoba 780</a> template. It was clean enough to understand how it worked and after a few evenings I finished my first blogspot template, so thanks for the inspiration <a href="http://www.isnaini.com">Isnaini Dot Com </a>.</p> <h3>Special features</h3> <p>I'm always proud of my work, and I try to learn every time a do a project. For this project I really wanted to dive deep into css and html. Here is a list of the thing's I'm particularly proud of.</p> <ul> <li>Using only 1 CSS hack (max-width IE6). </li> <li>Using valid HTML (the Blogspot navbar breaks everything). </li> <li>Round corner's using just a little bit extra html markup, I preferred the extra markup to the javascript solutions. </li> <li>Using png images with an alpha channel in an css background property and getting them to not be ugly in IE6 without using any hacks or filters. (TweakPNG to the rescue) </li> <li>Using my own basil plantage for the header image. </li> <li>The semi transparant box behind the title. </li> <li>Good usage of html tags (see the structure in FireBug) </li> </ul> <h3>Old Blog</h3> <p>I transferred the posts from my old blog to this blog at first for testing my template but also because I still like the idea of the old blog and want to keep my snippets in this blog.</p> <p> </p> <p>So I hope you'll like the content (and design) of the blog.</p> <p>Kind regards, <br />Davy Landman</p> <p><small>ps. I recommend using ClearType (or Font Smoothing) for reading this blog, normally I wouldn't choose fonts which assume ClearTyping enabled, but because the intended audience are developers I assume you're using the features your Operating System offers you.</small> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0tag:blogger.com,1999:blog-3108828885823618940.post-49348887448957754772008-06-17T21:46:00.001+02:002008-06-17T21:48:39.915+02:00Welcome to my blogHello,
<p>My name is Davy Landman and I'm a developer.</p>
<p>While working I develop mainly in ASP.NET and Winforms using the C# language, while sometimes developing Win32 applications in Delphi.</p>
<p>When not working and coding the utilities the inner geek wants, I use a mix of C#, Delphi, BASM and Matlab.
</p>
<p>In this blog I post about some interesting code I found or created, mainly sharing it for reference later and anyone else who would like it.<p>
<p>
Have fun.
</p>Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0tag:blogger.com,1999:blog-3108828885823618940.post-55079717410491395242007-01-28T12:07:00.005+01:002008-07-16T20:43:28.041+02:00Thread safe TStack (TThreadStack)<span class="Notice">This post was migrated from <a href="http://delphi-snippets.blogspot.com/2007/01/thread-safe-tstack-tthreadstack.html" rel="nofollow">my old blog delphi-snippets.blogspot.com</a>, for explanation about this switch see <a href="http://landman-code.blogspot.com/2008/07/my-new-blog.html" rel="nofollow">my introduction post</a>.</span> <p>Recently i've been doing a lot of multithreading, and luckily Delphi provides with a handy bunch of classes to make the developers life easier. You've got some basic synchronization classes (TMutex, TEvent, TCriticalSection, TMultiReadExclusiveWriteSynchronizer...) and an basic data container (TThreadList). But for one program I needed a thread safe stack. In this post I will describe how I created my own. </p><p>There is not thread safe stack in Borland Turbo Delphi 2006, so off course I started with a Google for <a title="delphi TThreadStack" href="http://www.google.nl/search?q=delphi+TThreadStack">delphi TThreadStack</a>, which at this time gives zero results. Searching the newsgroups I found an interesting group called <a title="comp.programming.threads" href="http://groups.google.com/group/comp.programming.threads" target="blank_">comp.programming.threads</a>, searching that group I found one Pascal <a title="Lock-Free" href="http://en.wikipedia.org/wiki/Lock-free_and_wait-free_algorithms" target="blank_">Lock-Free</a> stack (which basically means not using a critical section, or any other mechanism, to lock the data). But after testing it, FastMM pointed out an memory leak. I provided the author with a test case to cause the memory leak, but after 5 months no reply. </p><p>But I'm a hard person to please, and although it is indeed lock free, I was wondering if in my situation this lock-free solution wasn't to complicated and perhaps slower. So I created an simple TThreadStack from looking at the principle of the TThreadList (Very simple!), and compared it with the lock-free solution. </p><p>The source demonstrates is the test project. </p>
<pre class="Source Boxed"><code><span style="FONT: 10pt Courier New"><span class="pas1-reservedword">program</span><span class="pas1-space"> Project2</span><span class="pas1-symbol">;
</span><span class="pas1-preprocessor">{$APPTYPE CONSOLE}
</span><span class="pas1-reservedword">uses
</span><span class="pas1-space"> FastMM4</span><span class="pas1-symbol">,
</span><span class="pas1-space"> unThreadStack</span><span class="pas1-symbol">,
</span><span class="pas1-space"> FreeStack</span><span class="pas1-symbol">,</span><span class="pas1-space"> Math</span><span class="pas1-symbol">,
</span><span class="pas1-space"> Windows</span><span class="pas1-symbol">,</span><span class="pas1-space"> SysUtils</span><span class="pas1-symbol">,</span><span class="pas1-space"> Classes</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">const
</span><span class="pas1-space"> NumberOfAllocations </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1000</span><span class="pas1-symbol">;
</span><span class="pas1-space"> PopTimeOut </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">;
</span><span class="pas1-space"> PushTimeOut </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">;
</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">8</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-comment">// must be an multiple of 4
</span><span class="pas1-space"> NumberOfTest </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">10</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">type
</span><span class="pas1-space"> TTestRec </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">packed</span><span class="pas1-space"> </span><span class="pas1-reservedword">record
</span><span class="pas1-space"> BigField</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-number">254</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> Char</span><span class="pas1-symbol">;
</span><span class="pas1-space"> SmallerField</span><span class="pas1-symbol">:</span><span class="pas1-space"> Extended</span><span class="pas1-symbol">;
</span><span class="pas1-space"> SmallField</span><span class="pas1-symbol">:</span><span class="pas1-space"> Byte</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> PTestRec </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-symbol">^</span><span class="pas1-identifier">TTestRec</span><span class="pas1-symbol">;
</span><span class="pas1-space"> TFreeStackThread </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">class</span><span class="pas1-symbol">(</span><span class="pas1-identifier">TThread</span><span class="pas1-symbol">)
</span><span class="pas1-space"> FPopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">protected
</span><span class="pas1-space"> </span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> Execute</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-reservedword">override</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">public
</span><span class="pas1-space"> </span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">;</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> TThreadStackThread </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">class</span><span class="pas1-symbol">(</span><span class="pas1-identifier">TThread</span><span class="pas1-symbol">)
</span><span class="pas1-space"> FPopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">protected
</span><span class="pas1-space"> </span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> Execute</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-reservedword">override</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">public
</span><span class="pas1-space"> </span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">;</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">{ TThreadStackThread }
</span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> TThreadStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> FDestination </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADestination</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FPopper </span><span class="pas1-symbol">:=</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FFinished </span><span class="pas1-symbol">:=</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">inherited</span><span class="pas1-space"> Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">False</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> TThreadStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Execute</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> TempStack</span><span class="pas1-symbol">:</span><span class="pas1-space"> TStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> p</span><span class="pas1-symbol">:</span><span class="pas1-space"> PTestRec</span><span class="pas1-symbol">;
</span><span class="pas1-space"> counter</span><span class="pas1-symbol">:</span><span class="pas1-space"> Int64</span><span class="pas1-symbol">;
</span><span class="pas1-space"> temp</span><span class="pas1-symbol">:</span><span class="pas1-space"> LongWord</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> counter </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-reservedword">not</span><span class="pas1-space"> Terminated</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">and</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter </span><span class="pas1-symbol"><</span><span class="pas1-space"> NumberOfAllocations</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> TempStack </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">.</span><span class="pas1-identifier">LockStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">try
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FPopper </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> TempStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Count </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Dispose</span><span class="pas1-symbol">(</span><span class="pas1-identifier">PTestRec</span><span class="pas1-symbol">(</span><span class="pas1-identifier">TempStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Pop</span><span class="pas1-symbol">));
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> New</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">);
</span><span class="pas1-space"> TempStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Push</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">finally
</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">.</span><span class="pas1-identifier">UnlockStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FPopper </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> Sleep</span><span class="pas1-symbol">(</span><span class="pas1-identifier">PopTimeOut</span><span class="pas1-symbol">)
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else
</span><span class="pas1-space"> Sleep</span><span class="pas1-symbol">(</span><span class="pas1-identifier">PushTimeOut</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ReleaseSemaphore</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FFinished</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">@</span><span class="pas1-identifier">temp</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-comment">{ TFreeStackThread }
</span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> TFreeStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ADestination</span><span class="pas1-symbol">:</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">;</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">:</span><span class="pas1-space"> Boolean</span><span class="pas1-symbol">;</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> FDestination </span><span class="pas1-symbol">:=</span><span class="pas1-space"> ADestination</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FPopper </span><span class="pas1-symbol">:=</span><span class="pas1-space"> APopper</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FFinished </span><span class="pas1-symbol">:=</span><span class="pas1-space"> AFinished</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">inherited</span><span class="pas1-space"> Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">False</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> TFreeStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Execute</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> p</span><span class="pas1-symbol">:</span><span class="pas1-space"> PTestRec</span><span class="pas1-symbol">;
</span><span class="pas1-space"> counter</span><span class="pas1-symbol">:</span><span class="pas1-space"> Int64</span><span class="pas1-symbol">;
</span><span class="pas1-space"> temp</span><span class="pas1-symbol">:</span><span class="pas1-space"> LongWord</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> counter </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">;
</span><span class="pas1-space"> p </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-reservedword">nil</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">while</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-reservedword">not</span><span class="pas1-space"> Terminated</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">and</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter </span><span class="pas1-symbol"><</span><span class="pas1-space"> NumberOfAllocations</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FPopper </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Count </span><span class="pas1-symbol">></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Pop</span><span class="pas1-symbol">(</span><span class="pas1-identifier">TObject</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">))</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> Dispose</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">);
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> p </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">nil</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> New</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FDestination</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Push</span><span class="pas1-symbol">(</span><span class="pas1-identifier">TObject</span><span class="pas1-symbol">(</span><span class="pas1-identifier">p</span><span class="pas1-symbol">))</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> p </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-reservedword">nil</span><span class="pas1-symbol">;
</span><span class="pas1-space"> inc</span><span class="pas1-symbol">(</span><span class="pas1-identifier">counter</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> FPopper </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> Sleep</span><span class="pas1-symbol">(</span><span class="pas1-identifier">PopTimeOut</span><span class="pas1-symbol">)
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else
</span><span class="pas1-space"> Sleep</span><span class="pas1-symbol">(</span><span class="pas1-identifier">PushTimeOut</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ReleaseSemaphore</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FFinished</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">@</span><span class="pas1-identifier">temp</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">var
</span><span class="pas1-space"> AThreadStacksTests</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-identifier">NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> TThreadStackThread</span><span class="pas1-symbol">;
</span><span class="pas1-space"> AFreeStacksTests</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-identifier">NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> TFreeStackThread</span><span class="pas1-symbol">;
</span><span class="pas1-space"> i</span><span class="pas1-symbol">,</span><span class="pas1-space"> j</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Start</span><span class="pas1-symbol">,</span><span class="pas1-space"> Stop</span><span class="pas1-symbol">,</span><span class="pas1-space"> Freq</span><span class="pas1-symbol">:</span><span class="pas1-space"> Int64</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ThreadStacks</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FreeStacks</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ResultThread</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-identifier">NumberOfTest </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> Double</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ResultFree</span><span class="pas1-symbol">:</span><span class="pas1-space"> </span><span class="pas1-reservedword">array</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">..</span><span class="pas1-identifier">NumberOfTest </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-reservedword">of</span><span class="pas1-space"> Double</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Finished</span><span class="pas1-symbol">:</span><span class="pas1-space"> THandle</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Mean</span><span class="pas1-symbol">,</span><span class="pas1-space"> StdDev</span><span class="pas1-symbol">:</span><span class="pas1-space"> Extended</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> ThreadStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ThreadStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FreeStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FreeStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">1</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TFreeStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Finished </span><span class="pas1-symbol">:=</span><span class="pas1-space"> CreateSemaphore</span><span class="pas1-symbol">(</span><span class="pas1-reservedword">nil</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-symbol">,</span><span class="pas1-space"> NumberOfThreads</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-string">'Thread runners'</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Starting ThreadStack threads'</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> j </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfTest </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> AThreadStacksTests</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TThreadStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ThreadStacks</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i </span><span class="pas1-reservedword">mod</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">],</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">i </span><span class="pas1-reservedword">mod</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">>=</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">,</span><span class="pas1-space"> Finished</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> WaitForSingleObject</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Finished</span><span class="pas1-symbol">,</span><span class="pas1-space"> INFINITE</span><span class="pas1-symbol">);
</span><span class="pas1-space"> QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> AThreadStacksTests</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ResultThread</span><span class="pas1-symbol">[</span><span class="pas1-identifier">j</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Stop </span><span class="pas1-symbol">-</span><span class="pas1-space"> Start</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'ThreadStack done.'</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Starting TFreeStack threads'</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> j </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfTest </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> AFreeStacksTests</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> TFreeStackThread</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FreeStacks</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i </span><span class="pas1-reservedword">mod</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">],</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">i </span><span class="pas1-reservedword">mod</span><span class="pas1-space"> </span><span class="pas1-number">4</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">>=</span><span class="pas1-space"> </span><span class="pas1-number">2</span><span class="pas1-symbol">,</span><span class="pas1-space"> Finished</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> WaitForSingleObject</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Finished</span><span class="pas1-symbol">,</span><span class="pas1-space"> INFINITE</span><span class="pas1-symbol">);
</span><span class="pas1-space"> QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">for</span><span class="pas1-space"> I </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> NumberOfThreads </span><span class="pas1-symbol">-</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> AFreeStacksTests</span><span class="pas1-symbol">[</span><span class="pas1-identifier">i</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ResultFree</span><span class="pas1-symbol">[</span><span class="pas1-identifier">j</span><span class="pas1-symbol">]</span><span class="pas1-space"> </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Stop </span><span class="pas1-symbol">-</span><span class="pas1-space"> Start</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'TFreeStack done.'</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'Calculating the mean and the standard deviation out of %d runs.'</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">[</span><span class="pas1-identifier">NumberOfTest</span><span class="pas1-symbol">]));
</span><span class="pas1-space"> QueryPerformanceFrequency</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Freq</span><span class="pas1-symbol">);
</span><span class="pas1-space"> MeanAndStdDev</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ResultThread</span><span class="pas1-symbol">,</span><span class="pas1-space"> Mean</span><span class="pas1-symbol">,</span><span class="pas1-space"> StdDev</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'TThreadStack: %f (%f)'</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">[</span><span class="pas1-identifier">Mean</span><span class="pas1-symbol">,</span><span class="pas1-space"> StdDev</span><span class="pas1-symbol">]));
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'TThreadStack: %fms (%fms)'</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">[</span><span class="pas1-identifier">Mean </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Freq </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">1000</span><span class="pas1-symbol">),</span><span class="pas1-space"> StdDev </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Freq </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">1000</span><span class="pas1-symbol">)]));
</span><span class="pas1-space"> MeanAndStdDev</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ResultFree</span><span class="pas1-symbol">,</span><span class="pas1-space"> Mean</span><span class="pas1-symbol">,</span><span class="pas1-space"> StdDev</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'TFreeStack: %f (%f)'</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">[</span><span class="pas1-identifier">Mean</span><span class="pas1-symbol">,</span><span class="pas1-space"> StdDev</span><span class="pas1-symbol">]));
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'TFreeStack: %fms (%fms)'</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">[</span><span class="pas1-identifier">Mean </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Freq </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">1000</span><span class="pas1-symbol">),</span><span class="pas1-space"> StdDev </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Freq </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">1000</span><span class="pas1-symbol">)]));
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> DebugHook </span><span class="pas1-symbol"><></span><span class="pas1-space"> </span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">then
</span><span class="pas1-space"> Readln</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-comment">{ freeing everything}
</span><span class="pas1-space"> ThreadStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> ThreadStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">1</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FreeStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">0</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FreeStacks</span><span class="pas1-symbol">[</span><span class="pas1-number">1</span><span class="pas1-symbol">].</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> CloseHandle</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Finished</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">.
</span></span>
</code></pre>
<p>This one also creates the memory leak. Running the code on a P4 2.26 returns this result: </p><blockquote class="Console">Starting ThreadStack threads<br />
ThreadStack done.<br />
Starting TFreeStack threads<br />
TFreeStack done.<br />
Calculating the mean and the standard deviation out of 10 runs.<br />
TThreadStack: 7152374,20 (26574,65)<br />
TThreadStack: 1998,12ms (7,42ms)<br />
TFreeStack: 7339945,80 (310570,01)<br />
TFreeStack: 2050,52ms (86,76ms)</blockquote><p>So the TFreestack is all most the same speed as the simple critical section based TThreadStack, although I know now the test isn't what you'd call regular, because it's constantly trying to push and pop. So perhaps a more normal situation would result differently. But in my program this situation was expected. </p><p>I also liked the simplicity of the TThreadStack above the complexity of the FreeStack, were you had to compile a piece TASM (containing the CAS) for it to work. Another show stopper was the memory leak. But actually I just wanted to post my simple TThreadStack so that next time I have to use it, I can just wander to my own blog. So without further ado, I bring you the following source. </p>
<pre class="Source Boxed"><code><span style="FONT: 10pt Courier New"><span class="pas1-reservedword">unit</span><span class="pas1-space"> unThreadStack</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">interface
uses
</span><span class="pas1-space"> Windows</span><span class="pas1-symbol">,</span><span class="pas1-space"> Contnrs</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">type
</span><span class="pas1-space"> TStack </span><span class="pas1-symbol">=</span><span class="pas1-space"> Contnrs</span><span class="pas1-symbol">.</span><span class="pas1-identifier">TStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> TThreadStack </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">class
</span><span class="pas1-space"> </span><span class="pas1-reservedword">private
</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">:</span><span class="pas1-space"> TStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> FLock </span><span class="pas1-symbol">:</span><span class="pas1-identifier">TRTLCriticalSection</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">public
</span><span class="pas1-space"> </span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> Create</span><span class="pas1-symbol">();
</span><span class="pas1-space"> </span><span class="pas1-reservedword">destructor</span><span class="pas1-space"> Destroy</span><span class="pas1-symbol">;</span><span class="pas1-space"> </span><span class="pas1-reservedword">override</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">function</span><span class="pas1-space"> LockStack </span><span class="pas1-symbol">:</span><span class="pas1-space"> TStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> UnlockStack</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">function</span><span class="pas1-space"> Count</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">function</span><span class="pas1-space"> Push</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AItem</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">function</span><span class="pas1-space"> Pop</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">function</span><span class="pas1-space"> Peek</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">implementation
</span><span class="pas1-comment">{ TThreadStack }
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">LockStack</span><span class="pas1-symbol">:</span><span class="pas1-space"> TStack</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> EnterCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Count</span><span class="pas1-symbol">:</span><span class="pas1-space"> Integer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> EnterCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">try
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Count</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">finally
</span><span class="pas1-space"> LeaveCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">constructor</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">();
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> </span><span class="pas1-reservedword">inherited</span><span class="pas1-space"> Create</span><span class="pas1-symbol">();
</span><span class="pas1-space"> InitializeCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> FStack </span><span class="pas1-symbol">:=</span><span class="pas1-space"> Contnrs</span><span class="pas1-symbol">.</span><span class="pas1-identifier">TStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Create</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">destructor</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Destroy</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> DeleteCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Free</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">inherited</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Peek</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> EnterCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">try
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Peek</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">finally
</span><span class="pas1-space"> LeaveCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Pop</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> EnterCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">try
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Pop</span><span class="pas1-symbol">;
</span><span class="pas1-space"> </span><span class="pas1-reservedword">finally
</span><span class="pas1-space"> LeaveCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">function</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Push</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AItem</span><span class="pas1-symbol">:</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">):</span><span class="pas1-space"> Pointer</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> EnterCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">try
</span><span class="pas1-space"> Result </span><span class="pas1-symbol">:=</span><span class="pas1-space"> FStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">Push</span><span class="pas1-symbol">(</span><span class="pas1-identifier">AItem</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">finally
</span><span class="pas1-space"> LeaveCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">procedure</span><span class="pas1-space"> TThreadStack</span><span class="pas1-symbol">.</span><span class="pas1-identifier">UnlockStack</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">begin
</span><span class="pas1-space"> LeaveCriticalSection</span><span class="pas1-symbol">(</span><span class="pas1-identifier">FLock</span><span class="pas1-symbol">);
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">;
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">.
</span></span>
</code></pre>
<p>If you use this source, I would like it if you just left a comment on this blog. </p> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com3tag:blogger.com,1999:blog-3108828885823618940.post-28207447954143832642006-04-21T11:51:00.003+02:002008-07-15T19:09:22.385+02:00Fast reading of files using Memory Mapping<span class="Notice">This post was migrated from <a href="http://delphi-snippets.blogspot.com/2005/08/automatic-cropping-of-bitmap_18.html" rel="nofollow">my old blog delphi-snippets.blogspot.com</a>, for explanation about this switch see <a href="http://landman-code.blogspot.com/2008/07/my-new-blog.html" rel="nofollow">my introduction post</a>.</span> It has been six months since I last posted something. Lets just say things got a little busy :). And posting source code on Blogspot seemed to be a bitch because blogspot would filter out the enters. I solved that in the previous post by using an <br /> as an enter. But when copying and pasting from the page the newlines were lost (offcourse <a href="http://www.dow.wau.nl/aew/DelForExp.html">DelForExp</a> fixes that.. but still it sucked). <p></p> <p>Now I have just a little bit of time, and a few articles I wanted to post. So after some testing I found out blogspot fixed the enter removal and now I’ll try to post more frequently.</p> <p>Now let’s get ontopic, <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dngenlib/html/msdn_manamemo.asp">Memory Mapped Files</a> can be very helpful for reading large files. Looking through the internet you can find many advantages and disadvantages. The important thing is, think about what your doing, MMF can be very fast in one application. But slow in an other, it all depends on the situation, there are enough articles about the subject (for instance <a href="http://blogs.borland.com/dcc/archive/2004/03/19/2380.aspx">this</a> one by the Delphi Compiler Team)</p> <p>I like MMF a lot when using binary files of a certain format. Let’s assume we have the following file format:</p> <pre class='Source'><code><span style='font: 10pt courier new'><span class='pas1-identifier'>TCustomerStruct = </span><span class='pas1-reservedword'>packed</span><span class='pas1-space'> </span><span class='pas1-reservedword'>record
</span><span class='pas1-space'> CustomerID: Longword;
CustomerName: </span><span class='pas1-reservedword'>array</span><span class='pas1-symbol'>[</span><span class='pas1-number'>0</span><span class='pas1-symbol'>..</span><span class='pas1-number'>254</span><span class='pas1-symbol'>] </span><span class='pas1-reservedword'>of</span><span class='pas1-space'> Char;
CustomerBirthDay: TDateTime;
CustomerRate: Double;
AccountManagerID: Longword;
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span></span></code></pre>
<p>You could read this using BlockRead:</p>
<pre class='Source Boxed' style='height: 22em'><code><span class='pas1-reservedword'>var
</span><span class='pas1-space'> CustomerFile: </span><span class='pas1-reservedword'>file</span><span class='pas1-space'> </span><span class='pas1-reservedword'>of</span><span class='pas1-space'> TCustomerStruct;
Customers: </span><span class='pas1-reservedword'>array</span><span class='pas1-space'> </span><span class='pas1-reservedword'>of</span><span class='pas1-space'> TCustomerStruct;
i : integer;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> AssignFile(CustomerFile,</span><span class='pas1-string'>'c:\customers.cus'</span><span class='pas1-symbol'>);
</span><span class='pas1-reservedword'>try
</span><span class='pas1-space'> Reset(CustomerFile); </span><span class='pas1-comment'>// open the file for reading
</span><span class='pas1-space'> SetLength(Customers, FileSize(CustomerFile)); </span><span class='pas1-comment'>// create the array
</span><span class='pas1-space'> BlockRead(CustomerFile, Customers, Length(Customers)); </span><span class='pas1-comment'>// Read the hole party in to the array
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i := </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> High(Customers) </span><span class='pas1-reservedword'>do
</span><span class='pas1-space'> </span><span class='pas1-comment'>// List all the customers in a memo
</span><span class='pas1-space'> memCustomerList.Lines.Add(</span><span class='pas1-string'>'Name: '</span><span class='pas1-symbol'>+ Customers[i].CustomerName);
</span><span class='pas1-reservedword'>finally
</span><span class='pas1-space'> CloseFile(CustomerFile);
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span></code></pre>
<p>And now using MemoryMapping:</p>
<pre class='Source Boxed' style='height: 23em'><code><span class='pas1-reservedword'>type</span>
<span class='pas1-space'> TCustomerStructArray = </span><span class='pas1-reservedword'>array</span><span class='pas1-symbol'>[</span><span class='pas1-number'>0</span><span class='pas1-symbol'>..MaxInt </span><span class='pas1-reservedword'>div</span><span class='pas1-space'> SizeOf(TCustomerStruct) - </span><span class='pas1-number'>1</span><span class='pas1-symbol'>] </span><span class='pas1-reservedword'>of</span><span class='pas1-space'> TCustomerStruct;
PCustomerStructArray = ^TCustomerStructArray;
</span><span class='pas1-reservedword'>var
</span><span class='pas1-space'> CustomerFile : TMappedFile;
Customers: PCustomerStructArray;
i : integer;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> CustomerFile := TMappedFile.Create;
</span><span class='pas1-reservedword'>try
</span><span class='pas1-space'> CustomerFile.MapFile(</span><span class='pas1-string'>'c:\customers.cus'</span><span class='pas1-symbol'>);
Customers := PCustomerStructArray(CustomerFile.Content); </span><span class='pas1-comment'>// not needed, but handy
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i := </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> CustomerFile.Size </span><span class='pas1-reservedword'>div</span><span class='pas1-space'> SizeOf(TCustomerStruct) -</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do
</span><span class='pas1-space'> memCustomerList.Lines.Add(</span><span class='pas1-string'>'Name: '</span><span class='pas1-symbol'>+ Customers[i].CustomerName);
</span><span class='pas1-reservedword'>finally
</span><span class='pas1-space'> CustomerFile.Free;
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span></code></pre>
<p>The <span style='font: 10pt courier new'><span class='pas1-symbol'>MaxInt </span><span class='pas1-reservedword'>div</span><span class='pas1-space'> SizeOf(TCustomerStruct) – </span><span class='pas1-number'>1</span></span> is the maximum amount of records (thus memory) loaded at once.</p>
<p>The TMappedFile class is something I created myself so I can be lazy. Off course I will share that piece of code too.</p>
<pre class='Source Boxed'><code>
<span class='pas1-reservedword'>unit</span><span class='pas1-space'> unFileMapping</span><span class='pas1-symbol'>;
</span><span class='pas1-comment'>{
Copyright (c) 2005-2006 by Davy Landman
See the file COPYING.FPC, included in this distribution,
for details about the copyright. Alternately, you may use this source under the provisions of MPL v1.x or later
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
</span><span class='pas1-reservedword'>interface
uses
</span><span class='pas1-space'> Windows</span><span class='pas1-symbol'>,</span><span class='pas1-space'> SysUtils</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>type
</span><span class='pas1-space'> TMappedFile </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-reservedword'>class
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>private
</span><span class='pas1-space'> FMapping</span><span class='pas1-symbol'>:</span><span class='pas1-space'> THandle</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> FContent</span><span class='pas1-symbol'>:</span><span class='pas1-space'> Pointer</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> FSize</span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> MapFile</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> AFileName</span><span class='pas1-symbol'>:</span><span class='pas1-space'> WideString</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>public
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>constructor</span><span class='pas1-space'> Create</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> AFileName</span><span class='pas1-symbol'>:</span><span class='pas1-space'> WideString</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>destructor</span><span class='pas1-space'> Destroy</span><span class='pas1-symbol'>;</span><span class='pas1-space'> </span><span class='pas1-reservedword'>override</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>property</span><span class='pas1-space'> Content</span><span class='pas1-symbol'>:</span><span class='pas1-space'> Pointer </span><span class='pas1-reservedword'>read</span><span class='pas1-space'> FContent</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>property</span><span class='pas1-space'> Size</span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer </span><span class='pas1-reservedword'>read</span><span class='pas1-space'> FSize</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>implementation
function</span><span class='pas1-space'> FileExistsLongFileNames</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> FileName</span><span class='pas1-symbol'>:</span><span class='pas1-space'> WideString</span><span class='pas1-symbol'>):</span><span class='pas1-space'> Boolean</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> Length</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FileName</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-symbol'><</span><span class='pas1-space'> </span><span class='pas1-number'>2</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> Result </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> False</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> Exit</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> CompareMem</span><span class='pas1-symbol'>(@</span><span class='pas1-identifier'>FileName</span><span class='pas1-symbol'>[</span><span class='pas1-number'>1</span><span class='pas1-symbol'>],</span><span class='pas1-space'> </span><span class='pas1-symbol'>@WideString(</span><span class='pas1-string'>'\\')</span><span class='pas1-symbol'>[</span><span class='pas1-number'>1</span><span class='pas1-symbol'>],</span><span class='pas1-space'> </span><span class='pas1-number'>2</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> Result </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>GetFileAttributesW</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>PWideChar</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FileName</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>and</span><span class='pas1-space'> FILE_ATTRIBUTE_DIRECTORY </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>)
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>else
</span><span class='pas1-space'> Result </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>GetFileAttributesW</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>PWideChar</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>WideString</span><span class='pas1-symbol'>(</span><span class='pas1-string'>'\\?\'</span><span class='pas1-space'> </span><span class='pas1-symbol'>+</span><span class='pas1-space'> FileName</span><span class='pas1-symbol'>)))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>and</span><span class='pas1-space'> FILE_ATTRIBUTE_DIRECTORY </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>)
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-comment'>{ TMappedFile }
</span><span class='pas1-reservedword'>constructor</span><span class='pas1-space'> TMappedFile</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> AFileName</span><span class='pas1-symbol'>:</span><span class='pas1-space'> WideString</span><span class='pas1-symbol'>);
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>inherited</span><span class='pas1-space'> Create</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> FileExistsLongFileNames</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>AFileName</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> MapFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>AFileName</span><span class='pas1-symbol'>)
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>else
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>raise</span><span class='pas1-space'> Exception</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>(</span><span class='pas1-string'>'File "'</span><span class='pas1-space'> </span><span class='pas1-symbol'>+</span><span class='pas1-space'> AFileName </span><span class='pas1-symbol'>+</span><span class='pas1-space'> </span><span class='pas1-string'>'" does not exists.'</span><span class='pas1-symbol'>);
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>destructor</span><span class='pas1-space'> TMappedFile</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Destroy</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> Assigned</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FContent</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> UnmapViewOfFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FContent</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> CloseHandle</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FMapping</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>inherited</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> TMappedFile</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>MapFile</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> AFileName</span><span class='pas1-symbol'>:</span><span class='pas1-space'> WideString</span><span class='pas1-symbol'>);
</span><span class='pas1-reservedword'>var
</span><span class='pas1-space'> FileHandle</span><span class='pas1-symbol'>:</span><span class='pas1-space'> THandle</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> CompareMem</span><span class='pas1-symbol'>(@(</span><span class='pas1-identifier'>AFileName</span><span class='pas1-symbol'>[</span><span class='pas1-number'>1</span><span class='pas1-symbol'>]),</span><span class='pas1-space'> </span><span class='pas1-symbol'>@(</span><span class='pas1-string'>'\\'</span><span class='pas1-symbol'>[</span><span class='pas1-number'>1</span><span class='pas1-symbol'>]),</span><span class='pas1-space'> </span><span class='pas1-number'>2</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> </span><span class='pas1-comment'>{ Allready an UNC path }
</span><span class='pas1-space'> FileHandle </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> CreateFileW</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>PWideChar</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>AFileName</span><span class='pas1-symbol'>),</span><span class='pas1-space'> GENERIC_READ</span><span class='pas1-symbol'>,</span><span class='pas1-space'> FILE_SHARE_READ </span><span class='pas1-reservedword'>or
</span><span class='pas1-space'> FILE_SHARE_WRITE</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OPEN_EXISTING</span><span class='pas1-symbol'>,</span><span class='pas1-space'> FILE_ATTRIBUTE_NORMAL</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>)
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>else
</span><span class='pas1-space'> FileHandle </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> CreateFileW</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>PWideChar</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>WideString</span><span class='pas1-symbol'>(</span><span class='pas1-string'>'\\?\'</span><span class='pas1-space'> </span><span class='pas1-symbol'>+</span><span class='pas1-space'> AFileName</span><span class='pas1-symbol'>)),</span><span class='pas1-space'> GENERIC_READ</span><span class='pas1-symbol'>,</span><span class='pas1-space'> FILE_SHARE_READ </span><span class='pas1-reservedword'>or
</span><span class='pas1-space'> FILE_SHARE_WRITE</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OPEN_EXISTING</span><span class='pas1-symbol'>,</span><span class='pas1-space'> FILE_ATTRIBUTE_NORMAL</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> FileHandle </span><span class='pas1-symbol'><></span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>try
</span><span class='pas1-space'> FSize </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> GetFileSize</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FileHandle</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> FSize </span><span class='pas1-symbol'><></span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> FMapping </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> CreateFileMappingW</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FileHandle</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil</span><span class='pas1-symbol'>,</span><span class='pas1-space'> PAGE_READONLY</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-comment'>//Win32Check(FMapping <> 0);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>finally
</span><span class='pas1-space'> CloseHandle</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FileHandle</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> FSize </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then
</span><span class='pas1-space'> FContent </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-reservedword'>nil
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>else
</span><span class='pas1-space'> FContent </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> MapViewOfFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>FMapping</span><span class='pas1-symbol'>,</span><span class='pas1-space'> FILE_MAP_READ</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-comment'>//Win32Check(FContent <> nil);
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>.
</span></span></code></pre>
<p>The big advantage is, that with BlockRead you can either read the whole content of the file in the array, or buffering the file in blocks. With MMF there is no need to worry about it (unless you get very big files), Windows automatically arranges the memory when requested.Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com1tag:blogger.com,1999:blog-3108828885823618940.post-88190964146019524272005-08-19T23:41:00.001+02:002009-03-09T09:39:05.327+01:00Getting (possibly) 500% speed gain on divisions<span class="Notice">This post was migrated from <a href="http://delphi-snippets.blogspot.com/2005/08/getting-possibly-500-speed-gain-on.html" rel="nofollow">My old blog delphi-snippets.blogspot.com</a>, for explanation about this switch see <a href="http://landman-code.blogspot.com/2008/07/my-new-blog.html" rel="nofollow">my introduction post</a>.</span> One of my fellow students once made a remark about the old days when a division was much faster if it was written as multiplication. </p> <p> This means, instead of devising with a 100, you multiply with 0.01 (1/100). Because some programs of mine have a lot of divisions in their core loops, I investigated the difference.</p> <p> I created the following test program.</p>
<pre class="Source Boxed">
<code><span class="pas1-reservedword">program</span><span class="pas1-space"> DivVsMult</span><span class="pas1-symbol">;
</span><span class="pas1-preprocessor">{$APPTYPE CONSOLE}
</span><span class="pas1-reservedword">uses
</span><span class="pas1-space"> SysUtils</span><span class="pas1-symbol">,
</span><span class="pas1-space"> Windows</span><span class="pas1-symbol">;</span><span class="pas1-space">
</span><span class="pas1-reservedword">var</span><span class="pas1-space">
Start</span><span class="pas1-symbol">,</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">,</span><span class="pas1-space"> Start2</span><span class="pas1-symbol">,</span><span class="pas1-space"> Stop2</span><span class="pas1-symbol">,</span><span class="pas1-space"> Freq</span><span class="pas1-symbol">:</span><span class="pas1-identifier">int64</span><span class="pas1-symbol">;
</span><span class="pas1-space"> i </span><span class="pas1-symbol">:</span><span class="pas1-space"> integer</span><span class="pas1-symbol">;</span><span class="pas1-space">
t </span><span class="pas1-symbol">:</span><span class="pas1-space"> real</span><span class="pas1-symbol">;</span><span class="pas1-space">
CpuSpeed </span><span class="pas1-symbol">:</span><span class="pas1-space"> integer</span><span class="pas1-symbol">;</span><span class="pas1-space">
</span><span class="pas1-reservedword">begin</span><span class="pas1-space">
</span><span class="pas1-comment">{ TODO -oUser -cConsole Main : Insert code here }</span><span class="pas1-space">
</span><span class="pas1-comment">{ Cpu Speed fastes cpu = 1 slower => 10
it's just to determin the number of time to do the loop
Maxint div CpuSpeed is calculated }</span><span class="pas1-space">
</span><span class="pas1-reservedword">if</span><span class="pas1-space"> ParamCount </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">1</span><span class="pas1-space"> </span><span class="pas1-reservedword">then</span><span class="pas1-space">
CpuSpeed </span><span class="pas1-symbol">:=</span><span class="pas1-space"> StrToIntDef</span><span class="pas1-symbol">(</span><span class="pas1-identifier">ParamStr</span><span class="pas1-symbol">(</span><span class="pas1-number">1</span><span class="pas1-symbol">),</span><span class="pas1-number">1</span><span class="pas1-symbol">)</span><span class="pas1-space">
</span><span class="pas1-reservedword">else</span><span class="pas1-space">
CpuSpeed </span><span class="pas1-symbol">:=</span><span class="pas1-space"> </span><span class="pas1-number">10</span><span class="pas1-symbol">;</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Simple Number division:'</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Calculating'</span><span class="pas1-symbol">);</span><span class="pas1-space">
QueryPerformanceFrequency</span><span class="pas1-symbol">(</span><span class="pas1-identifier">freq</span><span class="pas1-symbol">);</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">);</span><span class="pas1-space">
</span><span class="pas1-reservedword">for</span><span class="pas1-space"> i</span><span class="pas1-symbol">:=</span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> MaxInt </span><span class="pas1-reservedword">div</span><span class="pas1-space"> CpuSpeed </span><span class="pas1-reservedword">do</span><span class="pas1-space">
t </span><span class="pas1-symbol">:=</span><span class="pas1-space"> i </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">100</span><span class="pas1-symbol">;
</span><span class="pas1-space"> QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'First Pass Result: %f'</span><span class="pas1-symbol">,[</span><span class="pas1-identifier">t</span><span class="pas1-symbol">]));</span><span class="pas1-space">
</span><span class="pas1-comment">{ This is needed because the compiler would optimize,
and would notice the result of the loop isn't used at all,
so therefor the result is useless.. so depending on the compiler, it will
choose what to do with it, this disables that optimization }</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">);</span><span class="pas1-space">
</span><span class="pas1-reservedword">for</span><span class="pas1-space"> i</span><span class="pas1-symbol">:=</span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> MaxInt </span><span class="pas1-reservedword">div</span><span class="pas1-space"> CpuSpeed </span><span class="pas1-reservedword">do</span><span class="pas1-space">
t </span><span class="pas1-symbol">:=</span><span class="pas1-space"> i </span><span class="pas1-symbol">*</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-number">1</span><span class="pas1-symbol">/</span><span class="pas1-number">100</span><span class="pas1-symbol">);</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'Second Pass Result: %15.6f'</span><span class="pas1-symbol">,[</span><span class="pas1-identifier">t</span><span class="pas1-symbol">]));</span><span class="pas1-space">
</span><span class="pas1-comment">{ This is needed because the compiler would optimize,
and would notice the result of the loop isn't used at all,
so therefor the result is useless.. so depending on the compiler, it will
choose what to do with it, this disables that optimization }</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Done, Results:'</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'/ 100 Time: %6.4f seconds'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'/ 100 Clock: %d ticks'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'* 0.01 Time: %6.4f seconds'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'* 0.01 Clock: %d ticks'</span><span class="pas1-symbol">,[(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">/</span><span class="pas1-space"> freq</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">),</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">/</span><span class="pas1-space"> freq</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">)]));
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">;</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-string">'Odd Number division:'</span><span class="pas1-symbol">);</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">);</span><span class="pas1-space">
</span><span class="pas1-reservedword">for</span><span class="pas1-space"> i</span><span class="pas1-symbol">:=</span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> high</span><span class="pas1-symbol">(</span><span class="pas1-identifier">i</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">div</span><span class="pas1-space"> CpuSpeed </span><span class="pas1-reservedword">do
</span><span class="pas1-space"> t </span><span class="pas1-symbol">:=</span><span class="pas1-space"> i </span><span class="pas1-symbol">/</span><span class="pas1-space"> </span><span class="pas1-number">556</span><span class="pas1-symbol">;</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'First Pass Result: %15.6f'</span><span class="pas1-symbol">,[</span><span class="pas1-identifier">t</span><span class="pas1-symbol">]));</span><span class="pas1-space">
</span><span class="pas1-comment">{ This is needed because the compiler would optimize,
and would notice the result of the loop isn't used at all,
so therefor the result is useless.. so depending on the compiler, it will
choose what to do with it, this disables that optimization }</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">);</span><span class="pas1-space">
</span><span class="pas1-reservedword">for</span><span class="pas1-space"> i</span><span class="pas1-symbol">:=</span><span class="pas1-number">0</span><span class="pas1-space"> </span><span class="pas1-reservedword">to</span><span class="pas1-space"> high</span><span class="pas1-symbol">(</span><span class="pas1-identifier">i</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">div</span><span class="pas1-space"> CpuSpeed </span><span class="pas1-reservedword">do</span><span class="pas1-space">
t </span><span class="pas1-symbol">:=</span><span class="pas1-space"> i </span><span class="pas1-symbol">*</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-number">1</span><span class="pas1-symbol">/</span><span class="pas1-number">556</span><span class="pas1-symbol">);</span><span class="pas1-space">
QueryPerformanceCounter</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">);</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'Second Pass Result: %15.6f'</span><span class="pas1-symbol">,[</span><span class="pas1-identifier">t</span><span class="pas1-symbol">]));</span><span class="pas1-space">
Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">'/ 556 Time: %6.4f seconds'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'/ 556 Clock: %d ticks'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'* (1/556) Time: %6.4f seconds'</span><span class="pas1-symbol">+</span><span class="pas1-character">#13#10</span><span class="pas1-symbol">+</span><span class="pas1-space">
</span><span class="pas1-string">'* (1/556) Clock: %d ticks'</span><span class="pas1-symbol">,[(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">/</span><span class="pas1-space"> freq</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start</span><span class="pas1-symbol">),</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-symbol">/</span><span class="pas1-space"> freq</span><span class="pas1-symbol">,</span><span class="pas1-space"> </span><span class="pas1-symbol">(</span><span class="pas1-identifier">Stop2</span><span class="pas1-symbol">-</span><span class="pas1-identifier">Start2</span><span class="pas1-symbol">)]));
</span><span class="pas1-space"> Writeln</span><span class="pas1-symbol">(</span><span class="pas1-identifier">Format</span><span class="pas1-symbol">(</span><span class="pas1-string">' (1/556) = %15.14f (approximate)'</span><span class="pas1-symbol">,[</span><span class="pas1-number">1</span><span class="pas1-symbol">/</span><span class="pas1-number">556</span><span class="pas1-symbol">]));</span><span class="pas1-space">
Readln</span><span class="pas1-symbol">;
</span><span class="pas1-space">
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">.
</span>
</code></pre>
<p>
On an old P3 900Mhz:</p>
<blockquote class="Console">
Simple Number division:<br />
Calculating<br />
First Pass Result: 2147483,64<br />
Second Pass Result: 2147483,64<br />
Done, Results:<br />
/ 100 Time: 10,3319 seconds<br />
/ 100 Clock: 36983482 ticks<br />
* 0.01 Time: 2,0378 seconds<br />
* 0.01 Clock: 7294251 ticks<br />
<br />
Odd Number division:<br />
First Pass Result: 386238,0647482014610000<br />
Second Pass Result: 386238,0647482014610000<br />
Done, Results:<br />
/ 556 Time: 10,0735 seconds<br />
/ 556 Clock: 36058581 ticks<br />
* (1/556) Time: 2,0446 seconds<br />
* (1/556) Clock: 7318775 ticks<br />
(1/556) = 0,0017985611510791 (approximate)
</blockquote>
<p>
On a new P4 2.3 Ghz:</p>
<blockquote class="Console">
Simple Number division:<br />
Calculating<br />
First Pass Result: 2147483.64<br />
Second Pass Result: 2147483.64<br />
Done, Results:<br />
/ 100 Time: 4.6227 seconds<br />
/ 100 Clock: 16547055 ticks<br />
* 0.01 Time: 1.0782 seconds<br />
* 0.01 Clock: 3859508 ticks<br />
<br />
Odd Number division:<br />
First Pass Result: 386238.064748<br />
Second Pass Result: 386238.064748<br />
Done, Results:<br />
/ 556 Time: 4.5820 seconds<br />
/ 556 Clock: 16401425 ticks<br />
* (1/556) Time: 12.1746 seconds<br />
* (1/556) Clock: 43579366 ticks<br />
(1/556) = 0.00179856115108 (approximate)
</blockquote>
<p>
The results are variating, on simple numbers like 0.01 the speedup is allways working,
but somehow the very complex numbers tend to be slower sometimes.</p>
<p>
I use this tip a lot when working with percentage.Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0tag:blogger.com,1999:blog-3108828885823618940.post-19563774543103239712005-08-18T01:02:00.002+02:002009-01-21T23:01:59.552+01:00Automatic Cropping of a Bitmap<span class="Notice">This post was migrated from <a href="http://delphi-snippets.blogspot.com/2005/08/automatic-cropping-of-bitmap_18.html" rel="nofollow">my old blog delphi-snippets.blogspot.com</a>, for explanation about this switch see <a href="http://landman-code.blogspot.com/2008/07/my-new-blog.html" rel="nofollow">my introduction post</a>.</span> I have created a lot of program’s which needed to do some operations on Bitmaps, most of them are pretty simple, but recently I needed some auto cropping due to the fact I could not calculate the width and height without a lot of calculation, but the maximum could easily be calculated/estimated, therefor I needed an algorithm for cropping these bitmap automatically. <p></p> <p>Everyone who uses Delphi and Bitmaps should have at least heard about scanlines, and in particularly <a href="http://homepages.borland.com/efg2lab/">efg</a>’s pages on the <a href="http://homepages.borland.com/efg2lab/ImageProcessing/Scanline.htm">topic</a>. In short: </p> <blockquote cite='http://homepages.borland.com/efg2lab/ImageProcessing/Scanline.htm'> <p>The ScanLine property, new in Delphi 3, allows quick access to individual pixels, but you must know what PixelFormat you're working with before you can access the pixels correctly.</p> </blockquote> <p>Because I almost always work with 24bit bitmaps, I didn’t adapt the code for other pixel formats, but it should really just be editing the “<span class='Source'>procedure AutoCropBitmap(InputBitmap, OutputBitmap: TBitmap; iBleeding : Integer; BackColor: TColor);</span>” overload to start the right sub functions for each pixel format.</p> <p>The current function will always translate it to an 24bit bitmap, which can be a processor and memory heavy job, the advise is therefor directly after creating the bitmap set the PixelFormat to pf24bit. </p> <p>You might notice the overloads, well thats just one part of me being lazy again, sometimes I haven’t got the time to create an extra variable and assign the property’s etc. The overloads allow the choice of which input and output you’ll like.</p> <pre class='Source Boxed'><code><span style='font: 10pt courier new'><span class='pas1-reservedword'>unit</span><span class='pas1-space'> unBitmapCropping</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>interface</span><span class='pas1-space'>  <br />  <br /></span><span class='pas1-reservedword'>uses <br /></span><span class='pas1-space'> Windows</span><span class='pas1-symbol'>,</span><span class='pas1-space'> Graphics</span><span class='pas1-symbol'>,</span><span class='pas1-space'> Dialogs</span><span class='pas1-symbol'>,</span><span class='pas1-space'> SysUtils</span><span class='pas1-symbol'>,</span><span class='pas1-space'> Math</span><span class='pas1-symbol'>,</span><span class='pas1-space'> Classes</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>const <br /></span><span class='pas1-space'> PixelCountMax </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>32768</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>type <br /></span><span class='pas1-space'> pRGBArray </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-symbol'>^</span><span class='pas1-identifier'>TRGBArray</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> TRGBArray </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-reservedword'>array</span><span class='pas1-symbol'>[</span><span class='pas1-number'>0</span><span class='pas1-symbol'>..</span><span class='pas1-identifier'>PixelCountMax</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-symbol'>]</span><span class='pas1-space'> </span><span class='pas1-reservedword'>of</span><span class='pas1-space'> TRGBTriple</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBmp</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> sFileName </span><span class='pas1-symbol'>:</span><span class='pas1-space'> </span><span class='pas1-reservedword'>String</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBmp</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> sFileName </span><span class='pas1-symbol'>:</span><span class='pas1-space'> </span><span class='pas1-reservedword'>String</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>);</span><span class='pas1-space'> </span><span class='pas1-reservedword'>overload</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>implementation</span><span class='pas1-space'>  <br />  <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>var</span><span class='pas1-space'> bmpTmp </span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> bmpTmp </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>try <br /></span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>bmpTmp</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>iBleeding</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> BitMapToCrop</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Assign</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>bmpTmp</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>finally <br /></span><span class='pas1-space'> bmpTmp</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>var</span><span class='pas1-space'> bmpTmp </span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> bmpTmp </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>try <br /></span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BitMapToCrop</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>bmpTmp</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>iBleeding</span><span class='pas1-symbol'>,</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> BitMapToCrop</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Assign</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>bmpTmp</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>finally <br /></span><span class='pas1-space'> bmpTmp</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>OutputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> iBleeding</span><span class='pas1-symbol'>,</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Canvas</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Pixels</span><span class='pas1-symbol'>[</span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-number'>0</span><span class='pas1-symbol'>]); <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>var</span><span class='pas1-space'> Row </span><span class='pas1-symbol'>:</span><span class='pas1-space'> pRGBArray</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> MyTop</span><span class='pas1-symbol'>,</span><span class='pas1-space'> MyBottom</span><span class='pas1-symbol'>,</span><span class='pas1-space'> MyLeft</span><span class='pas1-symbol'>, <br /></span><span class='pas1-space'> i</span><span class='pas1-symbol'>,</span><span class='pas1-space'> j</span><span class='pas1-symbol'>,</span><span class='pas1-space'> MyRight </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> MyTop </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> MyLeft </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> MyBottom </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> MyRight </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pf24bit</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pf24Bit</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-comment'>{ Find Top } <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> j </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> j </span><span class='pas1-symbol'>></span><span class='pas1-space'> MyTop </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Row </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pRGBArray</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Scanline</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>j</span><span class='pas1-symbol'>]); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i</span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width </span><span class='pas1-symbol'>-</span><span class='pas1-space'> </span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>downto</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>((</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtRed </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetRvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtGreen </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetGvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtBlue </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetBvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>)))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> MyTop </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> j</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> MyTop </span><span class='pas1-symbol'>=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-comment'>{ Empty Bitmap } <br /></span><span class='pas1-space'> MyTop </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /> </span><span class='pas1-comment'>{ Find Bottom } <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> j </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>Downto</span><span class='pas1-space'> MyTop </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>j </span><span class='pas1-symbol'>+</span><span class='pas1-space'> </span><span class='pas1-number'>1</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-symbol'><</span><span class='pas1-space'> MyBottom </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Row </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pRGBArray</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Scanline</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>j</span><span class='pas1-symbol'>]); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i</span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width </span><span class='pas1-symbol'>-</span><span class='pas1-space'> </span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>downto</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>((</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtRed </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetRvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtGreen </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetGvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtBlue </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetBvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>)))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> MyBottom </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> j</span><span class='pas1-symbol'>+</span><span class='pas1-number'>1</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /> </span><span class='pas1-comment'>{ Find Left } <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> j </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> MyTop </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> MyBottom</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> Row </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pRGBArray</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Scanline</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>j</span><span class='pas1-symbol'>]); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i</span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-space'> </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> MyLeft</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>((</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtRed </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetRvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtGreen </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetGvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtBlue </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetBvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>)))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> MyLeft </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> i</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> MyLeft </span><span class='pas1-symbol'>=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-comment'>{ Empty Bitmap } <br /></span><span class='pas1-space'> MyLeft </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /> </span><span class='pas1-comment'>{ Find Right } <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> j </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> MyTop </span><span class='pas1-reservedword'>to</span><span class='pas1-space'> MyBottom </span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> Row </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> pRGBArray</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Scanline</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>j</span><span class='pas1-symbol'>]); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>for</span><span class='pas1-space'> i</span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width</span><span class='pas1-symbol'>-</span><span class='pas1-number'>1</span><span class='pas1-space'> </span><span class='pas1-reservedword'>downto</span><span class='pas1-space'> MyRight </span><span class='pas1-reservedword'>do <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>((</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtRed </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetRvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtGreen </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetGvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Row</span><span class='pas1-symbol'>[</span><span class='pas1-identifier'>i</span><span class='pas1-symbol'>].</span><span class='pas1-identifier'>rgbtBlue </span><span class='pas1-symbol'><></span><span class='pas1-space'> GetBvalue</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>BackColor</span><span class='pas1-symbol'>)))</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> MyRight </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> i</span><span class='pas1-symbol'>+</span><span class='pas1-number'>1</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> Break</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>MyRight </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>or</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>MyBottom </span><span class='pas1-symbol'>=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-comment'>{ Empty Bitmap } <br /></span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>; <br /> <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> MyRight </span><span class='pas1-symbol'>-</span><span class='pas1-space'> MyLeft </span><span class='pas1-symbol'>+</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>iBleeding </span><span class='pas1-symbol'>*</span><span class='pas1-space'> </span><span class='pas1-number'>2</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> MyBottom </span><span class='pas1-symbol'>-</span><span class='pas1-space'> MyTop </span><span class='pas1-symbol'>+</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>iBleeding </span><span class='pas1-symbol'>*</span><span class='pas1-space'> </span><span class='pas1-number'>2</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Canvas</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Brush</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Color </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Canvas</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>FillRect</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>Rect</span><span class='pas1-symbol'>(</span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Width</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Height</span><span class='pas1-symbol'>));</span><span class='pas1-space'>  <br /> <br /> BitBlt</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>canvas</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Handle</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-symbol'>-</span><span class='pas1-identifier'>MyLeft </span><span class='pas1-symbol'>+</span><span class='pas1-space'> iBleeding</span><span class='pas1-symbol'>, <br /></span><span class='pas1-space'> </span><span class='pas1-symbol'>-</span><span class='pas1-identifier'>MyTop </span><span class='pas1-symbol'>+</span><span class='pas1-space'> iBleeding</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>MyLeft </span><span class='pas1-symbol'>+</span><span class='pas1-space'> MyRight</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>MyTop </span><span class='pas1-symbol'>+</span><span class='pas1-space'> MyBottom</span><span class='pas1-symbol'>, <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Canvas</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Handle</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> </span><span class='pas1-number'>0</span><span class='pas1-symbol'>,</span><span class='pas1-space'> SRCCOPY</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBmp</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> sFileName </span><span class='pas1-symbol'>:</span><span class='pas1-space'> </span><span class='pas1-reservedword'>String</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>var</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap </span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-reservedword'>not</span><span class='pas1-space'> FileExists</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>raise</span><span class='pas1-space'> Exception</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>(</span><span class='pas1-string'>'File doesn''s exists.'</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> InputBitmap </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> OutputBitmap </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>try <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>LoadFromFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>iBleeding</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>SaveToFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>finally <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;</span><span class='pas1-space'>  <br /> <br /></span><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> AutoCropBmp</span><span class='pas1-symbol'>(</span><span class='pas1-reservedword'>const</span><span class='pas1-space'> sFileName </span><span class='pas1-symbol'>:</span><span class='pas1-space'> </span><span class='pas1-reservedword'>String</span><span class='pas1-symbol'>;</span><span class='pas1-space'> iBleeding </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Integer</span><span class='pas1-symbol'>;</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>:</span><span class='pas1-space'> TColor</span><span class='pas1-symbol'>); <br /></span><span class='pas1-reservedword'>var</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap </span><span class='pas1-symbol'>:</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>begin <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>if</span><span class='pas1-space'> </span><span class='pas1-reservedword'>not</span><span class='pas1-space'> FileExists</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>then <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>raise</span><span class='pas1-space'> Exception</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>(</span><span class='pas1-string'>'File doesn''s exists.'</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> InputBitmap </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> OutputBitmap </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> TBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Create</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>try <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>LoadFromFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>PixelFormat</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> AutoCropBitmap</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>InputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>,</span><span class='pas1-identifier'>iBleeding</span><span class='pas1-symbol'>,</span><span class='pas1-space'> BackColor</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>SaveToFile</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>sFileName</span><span class='pas1-symbol'>); <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>finally <br /></span><span class='pas1-space'> OutputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> InputBitmap</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>Free</span><span class='pas1-symbol'>; <br /></span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>; <br /> <br /></span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>.</span><span class='pas1-space'>  <br /> <br /></span></span> <br /></code></pre>
<p>I started off with an <a href="http://www.efg2.com/Lab/Library/UseNet/2000/0307.txt">example</a> found on efg’s site, and started optimizing it’s algorithm:</p>
<ul>
<li>Dismissed the Temp variables and the counter variable.</li>
<li>Making the loops<span class='Source'> downto 0</span> as many as possible (this will make the loop slightly faster).</li>
<li>Making sure no extra round on the loop is used (adding breaks).</li>
<li>Decreasing the number of core operations (removing if’s)</li>
</ul>
<p>With this I created a >400% speed gain.</p>
<p>Writing this article, I got the following ideas for a little more speedup:</p>
<ul>
<li>Storing the <span class='Source'>GetXvalue</span> results, as to decrease the recalculation in each for loop.</li>
<li>Maybe running loops for 0 till the end will make it faster because of better page alignment</li>
</ul>
<p>But I will try that out an other time.</p> Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0tag:blogger.com,1999:blog-3108828885823618940.post-69614521094022907712005-08-16T10:01:00.002+02:002008-07-15T19:10:34.066+02:00CPU and Form Friendly (Long) Sleep<span class="Notice">This post was migrated from <a href="http://delphi-snippets.blogspot.com/2005/08/cpu-and-form-friendly-long-sleep.html" rel="nofollow">my old blog delphi-snippets.blogspot.com</a>, for explanation about this switch see <a href="http://landman-code.blogspot.com/2008/07/my-new-blog.html" rel="nofollow">my introduction post</a>.</span> Because a <span class='Source'>Sleep(1000)</span> will seriously freeze your form for a second, the you’ll see that the solution will often be using a <span
class='Source'>Application.ProcessMessages </span>loop until the second has passed, but the problem with that loop is, it will create 100% cpu usage. </p> <p> Let’s say your waiting for a response from a printer your controlling, than the 100% usage might slow down the complete process, not to mention that on a laptop you’ll be seriously eating the battery.</p> <p> The following source offers a nice solution to this problem.</p> <pre class='Source'>
<code><span class='pas1-reservedword'>procedure</span><span class='pas1-space'> TForm</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>LongDelay</span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>DelayMs </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Cardinal</span><span class='pas1-symbol'>);
</span><span class='pas1-reservedword'>var
</span><span class='pas1-space'> StopTime </span><span class='pas1-symbol'>:</span><span class='pas1-space'> Cardinal</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> StopTime </span><span class='pas1-symbol'>:=</span><span class='pas1-space'> GetTickCount </span><span class='pas1-symbol'>+</span><span class='pas1-space'> DelayMs</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>while</span><span class='pas1-space'> </span><span class='pas1-symbol'>(</span><span class='pas1-identifier'>GetTickCount </span><span class='pas1-symbol'><</span><span class='pas1-space'> StopTime</span><span class='pas1-symbol'>)</span><span class='pas1-space'> </span><span class='pas1-reservedword'>do
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>begin
</span><span class='pas1-space'> Application</span><span class='pas1-symbol'>.</span><span class='pas1-identifier'>ProcessMessages</span><span class='pas1-symbol'>;
</span><span class='pas1-space'> Sleep</span><span class='pas1-symbol'>(</span><span class='pas1-number'>1</span><span class='pas1-symbol'>);
</span><span class='pas1-space'> </span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span><span class='pas1-reservedword'>end</span><span class='pas1-symbol'>;
</span>
</code></pre>
<p>
It’s pretty straight forward, offcourse when using a basic windows function,
you should check out <a href="http://msdn.microsoft.com/library/en-us/dllproc/base/sleep.asp">
MSDN</a> for the arguments and remarks. There was one thing that was interresting.</p>
<blockquote cite='http://msdn.microsoft.com/library/en-us/dllproc/base/sleep.asp'>
<p>
A value of zero causes the thread to relinquish the remainder of its time slice
to any other thread of equal priority that is ready to run. If there are no other
threads of equal priority ready to run, the function returns immediately, and the
thread continues execution.</p>
</blockquote>
<p>
This fixes one problem, you will only use the cpu when it’s idle. But that
still makes this a battery eater on laptops.</p>
<p>
I hope you liked this first post, this was just a minor subject.. But I got to start
somewhere.Davy Landmanhttp://www.blogger.com/profile/06890346525536829946noreply@blogger.com0