Here's a surprise, range operator is beaten by a large set of serial cases statements!
In the below code example which validates a drive letter, by
using System.Runtime.CompilerServices;
you can adorn the case-statement method to be compiled with
[MethodImplAttribute(MethodImplOptions.AggressiveOptimization )] and/or
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
to surprising results. I was surprised by v6. v5 and v6 win on alternative runs.
Full documentation here - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.methodimploptions
Source Code
using System; using System.Diagnostics; using System.Runtime.CompilerServices; public static class Program { //Fri 30-Oct-20 2:17pm metadataconsulting.ca //https://metadataconsulting.blogspot.com/2020/10/C-NET-Validate-Drive-Letter-with-compiler-optimization-aggressive-in-lining-for-large-fall-through-case-statements.html //-> this method does not exist on the interwebs, trivial? //-> fun with compiler switches to optimize case statements public static bool isValidDriveLetter(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); // this is surprisingly faster than the equivalent if statement switch (drivewithcolon[0]) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return true; default: return false; } } else return false; } //range operator public static bool isValidDriveLetterV2(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); if (drivewithcolon[0] >= 'A' && drivewithcolon[0] <= 'Z') return true; else return false; } else return false; } [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] public static bool isValidDriveLetterV3(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); // this is surprisingly faster than the equivalent if statement switch (drivewithcolon[0]) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return true; default: return false; } } else return false; } [MethodImplAttribute(MethodImplOptions.AggressiveOptimization)] public static bool isValidDriveLetterV4(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); // this is surprisingly faster than the equivalent if statement switch (drivewithcolon[0]) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return true; default: return false; } } else return false; } [MethodImplAttribute(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public static bool isValidDriveLetterV5(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); // this is surprisingly faster than the equivalent if statement switch (drivewithcolon[0]) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return true; default: return false; } } else return false; } [MethodImplAttribute(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public static bool isValidDriveLetterV6(this string drivewithcolon) { if (drivewithcolon.Length == 2 && drivewithcolon[1] == ':') { drivewithcolon = drivewithcolon.ToUpper(); if (drivewithcolon[0] >= 'A' && drivewithcolon[0] <= 'Z') return true; else return false; } else return false; } public static void Main() { bool v1,v2,v3,v4,v5,v6 = false; Stopwatch sw = new Stopwatch(); sw.Start(); v1= "Z:".isValidDriveLetter(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v1 in {1} ticks.",v1.ToString(), sw.ElapsedTicks); sw.Reset(); sw.Start(); v2= "Z:".isValidDriveLetterV2(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v2 in {1} ticks.",v2.ToString(), sw.ElapsedTicks); sw.Reset(); sw.Start(); v3= "Z:".isValidDriveLetterV3(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v3 in {1} ticks.",v3.ToString(), sw.ElapsedTicks); sw.Reset(); sw.Start(); v4= "Z:".isValidDriveLetterV4(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v4 in {1} ticks.",v4.ToString(), sw.ElapsedTicks); sw.Reset(); sw.Start(); v5= "Z:".isValidDriveLetterV5(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v5 in {1} ticks.",v5.ToString(), sw.ElapsedTicks); sw.Reset(); sw.Start(); v6= "Z:".isValidDriveLetterV6(); sw.Stop(); Console.WriteLine("is Z: valid drive letter ?{0}, v6 in {1} ticks.",v6.ToString(), sw.ElapsedTicks); } }
No comments:
Post a Comment