Created
June 25, 2025 19:36
-
-
Save teoadal/a7395b5a96f8c6209bb61f5df706de1e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Frozen; | |
using System.Runtime.CompilerServices; | |
namespace ConsoleApp1; | |
[SimpleJob(RuntimeMoniker.Net90)] | |
[SimpleJob(RuntimeMoniker.Net80)] | |
[Orderer(SummaryOrderPolicy.FastestToSlowest)] | |
[MeanColumn, MemoryDiagnoser] | |
public class HasFlagBench | |
{ | |
private Operator[] _flags = null!; | |
private Operator[] _values = null!; | |
[Benchmark(Baseline = true)] | |
public bool HasFlagMethod() | |
{ | |
var result = false; | |
foreach (var flag in _flags) | |
{ | |
foreach (var value in _values) | |
{ | |
result = value.HasFlag(flag); | |
} | |
} | |
return result; | |
} | |
[Benchmark] | |
public bool BitwiseOperation() | |
{ | |
var result = false; | |
foreach (var flag in _flags) | |
{ | |
foreach (var value in _values) | |
{ | |
result = (value & flag) != 0; | |
} | |
} | |
return result; | |
} | |
[Benchmark] | |
public bool SwitchCheck() | |
{ | |
var result = false; | |
foreach (var flag in _flags) | |
{ | |
foreach (var value in _values) | |
{ | |
result = value.Is(flag); | |
} | |
} | |
return result; | |
} | |
[Benchmark] | |
public bool ArrayCheck() | |
{ | |
var result = false; | |
foreach (var flag in _flags) | |
{ | |
foreach (var value in _values) | |
{ | |
result = value.Is_Array(flag); | |
} | |
} | |
return result; | |
} | |
[Benchmark] | |
public bool HashSetCheck() | |
{ | |
var result = false; | |
foreach (var flag in _flags) | |
{ | |
foreach (var value in _values) | |
{ | |
result = value.Is_HashSet(flag); | |
} | |
} | |
return result; | |
} | |
[GlobalSetup] | |
public void Setup() | |
{ | |
_flags = | |
[ | |
Operator.NonOperator, | |
Operator.Comparison, | |
Operator.Logical, | |
Operator.Math, | |
Operator.Grouping | |
]; | |
_values = Enum.GetValues<Operator>(); | |
} | |
} | |
[Flags] | |
public enum Operator : short | |
{ | |
None = 0x0, | |
// Flags | |
NonOperator = 0x0001, | |
Comparison = 0x0002, | |
Logical = 0x0004, | |
Math = 0x0008, | |
Grouping = 0x0010, | |
// Grouping Operators | |
OpenParen = 0x0100 | Grouping, | |
ClosedParen = 0x0200 | Grouping, | |
// Logical Operators | |
Not = 0x0300 | Logical, | |
Or = 0x0400 | Logical, | |
And = 0x0500 | Logical, | |
In = 0x0600 | Logical, | |
// Comparison Operators | |
Equals = 0x0700 | Comparison, | |
NotEquals = 0x0800 | Comparison, | |
LessThan = 0x0900 | Comparison, | |
LessThanOrEqual = 0x0A00 | Comparison, | |
GreaterThan = 0x0B00 | Comparison, | |
GreaterThanOrEqual = 0x0C00 | Comparison, | |
// Math Operators | |
Add = 0x0D00 | Math, | |
Subtract = 0x0E00 | Math, | |
Multiply = 0x0F00 | Math, | |
Divide = 0x1000 | Math, | |
Modulus = 0x1100 | Math, | |
// Specific non-operators | |
Whitespace = 0x2000 | NonOperator, | |
Quotes = 0x2100 | NonOperator, | |
Token = 0x2200 | NonOperator, | |
Bracket = 0x2300 | NonOperator, | |
} | |
public static class OperatorExtensions | |
{ | |
private static readonly Operator[] NonOperatorValues = | |
[ | |
Operator.Whitespace, | |
Operator.Quotes, | |
Operator.Token, | |
Operator.Bracket | |
]; | |
private static readonly Operator[] ComparisonValues = | |
[ | |
Operator.Equals, | |
Operator.NotEquals, | |
Operator.LessThan, | |
Operator.LessThanOrEqual, | |
Operator.GreaterThan, | |
Operator.GreaterThanOrEqual | |
]; | |
private static readonly Operator[] LogicalValues = | |
[ | |
Operator.Not, | |
Operator.Or, | |
Operator.And, | |
Operator.In | |
]; | |
private static readonly Operator[] MathValues = | |
[ | |
Operator.Add, | |
Operator.Subtract, | |
Operator.Multiply, | |
Operator.Divide, | |
Operator.Modulus | |
]; | |
private static readonly FrozenSet<Operator> NonOperatorSet = NonOperatorValues.ToFrozenSet(); | |
private static readonly FrozenSet<Operator> ComparisonSet = ComparisonValues.ToFrozenSet(); | |
private static readonly FrozenSet<Operator> LogicalSet = LogicalValues.ToFrozenSet(); | |
private static readonly FrozenSet<Operator> MathSet = MathValues.ToFrozenSet(); | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool Is(this Operator op, Operator flag) => flag switch | |
{ | |
Operator.NonOperator => IsNonOperator(op), | |
Operator.Comparison => IsComparison(op), | |
Operator.Logical => IsLogical(op), | |
Operator.Math => IsMath(op), | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool Is_Array(this Operator op, Operator flag) => flag switch | |
{ | |
Operator.NonOperator => IsNonOperator_Array(op), | |
Operator.Comparison => IsComparison_Array(op), | |
Operator.Logical => IsLogical_Array(op), | |
Operator.Math => IsMath_Array(op), | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool Is_HashSet(this Operator op, Operator flag) => flag switch | |
{ | |
Operator.NonOperator => IsNonOperator_HashSet(op), | |
Operator.Comparison => IsComparison_HashSet(op), | |
Operator.Logical => IsLogical_HashSet(op), | |
Operator.Math => IsMath_HashSet(op), | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsNonOperator(this Operator op) => op switch | |
{ | |
Operator.Whitespace => true, | |
Operator.Quotes => true, | |
Operator.Token => true, | |
Operator.Bracket => true, | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsComparison(this Operator op) => op switch | |
{ | |
Operator.Equals => true, | |
Operator.NotEquals => true, | |
Operator.LessThan => true, | |
Operator.LessThanOrEqual => true, | |
Operator.GreaterThan => true, | |
Operator.GreaterThanOrEqual => true, | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsLogical(this Operator op) => op switch | |
{ | |
Operator.Not => true, | |
Operator.Or => true, | |
Operator.And => true, | |
Operator.In => true, | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsMath(this Operator op) => op switch | |
{ | |
Operator.Add => true, | |
Operator.Subtract => true, | |
Operator.Multiply => true, | |
Operator.Divide => true, | |
Operator.Modulus => true, | |
_ => false | |
}; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsNonOperator_Array(this Operator op) => Array.IndexOf(NonOperatorValues, op) > -1; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsComparison_Array(this Operator op) => Array.IndexOf(ComparisonValues, op) > -1; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsLogical_Array(this Operator op) => Array.IndexOf(LogicalValues, op) > -1; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool IsMath_Array(this Operator op) => Array.IndexOf(MathValues, op) > -1; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static bool IsMath_HashSet(Operator op) => MathSet.Contains(op); | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static bool IsLogical_HashSet(Operator op) => LogicalSet.Contains(op); | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static bool IsComparison_HashSet(Operator op) => ComparisonSet.Contains(op); | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static bool IsNonOperator_HashSet(Operator op) => NonOperatorSet.Contains(op); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment