Skip to content

Commit f08dd04

Browse files
committed
Add value support to KeyLength
1 parent d87aa96 commit f08dd04

File tree

9 files changed

+115
-189
lines changed

9 files changed

+115
-189
lines changed

Src/FastData.Generator.CPlusPlus.Tests/Features/ObjectSupportTest-KeyLengthStructure_String_3.verified.txt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,22 @@
66
#include <limits>
77
#include <string_view>
88

9+
struct Person {
10+
int32_t age;
11+
std::string_view name;
12+
const Person* other;
13+
14+
Person(const int32_t age, const std::string_view name, const Person* other) : age(age), name(name), other(other) { }
15+
};
916
class KeyLengthStructure_String_3 final
1017
{
11-
static constexpr std::array<std::string_view, 3> entries = {
18+
static constexpr std::array<int32_t, 3> offsets = {
19+
0, 1, 2
20+
};
21+
static inline std::array<Person*, 3> values = {
22+
new Person(1, "Bob", new Person(4, "Anna", nullptr)), new Person(2, "Billy", nullptr), new Person(3, "Bibi", nullptr)
23+
};
24+
static constexpr std::array<std::string_view, 3> keys = {
1225
"a", "aa", "aaa"
1326
};
1427

@@ -19,9 +32,24 @@ public:
1932
if (const size_t len = key.length(); len < 1u || len > 3u)
2033
return false;
2134

22-
return key == entries[key.length() - 1];
35+
return key == keys[key.length() - 1];
36+
}[[nodiscard]]
37+
static bool try_lookup(const std::string_view key, const Person*& value) noexcept
38+
{
39+
if (const size_t len = key.length(); len < 1u || len > 3u)
40+
return false;
41+
42+
size_t idx = key.length() - 1;
43+
if (key == keys[idx])
44+
{
45+
value = values[offsets[idx]];
46+
return true;
2347
}
2448

49+
value = nullptr;
50+
return false;
51+
}
52+
2553
static constexpr size_t item_count = 3;
2654
static constexpr size_t min_key_length = 1;
2755
static constexpr size_t max_key_length = 3;

Src/FastData.Generator.CPlusPlus.Tests/Vectors/KeyLengthStructure_String_7.verified.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class KeyLengthStructure_String_7 final
1010
{
11-
static constexpr std::array<std::string_view, 8> entries = {
11+
static constexpr std::array<std::string_view, 8> keys = {
1212
"aaa", "", "aaaaa", "aaaaaa", "aaaaaaa", "aaaaaaaa", "aaaaaaaaa", "aaaaaaaaaa"
1313
};
1414

@@ -19,7 +19,7 @@ public:
1919
if ((1012ULL & (1ULL << (key.length() - 1))) == 0)
2020
return false;
2121

22-
return key == entries[key.length() - 3];
22+
return key == keys[key.length() - 3];
2323
}
2424

2525
static constexpr size_t item_count = 7;

Src/FastData.Generator.CPlusPlus/CPlusPlusCodeGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ protected override void AppendFooter<T>(StringBuilder sb, GeneratorConfig<T> gen
8181
ConditionalContext<TKey, TValue> x => new ConditionalCode<TKey, TValue>(x, Shared),
8282
HashTableContext<TKey, TValue> x => new HashTableCode<TKey, TValue>(x, Shared),
8383
HashTablePerfectContext<TKey, TValue> x => new HashTablePerfectCode<TKey, TValue>(x, Shared),
84-
KeyLengthContext<TValue> x => new KeyLengthCode<TKey, TValue>(x),
84+
KeyLengthContext<TValue> x => new KeyLengthCode<TKey, TValue>(x, Shared),
8585
_ => null
8686
};
8787
}
Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,71 @@
11
using Genbox.FastData.Generator.CPlusPlus.Internal.Framework;
2+
using Genbox.FastData.Generator.Enums;
23
using Genbox.FastData.Generator.Extensions;
34
using Genbox.FastData.Generators.Contexts;
45

56
namespace Genbox.FastData.Generator.CPlusPlus.Internal.Generators;
67

7-
internal sealed class KeyLengthCode<TKey, TValue>(KeyLengthContext<TValue> ctx) : CPlusPlusOutputWriter<TKey>
8+
internal sealed class KeyLengthCode<TKey, TValue>(KeyLengthContext<TValue> ctx, SharedCode shared) : CPlusPlusOutputWriter<TKey>
89
{
9-
public override string Generate() => ctx.LengthsAreUniq ? GenerateUniq() : GenerateNormal();
10-
11-
private string GenerateUniq()
10+
public override string Generate()
1211
{
13-
string?[] lengths = ctx.Lengths.Skip((int)ctx.MinLength).Select(x => x?.FirstOrDefault()).ToArray();
14-
15-
return $$"""
16-
{{FieldModifier}}std::array<{{KeyTypeName}}, {{lengths.Length.ToStringInvariant()}}> entries = {
17-
{{FormatColumns(lengths, ToValueLabel)}}
18-
};
19-
20-
public:
21-
{{MethodAttribute}}
22-
{{MethodModifier}}bool contains(const {{KeyTypeName}} key){{PostMethodModifier}}
23-
{
24-
{{EarlyExits}}
25-
26-
return {{GetEqualFunction("key", $"entries[key.length() - {ctx.MinLength.ToStringInvariant()}]")}};
27-
}
28-
""";
29-
}
12+
StringBuilder sb = new StringBuilder();
3013

31-
private string GenerateNormal()
32-
{
33-
List<string>?[] lengths = ctx.Lengths.Skip((int)ctx.MinLength).Take((int)(ctx.MaxLength - ctx.MinLength + 1)).ToArray();
34-
35-
return $$"""
36-
{{FieldModifier}}std:array<std:vector<{{KeyTypeName}}>, {{lengths.Length.ToStringInvariant()}}> entries = {
37-
{{FormatList(lengths, RenderMany, ",\n")}}
38-
};
39-
40-
public:
41-
{{MethodAttribute}}
42-
{{MethodModifier}}bool contains(const {{KeyTypeName}}& key){{PostMethodModifier}}
43-
{
44-
{{EarlyExits}}
45-
std::vector<{{KeyTypeName}}> bucket = entries[key.length() - {{ctx.MinLength.ToStringInvariant()}}];
46-
47-
if (bucket == nullptr)
48-
return false;
49-
50-
foreach ({{KeyTypeName}} str in bucket)
51-
{
52-
if ({{GetEqualFunction("str", "key")}})
53-
return true;
54-
}
55-
56-
return false;
57-
}
58-
""";
59-
}
14+
if (ctx.Values != null)
15+
{
16+
shared.Add("classes", CodePlacement.Before, GetObjectDeclarations<TValue>());
17+
18+
sb.Append($$"""
19+
{{FieldModifier}}std::array<int32_t, {{ctx.ValueOffsets.Length}}> offsets = {
20+
{{FormatColumns(ctx.ValueOffsets, static x => x.ToStringInvariant())}}
21+
};
22+
23+
""");
24+
25+
sb.Append($$"""
26+
static inline std::array<{{ValueTypeName}}*, {{ctx.Values.Length}}> values = {
27+
{{FormatColumns(ctx.Values, ToValueLabel)}}
28+
};
29+
30+
""");
31+
}
6032

61-
private string RenderMany(List<string>? x) => x == null ? " \"\"" : $"new [] {{ {string.Join(",", x.Select(ToValueLabel))} }}";
33+
sb.Append($$"""
34+
{{FieldModifier}}std::array<{{KeyTypeName}}, {{ctx.Lengths.Length.ToStringInvariant()}}> keys = {
35+
{{FormatColumns(ctx.Lengths, ToValueLabel)}}
36+
};
37+
38+
public:
39+
{{MethodAttribute}}
40+
{{MethodModifier}}bool contains(const {{KeyTypeName}} key){{PostMethodModifier}}
41+
{
42+
{{EarlyExits}}
43+
44+
return {{GetEqualFunction("key", $"keys[key.length() - {ctx.MinLength.ToStringInvariant()}]")}};
45+
}
46+
""");
47+
48+
if (ctx.Values != null)
49+
{
50+
sb.Append($$"""
51+
{{MethodAttribute}}
52+
{{MethodModifier}}bool try_lookup(const {{KeyTypeName}} key, const {{ValueTypeName}}*& value){{PostMethodModifier}}
53+
{
54+
{{EarlyExits}}
55+
56+
size_t idx = key.length() - {{ctx.MinLength.ToStringInvariant()}};
57+
if ({{GetEqualFunction("key", "keys[idx]")}})
58+
{
59+
value = values[offsets[idx]];
60+
return true;
61+
}
62+
63+
value = nullptr;
64+
return false;
65+
}
66+
""");
67+
}
68+
69+
return sb.ToString();
70+
}
6271
}

Src/FastData.Generator.CSharp/CSharpCodeGeneratorConfig.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@ public sealed class CSharpCodeGeneratorConfig(string className)
1212
public ClassVisibility ClassVisibility { get; set; } = ClassVisibility.Internal;
1313
public ClassType ClassType { get; set; } = ClassType.Static;
1414
public CSharpOptions GeneratorOptions { get; set; }
15-
public BranchType KeyLengthUniqBranchType { get; set; } = BranchType.If;
1615
public BranchType ConditionalBranchType { get; set; } = BranchType.Switch;
1716
}

Src/FastData.Generator.CSharp/Internal/Generators/KeyLengthCode.cs

Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -9,84 +9,19 @@ internal sealed class KeyLengthCode<TKey, TValue>(KeyLengthContext<TValue> ctx,
99
{
1010
public override string Generate()
1111
{
12-
if (ctx.LengthsAreUniq)
13-
{
14-
//There is an assumptions, that when LengthsAreUniq is true, all the length buckets only contain one item
15-
return cfg.KeyLengthUniqBranchType switch
16-
{
17-
BranchType.If => GenerateUniqIf(),
18-
BranchType.Switch => GenerateUniqSwitch(),
19-
_ => throw new InvalidOperationException("Invalid branch type: " + cfg.KeyLengthUniqBranchType)
20-
};
21-
}
22-
23-
return GenerateNormal();
24-
}
25-
26-
private string GenerateUniqIf() =>
27-
$$"""
28-
{{FieldModifier}}{{KeyTypeName}}[] _entries = new {{KeyTypeName}}[] {
29-
{{FormatColumns(ctx.Lengths.AsReadOnlySpan((int)ctx.MinLength), x => ToValueLabel(x?.FirstOrDefault()))}}
30-
};
31-
32-
{{MethodAttribute}}
33-
{{MethodModifier}}bool Contains({{KeyTypeName}} key)
34-
{
35-
{{EarlyExits}}
36-
37-
return {{GetEqualFunction("key", $"_entries[key.Length - {ctx.MinLength.ToStringInvariant()}]")}};
38-
}
39-
""";
40-
41-
private string GenerateUniqSwitch()
42-
{
43-
string[] filtered = ctx.Lengths.Where(x => x != null).Select(x => x![0]).ToArray();
44-
4512
return $$"""
46-
{{MethodAttribute}}
47-
{{MethodModifier}}bool Contains({{KeyTypeName}} key)
48-
{
49-
{{EarlyExits}}
50-
51-
switch (key.Length)
52-
{
53-
{{FormatList(filtered, x => $"""
54-
case {x.Length}:
55-
return {GetEqualFunction("key", ToValueLabel(x))};
56-
""")}}
57-
default:
58-
return false;
59-
}
60-
}
61-
""";
62-
}
63-
64-
private string GenerateNormal()
65-
{
66-
return $$"""
67-
{{FieldModifier}}{{KeyTypeName}}[]?[] _entries = new {{KeyTypeName}}[]?[] {
68-
{{FormatList(ctx.Lengths.AsReadOnlySpan((int)ctx.MinLength, (int)(ctx.MaxLength - ctx.MinLength + 1)), RenderMany, ",\n")}}
13+
{{FieldModifier}}{{KeyTypeName}}[] _entries = new {{KeyTypeName}}[] {
14+
{{FormatColumns(ctx.Lengths, ToValueLabel)}}
6915
};
7016
7117
{{MethodAttribute}}
7218
{{MethodModifier}}bool Contains({{KeyTypeName}} key)
7319
{
7420
{{EarlyExits}}
75-
{{KeyTypeName}}[]? bucket = _entries[key.Length - {{ctx.MinLength}}];
76-
77-
if (bucket == null)
78-
return false;
79-
80-
foreach ({{KeyTypeName}} str in bucket)
81-
{
82-
if ({{GetEqualFunction("key", "str")}})
83-
return true;
84-
}
8521
86-
return false;
22+
return {{GetEqualFunction("key", $"_entries[key.Length - {ctx.MinLength.ToStringInvariant()}]")}};
8723
}
8824
""";
89-
}
9025

91-
private string RenderMany(List<string>? x) => x == null ? " null" : $"new [] {{{string.Join(",", x.Select(ToValueLabel))}}}";
26+
}
9227
}

Src/FastData.Generator.Rust/Internal/Generators/KeyLengthCode.cs

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,9 @@ namespace Genbox.FastData.Generator.Rust.Internal.Generators;
66

77
internal sealed class KeyLengthCode<TKey, TValue>(KeyLengthContext<TValue> ctx) : RustOutputWriter<TKey>
88
{
9-
public override string Generate() => ctx.LengthsAreUniq ? GenerateUniq() : GenerateNormal();
10-
11-
private string GenerateUniq()
9+
public override string Generate()
1210
{
13-
string?[] lengths = ctx.Lengths
14-
.Skip((int)ctx.MinLength)
15-
.Select(x => x?.FirstOrDefault())
16-
.ToArray();
11+
string?[] lengths = ctx.Lengths;
1712

1813
return $$"""
1914
{{FieldModifier}}const ENTRIES: [{{KeyTypeName}}; {{lengths.Length.ToStringInvariant()}}] = [
@@ -27,39 +22,4 @@ private string GenerateUniq()
2722
}
2823
""";
2924
}
30-
31-
private string GenerateNormal()
32-
{
33-
List<string>?[] lengths = ctx.Lengths
34-
.Skip((int)ctx.MinLength)
35-
.Take((int)(ctx.MaxLength - ctx.MinLength + 1))
36-
.ToArray();
37-
38-
return $$"""
39-
{{FieldModifier}}const ENTRIES: [Vec<{{KeyTypeName}}>; {{lengths.Length}}] = [
40-
{{FormatList(lengths, RenderMany, ",\n")}}
41-
];
42-
43-
{{MethodAttribute}}
44-
{{MethodModifier}}fn contains(key: &{{KeyTypeName}}) -> bool {
45-
{{EarlyExits}}
46-
let idx = (key.len() - {{ctx.MinLength.ToStringInvariant()}}) as usize;
47-
let bucket = &Self::ENTRIES[idx];
48-
49-
if bucket.is_empty() {
50-
false
51-
}
52-
53-
for item in bucket.iter() {
54-
if item == key {
55-
true
56-
}
57-
}
58-
59-
false
60-
}
61-
""";
62-
}
63-
64-
private string RenderMany(List<string>? x) => x == null ? "Vec::new()" : $"vec![{string.Join(", ", x.Select(ToValueLabel))}]";
6525
}

Src/FastData/Generators/Contexts/KeyLengthContext.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,15 @@ namespace Genbox.FastData.Generators.Contexts;
44

55
/// <summary>Provides a context for key length-based data structures.</summary>
66
/// <param name="lengths">An array of lists containing string lengths.</param>
7-
/// <param name="lengthsAreUniq">Indicates whether all lengths are unique.</param>
87
/// <param name="minLength">The minimum string length.</param>
9-
/// <param name="maxLength">The maximum string length.</param>
10-
public sealed class KeyLengthContext<TValue>(List<string>?[] lengths, bool lengthsAreUniq, uint minLength, uint maxLength, TValue[]? values) : IContext<TValue>
8+
public sealed class KeyLengthContext<TValue>(string?[] lengths, uint minLength, TValue[]? values, int[] valueOffsets) : IContext<TValue>
119
{
1210
/// <summary>Gets the array of lists containing string lengths.</summary>
13-
public List<string>?[] Lengths { get; } = lengths;
14-
15-
/// <summary>Gets a value indicating whether all lengths are unique.</summary>
16-
public bool LengthsAreUniq { get; } = lengthsAreUniq;
11+
public string?[] Lengths { get; } = lengths;
1712

1813
/// <summary>Gets the minimum string length.</summary>
1914
public uint MinLength { get; } = minLength;
2015

21-
/// <summary>Gets the maximum string length.</summary>
22-
public uint MaxLength { get; } = maxLength;
2316
public TValue[]? Values { get; } = values;
17+
public int[] ValueOffsets { get; } = valueOffsets;
2418
}

0 commit comments

Comments
 (0)