Skip to content

Commit a745015

Browse files
committed
API changes
1 parent 21470d2 commit a745015

21 files changed

+448
-212
lines changed

Benchmarks/Benchmarks.csproj

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@
2121

2222
<ItemGroup>
2323
<Protobuf Include="Protos\structures.proto" GrpcServices="None" />
24+
<Protobuf Include="Protos\structures_big.proto" GrpcServices="None" />
25+
<AdditionalFiles Include="Protos\structures_big_zero.proto" />
2426
</ItemGroup>
2527

2628
<ItemGroup>
27-
<ProjectReference Include="..\ProtoZeroSharp\ProtoZeroSharp.csproj" />
29+
<ProjectReference Include="..\ProtoZeroGenerator\ProtoZeroGenerator.csproj"
30+
OutputItemType="Analyzer"
31+
ReferenceOutputAssembly="false"/>
32+
33+
<ProjectReference Include="..\ProtoZeroSharp\ProtoZeroSharp.csproj" />
2834
</ItemGroup>
2935

3036
<ItemGroup>

Benchmarks/Program.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class Program
66
{
77
static void Main(string[] args)
88
{
9-
var summary = BenchmarkRunner.Run<ProtoZeroVsCanonical>();
9+
//var summary = BenchmarkRunner.Run<ProtoZeroVsCanonical>();
10+
var summary = BenchmarkRunner.Run<ProtoZeroVsCanonicalReader>();
1011
}
1112
}

Benchmarks/ProtoZeroVsCanonical.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public unsafe void PerfectSerializer()
5959

6060
array.CopyTo(output);
6161

62-
array.Free();
62+
array.Dispose();
6363
#endif
6464
}
6565

@@ -68,7 +68,8 @@ public unsafe void PerfectSerializer()
6868
[Arguments(false)]
6969
public void ProtoZeroSharp(bool optimizeSizeOverPerformance)
7070
{
71-
ProtoWriter writer = new ProtoWriter();
71+
ArenaAllocator allocator = new();
72+
ProtoWriter writer = new ProtoWriter(ref allocator);
7273

7374
for (int j = 0; j < 200000; ++j)
7475
{
@@ -96,7 +97,7 @@ public void ProtoZeroSharp(bool optimizeSizeOverPerformance)
9697

9798
writer.CopyTo(output);
9899

99-
writer.Free();
100+
allocator.Dispose();
100101
}
101102

102103
[Benchmark(Baseline = true)]

ProtoZeroGenerator/ProtobufSourceGenerator.cs

+19-21
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ private string GenerateProtobufClasses(string protoFileContent)
249249

250250
if (!oneof.Inline)
251251
{
252-
codeGenerator.OpenBlock($"public ref T Alloc{oneofName}<T>(ref ArenaAllocator memory) where T : unmanaged");
253-
codeGenerator.AppendLine($"var mem = memory.TakeContiguousSpan(sizeof(T));");
254-
codeGenerator.AppendLine($"{oneofName}Data = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(mem));");
252+
codeGenerator.OpenBlock($"public ref T Alloc{oneofName}<T, TAllocator>(ref TAllocator memory) where T : unmanaged where TAllocator : unmanaged, IAllocator");
253+
codeGenerator.AppendLine($"{oneofName}Data = (byte*)memory.Allocate<T>();");
255254
codeGenerator.AppendLine($"return ref Unsafe.AsRef<T>({oneofName}Data);");
256255
codeGenerator.CloseBlock();
257256
}
@@ -260,7 +259,7 @@ private string GenerateProtobufClasses(string protoFileContent)
260259
codeGenerator.AppendLine($"public ref {field.Type.ToCSharpType(false, false)} {field.Name} => ref {oneofName}<{field.Type.ToCSharpType(false, false)}>();");
261260
}
262261

263-
codeGenerator.OpenBlock("internal unsafe void Read(ref ProtoReader reader, ref ArenaAllocator memory)");
262+
codeGenerator.OpenBlock("internal unsafe void Read<TAllocator>(ref ProtoReader reader, ref TAllocator memory) where TAllocator : unmanaged, IAllocator");
264263

265264
foreach (var field in message.Fields.Where(f => f.IsRepeated))
266265
{
@@ -329,8 +328,9 @@ private string GenerateProtobufClasses(string protoFileContent)
329328

330329
foreach (var field in message.Fields.Where(f => f.IsRepeated))
331330
{
331+
var genericType = field.Type.ToCSharpType(false, false);
332332
codeGenerator.AppendLine(
333-
$"{field.Name} = UnmanagedArray<{field.Type.ToCSharpType(false, false)}>.AllocArray({field.Name}_count, ref memory);");
333+
$"{field.Name} = UnmanagedArray<{genericType}>.AllocArray<TAllocator>({field.Name}_count, ref memory);");
334334
codeGenerator.AppendLine($"{field.Name}_count = 0;");
335335
}
336336

@@ -339,7 +339,7 @@ private string GenerateProtobufClasses(string protoFileContent)
339339
var keyType = map.KeyType.ToCSharpType(false, false);
340340
var valueType = map.ValueType.ToCSharpType(false, false);
341341
codeGenerator.AppendLine(
342-
$"{map.Name} = UnmanagedMap<{keyType}, {valueType}>.AllocMap({map.Name}_count, ref memory);");
342+
$"{map.Name} = UnmanagedMap<{keyType}, {valueType}>.AllocMap<TAllocator>({map.Name}_count, ref memory);");
343343
codeGenerator.AppendLine($"{map.Name}_count = 0;");
344344
codeGenerator.AppendLine(
345345
$"{map.Name}.GetUnderlyingArrays(out var {map.Name}_keys, out var {map.Name}_values);");
@@ -368,8 +368,8 @@ string ReadType(ProtoType type, string reader)
368368
BuiltinTypes.Sfixed32 => $"(int){reader}.ReadFixed32()",
369369
BuiltinTypes.Sfixed64 => $"(long){reader}.ReadFixed64()",
370370
BuiltinTypes.Bool => $"{reader}.ReadBool()",
371-
BuiltinTypes.String => $"{reader}.ReadUtf8String(ref memory)",
372-
BuiltinTypes.Bytes => $"{reader}.ReadBytesArray(ref memory)",
371+
BuiltinTypes.String => $"{reader}.ReadUtf8String<TAllocator>(ref memory)",
372+
BuiltinTypes.Bytes => $"{reader}.ReadBytesArray<TAllocator>(ref memory)",
373373
_ => throw new NotImplementedException($"Type {type} is not supported")
374374
};
375375
}
@@ -384,7 +384,7 @@ string ReadType(ProtoType type, string reader)
384384
codeGenerator.AppendLine("var subReader = reader.ReadMessage();");
385385
codeGenerator.AppendLine($"{field.Name}[{field.Name}_count] = default;");
386386
codeGenerator.AppendLine(
387-
$"{field.Name}[{field.Name}_count++].Read(ref subReader, ref memory);");
387+
$"{field.Name}[{field.Name}_count++].Read<TAllocator>(ref subReader, ref memory);");
388388
}
389389
else
390390
{
@@ -416,23 +416,21 @@ string ReadType(ProtoType type, string reader)
416416
if (field.IsOptionalPointer)
417417
{
418418
var fieldType = field.Type.ToCSharpType(false, false);
419-
codeGenerator.AppendLine(
420-
$"var {field.Name}_span = memory.TakeContiguousSpan(sizeof({fieldType}));");
421-
codeGenerator.AppendLine($"{field.Name} = ({fieldType}*)Unsafe.AsPointer(ref MemoryMarshal.GetReference({field.Name}_span));");
419+
codeGenerator.AppendLine($"{field.Name} = memory.Allocate<{fieldType}>();");
422420
codeGenerator.AppendLine($"*{field.Name} = default;");
423-
codeGenerator.AppendLine($"{field.Name}->Read(ref subReader, ref memory);");
421+
codeGenerator.AppendLine($"{field.Name}->Read<TAllocator>(ref subReader, ref memory);");
424422
}
425423
else
426424
{
427425
codeGenerator.AppendLine($"{field.Name}.Value = default;");
428-
codeGenerator.AppendLine($"{field.Name}.Value.Read(ref subReader, ref memory);");
426+
codeGenerator.AppendLine($"{field.Name}.Value.Read<TAllocator>(ref subReader, ref memory);");
429427
codeGenerator.AppendLine($"{field.Name}.HasValue = true;");
430428
}
431429
}
432430
else
433431
{
434432
codeGenerator.AppendLine($"{field.Name} = default;");
435-
codeGenerator.AppendLine($"{field.Name}.Read(ref subReader, ref memory);");
433+
codeGenerator.AppendLine($"{field.Name}.Read<TAllocator>(ref subReader, ref memory);");
436434
}
437435
}
438436
else
@@ -459,7 +457,7 @@ string ReadType(ProtoType type, string reader)
459457
codeGenerator.AppendLine("var subSubReader = subReader.ReadMessage();");
460458
codeGenerator.AppendLine($"{map.Name}_values[{map.Name}_count] = default;");
461459
codeGenerator.AppendLine(
462-
$"{map.Name}_values[{map.Name}_count].Read(ref subSubReader, ref memory);");
460+
$"{map.Name}_values[{map.Name}_count].Read<TAllocator>(ref subSubReader, ref memory);");
463461
}
464462
else
465463
{
@@ -491,7 +489,7 @@ string ReadType(ProtoType type, string reader)
491489
{
492490
codeGenerator.AppendLine($"{oneof.Name}Data.{field.Name} = default;");
493491
codeGenerator.AppendLine($"var subReader = reader.ReadMessage();");
494-
codeGenerator.AppendLine($"{oneof.Name}Data.{field.Name}.Read(ref subReader, ref memory);");
492+
codeGenerator.AppendLine($"{oneof.Name}Data.{field.Name}.Read<TAllocator>(ref subReader, ref memory);");
495493
}
496494
else
497495
{
@@ -500,14 +498,14 @@ string ReadType(ProtoType type, string reader)
500498
}
501499
else
502500
{
503-
codeGenerator.AppendLine($"var mem = memory.TakeContiguousSpan(sizeof({field.Type.ToCSharpType(false, false)}));");
504-
codeGenerator.AppendLine($"{oneof.Name}Data = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(mem));");
505-
codeGenerator.AppendLine($"{field.Type.ToCSharpType(false, false)}* ptr = ({field.Type.ToCSharpType(false, false)}*){oneof.Name}Data;");
501+
var fieldType = field.Type.ToCSharpType(false, false);
502+
codeGenerator.AppendLine($"{field.Type.ToCSharpType(false, false)}* ptr = memory.Allocate<{fieldType}>();");
503+
codeGenerator.AppendLine($"{oneof.Name}Data = (byte*)ptr;");
506504
if (field.Type.IsMessage)
507505
{
508506
codeGenerator.AppendLine("var subReader = reader.ReadMessage();");
509507
codeGenerator.AppendLine("*ptr = default;");
510-
codeGenerator.AppendLine("ptr->Read(ref subReader, ref memory);");
508+
codeGenerator.AppendLine("ptr->Read<TAllocator>(ref subReader, ref memory);");
511509
}
512510
else
513511
{

ProtoZeroSharp.Tests/ProtoWriterTests.cs

+16-20
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
using System.Text;
2-
using ProtoZeroSharp.Tests.Zero;
32

43
namespace ProtoZeroSharp.Tests;
54

65
public class ProtoWriterTests
76
{
8-
private byte[] output = new byte[256 * 1024 * 1024];
9-
107
[Test]
11-
public unsafe void Encode_Zero_Decode_Canonical()
8+
public void Encode_Zero_Decode_Canonical()
129
{
13-
ProtoWriter writer = new ProtoWriter();
10+
ArenaAllocator allocator = new();
11+
ProtoWriter writer = new ProtoWriter(ref allocator);
1412

1513
for (int j = 0; j < 1000; ++j)
1614
{
@@ -36,7 +34,7 @@ public unsafe void Encode_Zero_Decode_Canonical()
3634
var buffer = new byte[writer.GetTotalLength()];
3735
writer.CopyTo(buffer);
3836

39-
writer.Free();
37+
allocator.Dispose();
4038

4139
var msg = Canonical.TestMessage.Parser.ParseFrom(buffer);
4240
}
@@ -56,7 +54,8 @@ public unsafe void Encode_Zero_Decode_Canonical()
5654
public unsafe void Randomized_Read_Write(int seed)
5755
{
5856
Random r = new Random(seed);
59-
ProtoWriter writer = new ProtoWriter();
57+
ArenaAllocator allocator = new();
58+
ProtoWriter writer = new ProtoWriter(ref allocator);
6059
Span<byte> tempBuffer = stackalloc byte[1000];
6160
for (int i = 0; i < tempBuffer.Length; ++i)
6261
tempBuffer[i] = (byte)'a';
@@ -131,21 +130,18 @@ public unsafe void Randomized_Read_Write(int seed)
131130

132131
var encoded = new byte[writer.GetTotalLength()];
133132
writer.CopyTo(encoded);
134-
writer.Free();
133+
allocator.Dispose();
135134

136135
var decoded = Canonical.TestMessage.Parser.ParseFrom(encoded);
137136

138-
var allocator = new ArenaAllocator();
139-
fixed (byte* ptr = encoded)
140-
{
141-
var protoReader = new ProtoReader(ptr, encoded.Length);
142-
var decoded_zero = new Zero.TestMessage();
143-
decoded_zero.Read(ref protoReader, ref allocator);
137+
allocator = new ArenaAllocator();
138+
var protoReader = new ProtoReader(encoded);
139+
var decoded_zero = new Zero.TestMessage();
140+
decoded_zero.Read(ref protoReader, ref allocator);
144141

145-
AssertEquals(decoded, in decoded_zero);
142+
AssertEquals(decoded, in decoded_zero);
146143

147-
allocator.Free();
148-
}
144+
allocator.Dispose();
149145
}
150146

151147
private unsafe void AssertEquals(Canonical.TestMessage canonical, in Zero.TestMessage zero)
@@ -169,7 +165,7 @@ private unsafe void AssertEquals(Canonical.TestMessage canonical, in Zero.TestMe
169165
if (zero.F[i].Name.HasValue)
170166
Assert.That(zero.F[i].Name.Value.ToString(), Is.EqualTo(canonical.F[i].Name));
171167
Assert.That((int)zero.F[i].OneOf->TypeCase, Is.EqualTo((int)canonical.F[i].OneOf.TypeCase));
172-
if (zero.F[i].OneOf->TypeCase == OneOfMessage.TypeOneofCase.Scalar)
168+
if (zero.F[i].OneOf->TypeCase == Zero.OneOfMessage.TypeOneofCase.Scalar)
173169
{
174170
ref var zeroScalar = ref zero.F[i].OneOf->Scalar;
175171
var canonicalScalar = canonical.F[i].OneOf.Scalar;
@@ -184,7 +180,7 @@ private unsafe void AssertEquals(Canonical.TestMessage canonical, in Zero.TestMe
184180
for (int j = 0; j < zeroScalar.Bytes.Length; ++j)
185181
Assert.That(zeroScalar.Bytes[j], Is.EqualTo(canonicalScalar.Bytes[j]));
186182
}
187-
else if (zero.F[i].OneOf->TypeCase == OneOfMessage.TypeOneofCase.OptionalScalar)
183+
else if (zero.F[i].OneOf->TypeCase == Zero.OneOfMessage.TypeOneofCase.OptionalScalar)
188184
{
189185
ref var zeroScalar = ref zero.F[i].OneOf->OptionalScalar;
190186
var canonicalScalar = canonical.F[i].OneOf.OptionalScalar;
@@ -217,7 +213,7 @@ private unsafe void AssertEquals(Canonical.TestMessage canonical, in Zero.TestMe
217213
Assert.That(zeroScalar.Bytes.Value[j], Is.EqualTo(canonicalScalar.Bytes[j]));
218214
}
219215
}
220-
else if (zero.F[i].OneOf->TypeCase == OneOfMessage.TypeOneofCase.RepeatedScalar)
216+
else if (zero.F[i].OneOf->TypeCase == Zero.OneOfMessage.TypeOneofCase.RepeatedScalar)
221217
{
222218
ref var zeroScalar = ref zero.F[i].OneOf->RepeatedScalar;
223219
var canonicalScalar = canonical.F[i].OneOf.RepeatedScalar;

ProtoZeroSharp/ArenaAllocator.Chunk.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public unsafe partial struct ArenaAllocator
88
/// <summary>
99
/// Single chunk of contiguous memory.
1010
/// </summary>
11-
public struct Chunk
11+
internal struct Chunk
1212
{
1313
public Chunk* Next;
1414
public int Used;
@@ -97,7 +97,7 @@ public static void FreeChunksChain(Chunk* first)
9797
}
9898
}
9999

100-
public struct ChunkOffset
100+
internal struct ChunkOffset
101101
{
102102
public readonly Chunk* Chunk;
103103
public readonly int Offset;

0 commit comments

Comments
 (0)