-
Notifications
You must be signed in to change notification settings - Fork 7
Serialization
Andrey edited this page Sep 24, 2023
·
3 revisions
A zero-allocation alternative for Split method on string
For example
var input = "x1,x2,x3,x4";
var separator = ",";
var parser = new LLParserSpan(separator, input);
There are a few things you can do here
Console.WriteLine(parser.GetCountOfValues());
Output:
4
ReadOnlySpan<char> value;
while ((value = parser.Next()) != null)
Console.WriteLine(value.ToString());
Output:
x1
x2
x3
x4
while (parser.TryParseNext(out var key, out var value))
Console.WriteLine($"{key} = {value}");
Output:
x1 = x2
x3 = x4
Benchmark
Method | ItemsCount | ValueLength | Mean | Error | StdDev | Code Size | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|---|---|---|
LLParserSpan_EnumerateValues | 10000 | 1 | 63.53 us | 1.240 us | 1.967 us | 341 B | - | - | - |
Split_EnumerateValues | 10000 | 1 | 293.70 us | 5.780 us | 8.289 us | 880 B | 3.4180 | 0.9766 | 320025 B |
LLParserSpan_EnumerateValues | 10000 | 5 | 176.33 us | 2.805 us | 2.624 us | 341 B | - | - | - |
Split_EnumerateValues | 10000 | 5 | 296.32 us | 5.674 us | 10.516 us | 880 B | 4.3945 | 1.9531 | 400025 B |
LLParserSpan_EnumerateValues | 10000 | 20 | 688.86 us | 10.436 us | 9.252 us | 341 B | - | - | 1 B |
Split_EnumerateValues | 10000 | 20 | 542.46 us | 10.635 us | 18.904 us | 880 B | 7.8125 | 2.9297 | 720025 B |
Uses for serialize and deserialize classes in GeometryDash csv like format.
Made to convert any contracts as quickly as possible. Uses the expression inside compilation
If you want to create your custom contract. You can define a class, like this
[Sense(":")]
public class MyGameContract : GameObject
{
[GameProperty("1", Order = 1)]
public string Name { get; set; }
[GameProperty("2", Order = 2)]
public PlayerSpeed Speed { get; set; }
[GameProperty("4", Order = 3)]
[ArraySense(",")]
public int[] Groups { get; set; }
}
There are several points here
- Defined class should be inherited from
GameObject
.
This base class guarantees the safety of undefined fields in contact. If you define a property with a non-existent key3
, then deserialize and serialize back, then the property will remain, despite the fact that it is missing in the definition. - Should add
SenseAttribute
to the defined class.
This attribute tells which separator is used for the contract in csv like format.
e.g. current contract will be serialized as1:Player:2:1:3:NULL
- Each property used in contract will must contain the
GamePropertyAttribute
.
This attribute tells, how serialize and deserialize a property.
Applies to properties and fields - Some arrays or
List<T>
can define as GameProperty too.
But you should addArraySenseAttribute
to it. Because csv like format nedded separator for serialize each item in your collection
Create a new instance of TypeDescriptor<T>
.
not recomended way, because each descriptor creates for a long time and has caches
var descriptor = new TypeDescriptor<MyGameContract>();
// Create a new instance of MyGameContract
var instance = descriptor.Create();
// Or create a new instance of `MyGameContract` from the string representation (deserialize)
instance = descriptor.Create("1:Player:2:1:3:NULL");
// some changes...
instance.Name = "Folleach";
// Serialize to the string
var builder = new StringBuilder();
instance.CopyTo(instance, builder);
Console.WriteLine(builder.ToString()); // will return 1:Folleach:2:1:3:NULL
Also you can define some arrays or List<T>
in your contract.