Skip to content

Commit 9e09d6e

Browse files
committed
Add support for multiple ranges in RangeStructure
1 parent f548f40 commit 9e09d6e

15 files changed

Lines changed: 249 additions & 27 deletions

File tree

Src/FastData.Generator.CPlusPlus/Templates/Range.tt

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,41 @@
22
<#@ parameter type="Genbox.FastData.Generator.Template.TemplateData.RangeTemplateData" name="Data" #>
33

44
<#
5-
string minLabel = TypeMap.ToValueLabel(Data.Min);
6-
string maxLabel = TypeMap.ToValueLabel(Data.Max);
5+
if (Data.RangeCount > 1)
6+
{
7+
#>
8+
<#= FieldModifier(true) #>std::array<<#= KeyTypeName #>, <#= Data.RangeCount.ToStringInvariant() #>> range_starts = {
9+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.Start), 8) #>
10+
};
11+
12+
<#= FieldModifier(true) #>std::array<<#= KeyTypeName #>, <#= Data.RangeCount.ToStringInvariant() #>> range_ends = {
13+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.End), 8) #>
14+
};
15+
<#
16+
}
717
#>
818
public:
919
<#= MethodAttribute #>
1020
<#= MethodModifier(true) #>bool contains(const <#= KeyTypeName #> key)<#= PostMethodModifier #> {
1121
<#= GetMethodHeader(MethodType.Contains) #>
12-
return <#= LookupKeyName #> >= <#= minLabel #> && <#= LookupKeyName #> <= <#= maxLabel #>;
22+
<#
23+
if (Data.RangeCount == 1)
24+
{
25+
#>
26+
return <#= LookupKeyName #> >= <#= TypeMap.ToValueLabel(Data.Ranges[0].Start) #> && <#= LookupKeyName #> <= <#= TypeMap.ToValueLabel(Data.Ranges[0].End) #>;
27+
<#
28+
}
29+
else
30+
{
31+
#>
32+
for (size_t i = 0; i < <#= Data.RangeCount.ToStringInvariant() #>; ++i) {
33+
if (<#= LookupKeyName #> >= range_starts[i] && <#= LookupKeyName #> <= range_ends[i])
34+
return true;
35+
}
36+
37+
return false;
38+
<#
39+
}
40+
#>
1341
}
1442
<#@ include file="Includes\Footer.ttinclude" #>
Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,44 @@
11
<#@ include file="Includes\Header.ttinclude" #>
22
<#@ parameter type="Genbox.FastData.Generator.Template.TemplateData.RangeTemplateData" name="Data" #>
33

4+
<#
5+
if (Data.RangeCount > 1)
6+
{
7+
#>
8+
<#= FieldModifier #><#= KeyTypeName #>[] _rangeStarts = new <#= KeyTypeName #>[] {
9+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.Start), 8) #>
10+
};
11+
12+
<#= FieldModifier #><#= KeyTypeName #>[] _rangeEnds = new <#= KeyTypeName #>[] {
13+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.End), 8) #>
14+
};
15+
<#
16+
}
17+
#>
418
<#= MethodAttribute #>
519
<#= MethodModifier #>bool Contains(<#= KeyTypeName #> key)
620
{
721
<#= GetMethodHeader(MethodType.Contains) #>
822

9-
return <#= LookupKeyName #> >= <#= TypeMap.ToValueLabel(Data.Min) #> && <#= LookupKeyName #> <= <#= TypeMap.ToValueLabel(Data.Max) #>;
23+
<#
24+
if (Data.RangeCount == 1)
25+
{
26+
#>
27+
return <#= LookupKeyName #> >= <#= TypeMap.ToValueLabel(Data.Ranges[0].Start) #> && <#= LookupKeyName #> <= <#= TypeMap.ToValueLabel(Data.Ranges[0].End) #>;
28+
<#
29+
}
30+
else
31+
{
32+
#>
33+
for (int i = 0; i < <#= Data.RangeCount.ToStringInvariant() #>; i++)
34+
{
35+
if (<#= LookupKeyName #> >= _rangeStarts[i] && <#= LookupKeyName #> <= _rangeEnds[i])
36+
return true;
37+
}
38+
39+
return false;
40+
<#
41+
}
42+
#>
1043
}
1144
<#@ include file="Includes\Footer.ttinclude" #>

Src/FastData.Generator.Rust/Templates/Range.tt

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,41 @@
33
<#@ parameter type="Genbox.FastData.Generator.Template.TemplateData.RangeTemplateData" name="Data" #>
44

55
<#
6-
string minLabel = TypeMap.ToValueLabel(Data.Min);
7-
string maxLabel = TypeMap.ToValueLabel(Data.Max);
6+
if (Data.RangeCount > 1)
7+
{
8+
#>
9+
<#= FieldModifier #>RANGE_STARTS: [<#= StoredKeyTypeName #>; <#= Data.RangeCount.ToStringInvariant() #>] = [
10+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.Start), 8) #>
11+
];
12+
13+
<#= FieldModifier #>RANGE_ENDS: [<#= StoredKeyTypeName #>; <#= Data.RangeCount.ToStringInvariant() #>] = [
14+
<#= FormatHelper.FormatColumns(Data.Ranges, x => TypeMap.ToValueLabel(x.End), 8) #>
15+
];
16+
<#
17+
}
818
#>
919
<#= MethodAttribute #>
1020
<#= MethodModifier #>fn contains(key: <#= InputKeyTypeName #>) -> bool {
1121
<#= GetMethodHeader(MethodType.Contains) #>
12-
<#= LookupKeyName #> >= <#= minLabel #> && <#= LookupKeyName #> <= <#= maxLabel #>
22+
<#
23+
if (Data.RangeCount == 1)
24+
{
25+
#>
26+
<#= LookupKeyName #> >= <#= TypeMap.ToValueLabel(Data.Ranges[0].Start) #> && <#= LookupKeyName #> <= <#= TypeMap.ToValueLabel(Data.Ranges[0].End) #>
27+
<#
28+
}
29+
else
30+
{
31+
#>
32+
for i in 0..<#= Data.RangeCount.ToStringInvariant() #> {
33+
if <#= LookupKeyName #> >= Self::RANGE_STARTS[i] && <#= LookupKeyName #> <= Self::RANGE_ENDS[i] {
34+
return true;
35+
}
36+
}
37+
38+
false
39+
<#
40+
}
41+
#>
1342
}
1443
<#@ include file="Includes\Footer.ttinclude" #>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Genbox.FastData.Generator.Template.TemplateData;
2+
3+
public sealed class RangeEntryTemplateData
4+
{
5+
public required object Start { get; init; }
6+
public required object End { get; init; }
7+
}

Src/FastData.Generator.Template/TemplateData/RangeTemplateData.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ namespace Genbox.FastData.Generator.Template.TemplateData;
44

55
public sealed class RangeTemplateData : ITemplateData
66
{
7-
public required object Min { get; init; }
8-
public required object Max { get; init; }
7+
public required RangeEntryTemplateData[] Ranges { get; init; }
8+
public required int RangeCount { get; init; }
99
}

Src/FastData.Generator.Template/TemplatedCodeGenerator.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Genbox.FastData.Enums;
1+
using Genbox.FastData.Enums;
22
using Genbox.FastData.Generator.Abstracts;
33
using Genbox.FastData.Generator.Template.Abstracts;
44
using Genbox.FastData.Generator.Template.Extensions;
@@ -109,10 +109,22 @@ public string Generate<TKey, TValue>(GeneratorConfigBase genCfg, IContext contex
109109
};
110110

111111
case RangeContext<TKey> rangeCtx:
112+
ReadOnlySpan<(TKey Start, TKey End)> ranges = rangeCtx.Ranges.Span;
113+
RangeEntryTemplateData[] rangeEntries = new RangeEntryTemplateData[ranges.Length];
114+
115+
for (int i = 0; i < ranges.Length; i++)
116+
{
117+
rangeEntries[i] = new RangeEntryTemplateData
118+
{
119+
Start = ranges[i].Start!,
120+
End = ranges[i].End!
121+
};
122+
}
123+
112124
return new RangeTemplateData
113125
{
114-
Min = rangeCtx.Min,
115-
Max = rangeCtx.Max
126+
Ranges = rangeEntries,
127+
RangeCount = rangeEntries.Length
116128
};
117129

118130
case KeyLengthContext<TValue> klCtx:

Src/FastData.InternalShared/Helpers/TestVectorHelper.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,14 @@ public static IEnumerable<ITestVector> GetValueTestVectors()
103103
foreach (ITestVector testVector in GenerateTestVectors([[1f, 2f, 3f, 4f, 5f]], "interpolation", typeof(BinarySearchInterpolationStructure<,>)))
104104
yield return testVector;
105105

106-
// Test range/bitset support. Keys have to be without gaps for range to kick in.
106+
// Test range/bitset support. RangeStructure is selected when range count is low.
107107
foreach (ITestVector testVector in GenerateTestVectors([[1, 2, 3, 4, 5]], "range_bitset", typeof(RangeStructure<,>), typeof(BitSetStructure<,>)))
108108
yield return testVector;
109109

110+
// Test range support for non-consecutive data.
111+
foreach (ITestVector testVector in GenerateTestVectors([[1, 2, 4, 7, 8, 10]], "range_gaps", typeof(RangeStructure<,>)))
112+
yield return testVector;
113+
110114
// Test prefix/suffix support
111115
foreach (ITestVector testVector in GenerateTestVectors([["pretext", "prefetch", "prefix"], ["suffix", "prefix"]], "prefix_suffix", typeof(ArrayStructure<,>)))
112116
yield return testVector;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// @generated
2+
// This file is auto-generated. Do not edit manually.
3+
// Structure: Range
4+
#include <array>
5+
#include <cstring>
6+
#include <cstdint>
7+
#include <limits>
8+
#include <string_view>
9+
10+
11+
class fastdata final {
12+
13+
14+
static constexpr std::array<int32_t, 4> range_starts = {
15+
1, 4, 7, 10
16+
};
17+
18+
static constexpr std::array<int32_t, 4> range_ends = {
19+
2, 4, 8, 10
20+
};
21+
public:
22+
[[nodiscard]]
23+
static constexpr bool contains(const int32_t key) noexcept {
24+
25+
for (size_t i = 0; i < 4; ++i) {
26+
if (key >= range_starts[i] && key <= range_ends[i])
27+
return true;
28+
}
29+
30+
return false;
31+
}
32+
33+
static constexpr size_t item_count = 6;
34+
static constexpr int32_t min_key = 1;
35+
static constexpr int32_t max_key = 10;
36+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// <auto-generated />
2+
// This file is auto-generated. Do not edit manually.
3+
// Structure: Range
4+
#nullable enable
5+
using System;
6+
using System.Runtime.CompilerServices;
7+
using System.Runtime.InteropServices;
8+
9+
internal static class FastData
10+
{
11+
12+
13+
private static readonly int[] _rangeStarts = new int[] {
14+
1, 4, 7, 10
15+
};
16+
17+
private static readonly int[] _rangeEnds = new int[] {
18+
2, 4, 8, 10
19+
};
20+
21+
public static bool Contains(int key)
22+
{
23+
24+
25+
for (int i = 0; i < 4; i++)
26+
{
27+
if (key >= _rangeStarts[i] && key <= _rangeEnds[i])
28+
return true;
29+
}
30+
31+
return false;
32+
}
33+
34+
public const int ItemCount = 6;
35+
public const int MinKey = 1;
36+
public const int MaxKey = 10;
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! This file is auto-generated. Do not edit manually.
2+
//! Structure: Range
3+
#![allow(non_camel_case_types)]
4+
#![allow(unused_parens)]
5+
#![allow(missing_docs)]
6+
#![allow(unused_imports)]
7+
#![allow(unused_variables)]
8+
#![allow(unused_unsafe)]
9+
use std::ptr;
10+
11+
12+
pub struct fastdata;
13+
impl fastdata {
14+
15+
const RANGE_STARTS: [i32; 4] = [
16+
1, 4, 7, 10
17+
];
18+
19+
const RANGE_ENDS: [i32; 4] = [
20+
2, 4, 8, 10
21+
];
22+
#[must_use]
23+
pub fn contains(key: i32) -> bool {
24+
25+
for i in 0..4 {
26+
if key >= Self::RANGE_STARTS[i] && key <= Self::RANGE_ENDS[i] {
27+
return true;
28+
}
29+
}
30+
31+
false
32+
}
33+
34+
pub const ITEM_COUNT: usize = 6;
35+
pub const MIN_KEY: i32 = 1;
36+
pub const MAX_KEY: i32 = 10;
37+
}

0 commit comments

Comments
 (0)