Skip to content

Commit 34aee50

Browse files
committed
BonSerialization of Dictionary
1 parent bd0f701 commit 34aee50

File tree

4 files changed

+116
-3
lines changed

4 files changed

+116
-3
lines changed

BTDB/Serialization/BonSerializer.cs

+71-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ enum BonSerializerCmd : byte
6969
NextArray,
7070
InitList,
7171
InitHashSet,
72-
NextHashSet
72+
NextHashSet,
73+
InitDictionary,
74+
NextDictionary,
75+
AddOffset
7376
}
7477

7578
public ref struct BonSerializerCtx
@@ -267,6 +270,24 @@ public void Generate()
267270
return;
268271
}
269272

273+
if (_type.SpecializationOf(typeof(Dictionary<,>)) is { } dictionaryType)
274+
{
275+
_memWriter.WriteUInt8((byte)BonSerializerCmd.InitDictionary);
276+
var keyType = dictionaryType.GetGenericArguments()[0];
277+
var valueType = dictionaryType.GetGenericArguments()[1];
278+
var layout = RawData.GetDictionaryEntriesLayout(keyType, valueType);
279+
_memWriter.WriteUInt8((byte)BonSerializerCmd.AddOffset);
280+
_memWriter.WriteVUInt32(layout.OffsetKey);
281+
WriteCmdByType(null, keyType);
282+
_memWriter.WriteUInt8((byte)BonSerializerCmd.AddOffset);
283+
_memWriter.WriteVUInt32(layout.OffsetValue - layout.OffsetKey);
284+
WriteCmdByType(null, valueType);
285+
_memWriter.WriteUInt8((byte)BonSerializerCmd.AddOffset);
286+
_memWriter.WriteVUInt32(layout.Size - layout.OffsetValue);
287+
_memWriter.WriteUInt8((byte)BonSerializerCmd.NextDictionary);
288+
return;
289+
}
290+
270291
var classMetadata = ReflectionMetadata.FindByType(_type);
271292
if (classMetadata != null)
272293
{
@@ -707,6 +728,55 @@ public unsafe BonSerialize Build()
707728

708729
break;
709730
}
731+
case BonSerializerCmd.AddOffset:
732+
offset += reader.ReadVUInt32();
733+
break;
734+
case BonSerializerCmd.InitDictionary:
735+
{
736+
tempObject2 = Unsafe.As<byte, object>(ref value);
737+
var count = Unsafe.As<byte, int>(ref RawData.Ref(tempObject2,
738+
RawData.Align(8 + 6 * (uint)Unsafe.SizeOf<nint>(), 8)));
739+
tempObject2 = RawData.HashSetEntries(Unsafe.As<HashSet<object>>(tempObject2));
740+
ref readonly var mt = ref RawData.MethodTableRef(tempObject2);
741+
offset = mt.BaseSize - (uint)Unsafe.SizeOf<nint>();
742+
offsetDelta = mt.ComponentSize;
743+
offsetFinal = offset + offsetDelta * (uint)count;
744+
offsetLabel = (uint)reader.GetCurrentPositionWithoutController();
745+
ctx.Builder.StartDictionary();
746+
while (offset < offsetFinal)
747+
{
748+
if (Unsafe.As<byte, int>(ref RawData.Ref(tempObject2, offset + 4)) >= -1) break;
749+
offset += offsetDelta;
750+
}
751+
752+
if (offset >= offsetFinal)
753+
{
754+
ctx.Builder.FinishDictionary();
755+
return;
756+
}
757+
758+
break;
759+
}
760+
case BonSerializerCmd.NextDictionary:
761+
{
762+
while (offset < offsetFinal)
763+
{
764+
if (Unsafe.As<byte, int>(ref RawData.Ref(tempObject2, offset + 4)) >= -1) break;
765+
offset += offsetDelta;
766+
}
767+
768+
if (offset < offsetFinal)
769+
{
770+
reader.SetCurrentPositionWithoutController(offsetLabel);
771+
}
772+
else
773+
{
774+
ctx.Builder.FinishDictionary();
775+
return;
776+
}
777+
778+
break;
779+
}
710780
default:
711781
throw new InvalidDataException("Unknown command in BonSerializer " + (byte)cmd + " at " +
712782
(reader.GetCurrentPosition() - 1));

BTDB/Serialization/RawData.cs

+30
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ public static (uint Offset, uint Size) GetHashSetEntriesLayout(Type memberType)
7979
return (Align(8, sa.Align), sa.Size);
8080
}
8181

82+
public static (uint OffsetKey, uint OffsetValue, uint Size) GetDictionaryEntriesLayout(Type keyType, Type valueType)
83+
{
84+
var saKey = GetSizeAndAlign(keyType);
85+
var saValue = GetSizeAndAlign(valueType);
86+
var sa = Combine((8, 4), saKey, saValue);
87+
var offsetKey = Align(8, sa.Align);
88+
var offsetValue = Align(offsetKey + saKey.Size, saValue.Align);
89+
return (offsetKey, offsetValue, sa.Size);
90+
}
91+
8292
public static uint CombineAlign(uint align1, uint align2)
8393
{
8494
return align1 > align2 ? align1 : align2;
@@ -127,6 +137,26 @@ public static (uint Size, uint Align) GetSizeAndAlign(Type type)
127137
return Combine(GetSizeAndAlign(arguments[0]), GetSizeAndAlign(arguments[1]), GetSizeAndAlign(arguments[2]));
128138
}
129139

140+
if (type == typeof(long) || type == typeof(ulong) || type == typeof(double))
141+
{
142+
return (8, 8);
143+
}
144+
145+
if (type == typeof(int) || type == typeof(uint) || type == typeof(float))
146+
{
147+
return (4, 4);
148+
}
149+
150+
if (type == typeof(short) || type == typeof(ushort) || type == typeof(char) || type == typeof(Half))
151+
{
152+
return (2, 2);
153+
}
154+
155+
if (type == typeof(byte) || type == typeof(sbyte) || type == typeof(bool))
156+
{
157+
return (1, 1);
158+
}
159+
130160
var size = MethodTableOf(type).BaseSize;
131161
return (size, size);
132162
}

BTDBTest/SerializationTests/BonSerializerTest.SerializeDeserializeAllSupportedTypes.approved.txt

+12-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"Self": null,
3636
"DoubleArray": null,
3737
"IntList": null,
38-
"UShortSet": null
38+
"UShortSet": null,
39+
"LongIntDict": null
3940
},
4041
"DoubleArray": [
4142
2.718281828459045,
@@ -49,5 +50,15 @@
4950
"UShortSet": [
5051
666,
5152
12345
53+
],
54+
"LongIntDict": [
55+
[
56+
1111,
57+
2
58+
],
59+
[
60+
3333,
61+
4
62+
]
5263
]
5364
}

BTDBTest/SerializationTests/BonSerializerTest.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class AllSupportedTypes
3232
public double[]? DoubleArray;
3333
public List<int>? IntList;
3434
public HashSet<ushort>? UShortSet;
35+
public Dictionary<long, int>? LongIntDict;
3536
}
3637

3738
[Fact]
@@ -44,7 +45,8 @@ public void SerializeDeserializeAllSupportedTypes()
4445
DateTime = new(2024, 2, 11, 14, 4, 30),
4546
Guid = Guid.Parse("9e251065-0873-49bc-8fd9-266cc9aa39d3"), Float16 = (Half)3.14, Float32 = 3.14f,
4647
Float64 = Math.PI,
47-
Self = new(), DoubleArray = [Math.E, Math.PI], IntList = [1, 20, 300], UShortSet = [666, 12345]
48+
Self = new(), DoubleArray = [Math.E, Math.PI], IntList = [1, 20, 300], UShortSet = [666, 12345],
49+
LongIntDict = new() { { 1111, 2 }, { 3333, 4 } }
4850
};
4951
var builder = new BonBuilder();
5052
BonSerializerFactory.Serialize(ref builder, obj);

0 commit comments

Comments
 (0)