Skip to content

Commit a73bbb5

Browse files
committed
Add early exit reduction
1 parent 2e66a83 commit a73bbb5

20 files changed

Lines changed: 74 additions & 0 deletions

Src/FastData/FastDataGenerator.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ HashData GetNumericHash(ReadOnlySpan<TKey> keySpan)
310310

311311
private static IEarlyExit[] CombineEarlyExits(IEnumerable<IEarlyExit> mandatoryExits, IEnumerable<IEarlyExit> candidateExits)
312312
{
313+
// Use hash set to deduplicate early exits on their direct values
313314
HashSet<IEarlyExit> combined = new HashSet<IEarlyExit>();
314315

315316
foreach (IEarlyExit exit in mandatoryExits)
@@ -318,6 +319,30 @@ private static IEarlyExit[] CombineEarlyExits(IEnumerable<IEarlyExit> mandatoryE
318319
foreach (IEarlyExit exit in candidateExits)
319320
combined.Add(exit);
320321

322+
// Some early exits are reducible. For example, a LengthLessThan with a value of 3 is worse than one with 4.
323+
// So if there are competing exits, we take the one with the best bounds.
324+
if (combined.Count > 1)
325+
{
326+
IEarlyExit[] exits = combined.ToArray();
327+
328+
for (int i = 0; i < exits.Length; i++)
329+
{
330+
IEarlyExit exit = exits[i];
331+
332+
for (int j = 0; j < exits.Length; j++)
333+
{
334+
if (i == j)
335+
continue;
336+
337+
if (exit.IsWorseThan(exits[j]))
338+
{
339+
combined.Remove(exit);
340+
break;
341+
}
342+
}
343+
}
344+
}
345+
321346
return combined.ToArray();
322347
}
323348

Src/FastData/Generators/Abstracts/IEarlyExit.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ namespace Genbox.FastData.Generators.Abstracts;
66
public interface IEarlyExit
77
{
88
Expression GetExpression(ParameterExpression key);
9+
bool IsWorseThan(IEarlyExit other);
910
}

Src/FastData/Generators/EarlyExits/Abstracts/CharBitmapEarlyExitBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ public Expression GetExpression(ParameterExpression key)
2424
Expression selected = Or(And(lowMasked, lowMask), And(highMasked, highMask));
2525
return Equal(selected, Constant(0UL));
2626
}
27+
28+
public bool IsWorseThan(IEarlyExit other) => false;
2729
}

Src/FastData/Generators/EarlyExits/Abstracts/MethodComparisonEarlyExitBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ public Expression GetExpression(ParameterExpression key)
1313
}
1414

1515
protected abstract BinaryExpression Compare(Expression left, Expression right);
16+
17+
public abstract bool IsWorseThan(IEarlyExit other);
1618
}

Src/FastData/Generators/EarlyExits/Abstracts/StringAffixEarlyExitBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ public Expression GetExpression(ParameterExpression key)
1111
MethodInfo methodInfo = typeof(StringFunctions).GetMethod(Method, [typeof(string), typeof(string)])!;
1212
return Not(Call(methodInfo, Constant(Affix), key));
1313
}
14+
15+
public bool IsWorseThan(IEarlyExit other) => false;
1416
}

Src/FastData/Generators/EarlyExits/Abstracts/ValueComparisonEarlyExitBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ public abstract record ValueComparisonEarlyExitBase<T>(T Value) : IEarlyExit
88
public Expression GetExpression(ParameterExpression key) => Compare(key, Constant(Value, key.Type));
99

1010
protected abstract BinaryExpression Compare(Expression left, Expression right);
11+
12+
public abstract bool IsWorseThan(IEarlyExit other);
1113
}

Src/FastData/Generators/EarlyExits/Exits/CharFirstGreaterThanEarlyExit.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using Genbox.FastData.Generators.Abstracts;
23
using Genbox.FastData.Generators.EarlyExits.Abstracts;
34

45
namespace Genbox.FastData.Generators.EarlyExits.Exits;
@@ -7,4 +8,6 @@ namespace Genbox.FastData.Generators.EarlyExits.Exits;
78
public sealed record CharFirstGreaterThanEarlyExit(char Value) : MethodComparisonEarlyExitBase<char>(Value, nameof(StringFunctions.GetFirstChar))
89
{
910
protected override BinaryExpression Compare(Expression left, Expression right) => GreaterThan(left, right);
11+
12+
public override bool IsWorseThan(IEarlyExit other) => other is CharFirstGreaterThanEarlyExit otherExit && Value > otherExit.Value;
1013
}

Src/FastData/Generators/EarlyExits/Exits/CharFirstLessThanEarlyExit.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using Genbox.FastData.Generators.Abstracts;
23
using Genbox.FastData.Generators.EarlyExits.Abstracts;
34

45
namespace Genbox.FastData.Generators.EarlyExits.Exits;
@@ -7,4 +8,6 @@ namespace Genbox.FastData.Generators.EarlyExits.Exits;
78
public sealed record CharFirstLessThanEarlyExit(char Value) : MethodComparisonEarlyExitBase<char>(Value, nameof(StringFunctions.GetFirstChar))
89
{
910
protected override BinaryExpression Compare(Expression left, Expression right) => LessThan(left, right);
11+
12+
public override bool IsWorseThan(IEarlyExit other) => other is CharFirstLessThanEarlyExit otherExit && Value < otherExit.Value;
1013
}

Src/FastData/Generators/EarlyExits/Exits/CharFirstNotEqualEarlyExit.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using Genbox.FastData.Generators.Abstracts;
23
using Genbox.FastData.Generators.EarlyExits.Abstracts;
34

45
namespace Genbox.FastData.Generators.EarlyExits.Exits;
@@ -7,4 +8,6 @@ namespace Genbox.FastData.Generators.EarlyExits.Exits;
78
public sealed record CharFirstNotEqualEarlyExit(char Value, bool IgnoreCase) : MethodComparisonEarlyExitBase<char>(Value, IgnoreCase ? nameof(StringFunctions.GetFirstCharLower) : nameof(StringFunctions.GetFirstChar))
89
{
910
protected override BinaryExpression Compare(Expression left, Expression right) => NotEqual(left, right);
11+
12+
public override bool IsWorseThan(IEarlyExit other) => false;
1013
}

Src/FastData/Generators/EarlyExits/Exits/CharLastGreaterThanEarlyExit.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using Genbox.FastData.Generators.Abstracts;
23
using Genbox.FastData.Generators.EarlyExits.Abstracts;
34

45
namespace Genbox.FastData.Generators.EarlyExits.Exits;
@@ -7,4 +8,6 @@ namespace Genbox.FastData.Generators.EarlyExits.Exits;
78
public sealed record CharLastGreaterThanEarlyExit(char Value) : MethodComparisonEarlyExitBase<char>(Value, nameof(StringFunctions.GetLastChar))
89
{
910
protected override BinaryExpression Compare(Expression left, Expression right) => GreaterThan(left, right);
11+
12+
public override bool IsWorseThan(IEarlyExit other) => other is CharLastGreaterThanEarlyExit otherExit && Value > otherExit.Value;
1013
}

0 commit comments

Comments
 (0)