| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| using System.Collections; |
| using System.Collections.Concurrent; |
| |
| namespace Apache.Fory; |
| |
| internal static class PrimitiveDictionaryHeader |
| { |
| public static void WriteMapChunkTypeInfo( |
| WriteContext context, |
| bool keyDeclared, |
| bool valueDeclared, |
| TypeId keyTypeId, |
| TypeId valueTypeId) |
| { |
| if (!keyDeclared) |
| { |
| context.Writer.WriteUInt8((byte)keyTypeId); |
| } |
| |
| if (!valueDeclared) |
| { |
| context.Writer.WriteUInt8((byte)valueTypeId); |
| } |
| } |
| } |
| |
| internal interface IPrimitiveDictionaryCodec<T> |
| { |
| static abstract TypeId WireTypeId { get; } |
| |
| static abstract bool IsNullable { get; } |
| |
| static abstract T DefaultValue { get; } |
| |
| static abstract bool IsNone(T value); |
| |
| static abstract void Write(WriteContext context, T value); |
| |
| static abstract T Read(ReadContext context); |
| } |
| |
| internal readonly struct StringPrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<string> |
| { |
| public static TypeId WireTypeId => TypeId.String; |
| |
| public static bool IsNullable => true; |
| |
| public static string DefaultValue => null!; |
| |
| public static bool IsNone(string value) => value is null; |
| |
| public static void Write(WriteContext context, string value) |
| { |
| StringSerializer.WriteString(context, value ?? string.Empty); |
| } |
| |
| public static string Read(ReadContext context) |
| { |
| return StringSerializer.ReadString(context); |
| } |
| } |
| |
| internal readonly struct BoolPrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<bool> |
| { |
| public static TypeId WireTypeId => TypeId.Bool; |
| |
| public static bool IsNullable => false; |
| |
| public static bool DefaultValue => false; |
| |
| public static bool IsNone(bool value) => false; |
| |
| public static void Write(WriteContext context, bool value) |
| { |
| context.Writer.WriteUInt8(value ? (byte)1 : (byte)0); |
| } |
| |
| public static bool Read(ReadContext context) |
| { |
| return context.Reader.ReadUInt8() != 0; |
| } |
| } |
| |
| internal readonly struct Int8PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<sbyte> |
| { |
| public static TypeId WireTypeId => TypeId.Int8; |
| |
| public static bool IsNullable => false; |
| |
| public static sbyte DefaultValue => 0; |
| |
| public static bool IsNone(sbyte value) => false; |
| |
| public static void Write(WriteContext context, sbyte value) |
| { |
| context.Writer.WriteInt8(value); |
| } |
| |
| public static sbyte Read(ReadContext context) |
| { |
| return context.Reader.ReadInt8(); |
| } |
| } |
| |
| internal readonly struct Int16PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<short> |
| { |
| public static TypeId WireTypeId => TypeId.Int16; |
| |
| public static bool IsNullable => false; |
| |
| public static short DefaultValue => 0; |
| |
| public static bool IsNone(short value) => false; |
| |
| public static void Write(WriteContext context, short value) |
| { |
| context.Writer.WriteInt16(value); |
| } |
| |
| public static short Read(ReadContext context) |
| { |
| return context.Reader.ReadInt16(); |
| } |
| } |
| |
| internal readonly struct Int32PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<int> |
| { |
| public static TypeId WireTypeId => TypeId.VarInt32; |
| |
| public static bool IsNullable => false; |
| |
| public static int DefaultValue => 0; |
| |
| public static bool IsNone(int value) => false; |
| |
| public static void Write(WriteContext context, int value) |
| { |
| context.Writer.WriteVarInt32(value); |
| } |
| |
| public static int Read(ReadContext context) |
| { |
| return context.Reader.ReadVarInt32(); |
| } |
| } |
| |
| internal readonly struct Int64PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<long> |
| { |
| public static TypeId WireTypeId => TypeId.VarInt64; |
| |
| public static bool IsNullable => false; |
| |
| public static long DefaultValue => 0; |
| |
| public static bool IsNone(long value) => false; |
| |
| public static void Write(WriteContext context, long value) |
| { |
| context.Writer.WriteVarInt64(value); |
| } |
| |
| public static long Read(ReadContext context) |
| { |
| return context.Reader.ReadVarInt64(); |
| } |
| } |
| |
| internal readonly struct UInt16PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<ushort> |
| { |
| public static TypeId WireTypeId => TypeId.UInt16; |
| |
| public static bool IsNullable => false; |
| |
| public static ushort DefaultValue => 0; |
| |
| public static bool IsNone(ushort value) => false; |
| |
| public static void Write(WriteContext context, ushort value) |
| { |
| context.Writer.WriteUInt16(value); |
| } |
| |
| public static ushort Read(ReadContext context) |
| { |
| return context.Reader.ReadUInt16(); |
| } |
| } |
| |
| internal readonly struct UInt32PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<uint> |
| { |
| public static TypeId WireTypeId => TypeId.VarUInt32; |
| |
| public static bool IsNullable => false; |
| |
| public static uint DefaultValue => 0; |
| |
| public static bool IsNone(uint value) => false; |
| |
| public static void Write(WriteContext context, uint value) |
| { |
| context.Writer.WriteVarUInt32(value); |
| } |
| |
| public static uint Read(ReadContext context) |
| { |
| return context.Reader.ReadVarUInt32(); |
| } |
| } |
| |
| internal readonly struct UInt64PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<ulong> |
| { |
| public static TypeId WireTypeId => TypeId.VarUInt64; |
| |
| public static bool IsNullable => false; |
| |
| public static ulong DefaultValue => 0; |
| |
| public static bool IsNone(ulong value) => false; |
| |
| public static void Write(WriteContext context, ulong value) |
| { |
| context.Writer.WriteVarUInt64(value); |
| } |
| |
| public static ulong Read(ReadContext context) |
| { |
| return context.Reader.ReadVarUInt64(); |
| } |
| } |
| |
| internal readonly struct Float32PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<float> |
| { |
| public static TypeId WireTypeId => TypeId.Float32; |
| |
| public static bool IsNullable => false; |
| |
| public static float DefaultValue => 0; |
| |
| public static bool IsNone(float value) => false; |
| |
| public static void Write(WriteContext context, float value) |
| { |
| context.Writer.WriteFloat32(value); |
| } |
| |
| public static float Read(ReadContext context) |
| { |
| return context.Reader.ReadFloat32(); |
| } |
| } |
| |
| internal readonly struct Float64PrimitiveDictionaryCodec : IPrimitiveDictionaryCodec<double> |
| { |
| public static TypeId WireTypeId => TypeId.Float64; |
| |
| public static bool IsNullable => false; |
| |
| public static double DefaultValue => 0; |
| |
| public static bool IsNone(double value) => false; |
| |
| public static void Write(WriteContext context, double value) |
| { |
| context.Writer.WriteFloat64(value); |
| } |
| |
| public static double Read(ReadContext context) |
| { |
| return context.Reader.ReadFloat64(); |
| } |
| } |
| |
| internal interface IPrimitiveMapWriteOps<TMap, TKey, TValue, TEnumerator> |
| where TKey : notnull |
| where TEnumerator : struct, IEnumerator<KeyValuePair<TKey, TValue>> |
| { |
| static abstract int Count(TMap map); |
| |
| static abstract TEnumerator GetEnumerator(TMap map); |
| } |
| |
| internal interface IPrimitiveMapReadOps<TMap, TKey, TValue> |
| where TKey : notnull |
| { |
| static abstract TMap Create(int capacity); |
| |
| static abstract void Put(TMap map, TKey key, TValue value); |
| } |
| |
| internal readonly struct DictionaryPrimitiveMapOps<TKey, TValue> |
| : IPrimitiveMapWriteOps<Dictionary<TKey, TValue>, TKey, TValue, Dictionary<TKey, TValue>.Enumerator>, |
| IPrimitiveMapReadOps<Dictionary<TKey, TValue>, TKey, TValue> |
| where TKey : notnull |
| { |
| public static int Count(Dictionary<TKey, TValue> map) => map.Count; |
| |
| public static Dictionary<TKey, TValue>.Enumerator GetEnumerator(Dictionary<TKey, TValue> map) => map.GetEnumerator(); |
| |
| public static Dictionary<TKey, TValue> Create(int capacity) => new(capacity); |
| |
| public static void Put(Dictionary<TKey, TValue> map, TKey key, TValue value) |
| { |
| map[key] = value; |
| } |
| } |
| |
| internal readonly struct SortedDictionaryPrimitiveMapOps<TKey, TValue> |
| : IPrimitiveMapWriteOps<SortedDictionary<TKey, TValue>, TKey, TValue, SortedDictionary<TKey, TValue>.Enumerator>, |
| IPrimitiveMapReadOps<SortedDictionary<TKey, TValue>, TKey, TValue> |
| where TKey : notnull |
| { |
| public static int Count(SortedDictionary<TKey, TValue> map) => map.Count; |
| |
| public static SortedDictionary<TKey, TValue>.Enumerator GetEnumerator(SortedDictionary<TKey, TValue> map) => map.GetEnumerator(); |
| |
| public static SortedDictionary<TKey, TValue> Create(int capacity) |
| { |
| _ = capacity; |
| return new SortedDictionary<TKey, TValue>(); |
| } |
| |
| public static void Put(SortedDictionary<TKey, TValue> map, TKey key, TValue value) |
| { |
| map[key] = value; |
| } |
| } |
| |
| internal readonly struct SortedListPrimitiveMapOps<TKey, TValue> |
| : IPrimitiveMapWriteOps<SortedList<TKey, TValue>, TKey, TValue, SortedListPrimitiveEnumerator<TKey, TValue>>, |
| IPrimitiveMapReadOps<SortedList<TKey, TValue>, TKey, TValue> |
| where TKey : notnull |
| { |
| public static int Count(SortedList<TKey, TValue> map) => map.Count; |
| |
| public static SortedListPrimitiveEnumerator<TKey, TValue> GetEnumerator(SortedList<TKey, TValue> map) => new(map); |
| |
| public static SortedList<TKey, TValue> Create(int capacity) => new(capacity); |
| |
| public static void Put(SortedList<TKey, TValue> map, TKey key, TValue value) |
| { |
| map[key] = value; |
| } |
| } |
| |
| internal struct SortedListPrimitiveEnumerator<TKey, TValue> : IEnumerator<KeyValuePair<TKey, TValue>> |
| where TKey : notnull |
| { |
| private readonly SortedList<TKey, TValue> _map; |
| private int _index; |
| |
| public SortedListPrimitiveEnumerator(SortedList<TKey, TValue> map) |
| { |
| _map = map; |
| _index = -1; |
| } |
| |
| public KeyValuePair<TKey, TValue> Current => new(_map.Keys[_index], _map.Values[_index]); |
| |
| object IEnumerator.Current => Current; |
| |
| public bool MoveNext() |
| { |
| int next = _index + 1; |
| if (next >= _map.Count) |
| { |
| return false; |
| } |
| |
| _index = next; |
| return true; |
| } |
| |
| public void Reset() |
| { |
| _index = -1; |
| } |
| |
| public void Dispose() |
| { |
| } |
| } |
| |
| internal readonly struct ConcurrentDictionaryPrimitiveMapOps<TKey, TValue> |
| : IPrimitiveMapReadOps<ConcurrentDictionary<TKey, TValue>, TKey, TValue> |
| where TKey : notnull |
| { |
| public static ConcurrentDictionary<TKey, TValue> Create(int capacity) |
| { |
| return new ConcurrentDictionary<TKey, TValue>(Environment.ProcessorCount, capacity); |
| } |
| |
| public static void Put(ConcurrentDictionary<TKey, TValue> map, TKey key, TValue value) |
| { |
| map[key] = value; |
| } |
| } |
| |
| internal struct KeyValuePairArrayEnumerator<TKey, TValue> : IEnumerator<KeyValuePair<TKey, TValue>> |
| { |
| private readonly KeyValuePair<TKey, TValue>[] _array; |
| private int _index; |
| |
| public KeyValuePairArrayEnumerator(KeyValuePair<TKey, TValue>[] array) |
| { |
| _array = array; |
| _index = -1; |
| } |
| |
| public KeyValuePair<TKey, TValue> Current => _array[_index]; |
| |
| object IEnumerator.Current => Current; |
| |
| public bool MoveNext() |
| { |
| int next = _index + 1; |
| if (next >= _array.Length) |
| { |
| return false; |
| } |
| |
| _index = next; |
| return true; |
| } |
| |
| public void Reset() |
| { |
| _index = -1; |
| } |
| |
| public void Dispose() |
| { |
| } |
| } |
| |
| internal readonly struct ArrayPrimitiveMapWriteOps<TKey, TValue> |
| : IPrimitiveMapWriteOps<KeyValuePair<TKey, TValue>[], TKey, TValue, KeyValuePairArrayEnumerator<TKey, TValue>> |
| where TKey : notnull |
| { |
| public static int Count(KeyValuePair<TKey, TValue>[] map) => map.Length; |
| |
| public static KeyValuePairArrayEnumerator<TKey, TValue> GetEnumerator(KeyValuePair<TKey, TValue>[] map) => new(map); |
| } |
| |
| internal static class PrimitiveDictionaryCodecWriter |
| { |
| public static void WriteMap<TMap, TKey, TValue, TKeyCodec, TValueCodec, TMapOps, TEnumerator>( |
| WriteContext context, |
| TMap map, |
| bool hasGenerics) |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| where TMapOps : struct, IPrimitiveMapWriteOps<TMap, TKey, TValue, TEnumerator> |
| where TEnumerator : struct, IEnumerator<KeyValuePair<TKey, TValue>> |
| { |
| int totalLength = map is null ? 0 : TMapOps.Count(map); |
| context.Writer.WriteVarUInt32((uint)totalLength); |
| if (totalLength == 0) |
| { |
| return; |
| } |
| |
| TypeId keyTypeId = TKeyCodec.WireTypeId; |
| TypeId valueTypeId = TValueCodec.WireTypeId; |
| bool keyDeclared = hasGenerics && !TypeResolver.NeedToWriteTypeInfoForField(keyTypeId); |
| bool valueDeclared = hasGenerics && !TypeResolver.NeedToWriteTypeInfoForField(valueTypeId); |
| bool keyNullable = TKeyCodec.IsNullable; |
| bool valueNullable = TValueCodec.IsNullable; |
| |
| int writtenCount = 0; |
| using TEnumerator enumerator = TMapOps.GetEnumerator(map); |
| if (!enumerator.MoveNext()) |
| { |
| throw new InvalidDataException($"primitive map enumerator yielded zero entries while count={totalLength}"); |
| } |
| |
| KeyValuePair<TKey, TValue> pair = enumerator.Current; |
| bool hasCurrent = true; |
| while (hasCurrent) |
| { |
| bool keyNull = keyNullable && TKeyCodec.IsNone(pair.Key); |
| bool valueNull = valueNullable && TValueCodec.IsNone(pair.Value); |
| if (keyNull || valueNull) |
| { |
| byte header = 0; |
| if (keyNull) |
| { |
| header |= DictionaryBits.KeyNull; |
| } |
| else if (keyDeclared) |
| { |
| header |= DictionaryBits.DeclaredKeyType; |
| } |
| |
| if (valueNull) |
| { |
| header |= DictionaryBits.ValueNull; |
| } |
| else if (valueDeclared) |
| { |
| header |= DictionaryBits.DeclaredValueType; |
| } |
| |
| context.Writer.WriteUInt8(header); |
| if (!keyNull) |
| { |
| if (!keyDeclared) |
| { |
| context.Writer.WriteUInt8((byte)keyTypeId); |
| } |
| |
| TKeyCodec.Write(context, pair.Key); |
| } |
| |
| if (!valueNull) |
| { |
| if (!valueDeclared) |
| { |
| context.Writer.WriteUInt8((byte)valueTypeId); |
| } |
| |
| TValueCodec.Write(context, pair.Value); |
| } |
| |
| writtenCount += 1; |
| if (writtenCount > totalLength) |
| { |
| throw new InvalidDataException($"primitive map count mismatch: expected {totalLength}, wrote at least {writtenCount}"); |
| } |
| |
| hasCurrent = enumerator.MoveNext(); |
| if (hasCurrent) |
| { |
| pair = enumerator.Current; |
| } |
| |
| continue; |
| } |
| |
| byte blockHeader = 0; |
| if (keyDeclared) |
| { |
| blockHeader |= DictionaryBits.DeclaredKeyType; |
| } |
| |
| if (valueDeclared) |
| { |
| blockHeader |= DictionaryBits.DeclaredValueType; |
| } |
| |
| context.Writer.WriteUInt8(blockHeader); |
| int chunkSizeOffset = context.Writer.Count; |
| context.Writer.WriteUInt8(0); |
| PrimitiveDictionaryHeader.WriteMapChunkTypeInfo(context, keyDeclared, valueDeclared, keyTypeId, valueTypeId); |
| |
| byte chunkSize = 0; |
| while (true) |
| { |
| TKeyCodec.Write(context, pair.Key); |
| TValueCodec.Write(context, pair.Value); |
| chunkSize += 1; |
| writtenCount += 1; |
| if (writtenCount > totalLength) |
| { |
| throw new InvalidDataException($"primitive map count mismatch: expected {totalLength}, wrote at least {writtenCount}"); |
| } |
| |
| if (chunkSize == byte.MaxValue) |
| { |
| hasCurrent = enumerator.MoveNext(); |
| if (hasCurrent) |
| { |
| pair = enumerator.Current; |
| } |
| |
| break; |
| } |
| |
| if (!enumerator.MoveNext()) |
| { |
| hasCurrent = false; |
| break; |
| } |
| |
| pair = enumerator.Current; |
| keyNull = keyNullable && TKeyCodec.IsNone(pair.Key); |
| valueNull = valueNullable && TValueCodec.IsNone(pair.Value); |
| if (keyNull || valueNull) |
| { |
| hasCurrent = true; |
| break; |
| } |
| } |
| |
| context.Writer.SetByte(chunkSizeOffset, chunkSize); |
| } |
| |
| if (writtenCount != totalLength) |
| { |
| throw new InvalidDataException($"primitive map count mismatch: expected {totalLength}, wrote {writtenCount}"); |
| } |
| } |
| } |
| |
| internal static class PrimitiveDictionaryCodecReader |
| { |
| public static TMap ReadMap<TMap, TKey, TValue, TKeyCodec, TValueCodec, TMapOps>(ReadContext context) |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| where TMapOps : struct, IPrimitiveMapReadOps<TMap, TKey, TValue> |
| { |
| int totalLength = checked((int)context.Reader.ReadVarUInt32()); |
| TMap map = TMapOps.Create(totalLength); |
| if (totalLength == 0) |
| { |
| return map; |
| } |
| |
| TypeId keyTypeId = TKeyCodec.WireTypeId; |
| TypeId valueTypeId = TValueCodec.WireTypeId; |
| bool keyNullable = TKeyCodec.IsNullable; |
| int readCount = 0; |
| while (readCount < totalLength) |
| { |
| byte header = context.Reader.ReadUInt8(); |
| bool trackKeyRef = (header & DictionaryBits.TrackingKeyRef) != 0; |
| bool keyNull = (header & DictionaryBits.KeyNull) != 0; |
| bool keyDeclared = (header & DictionaryBits.DeclaredKeyType) != 0; |
| bool trackValueRef = (header & DictionaryBits.TrackingValueRef) != 0; |
| bool valueNull = (header & DictionaryBits.ValueNull) != 0; |
| bool valueDeclared = (header & DictionaryBits.DeclaredValueType) != 0; |
| if (trackKeyRef || trackValueRef) |
| { |
| throw new InvalidDataException("primitive dictionary codecs do not support reference-tracking flags"); |
| } |
| |
| if (keyNull && !keyNullable) |
| { |
| throw new InvalidDataException("non-nullable primitive dictionary key cannot be null"); |
| } |
| |
| if (keyNull && valueNull) |
| { |
| readCount += 1; |
| continue; |
| } |
| |
| if (keyNull) |
| { |
| if (!valueDeclared) |
| { |
| ReadAndValidateTypeInfo(context, valueTypeId); |
| } |
| |
| _ = TValueCodec.Read(context); |
| readCount += 1; |
| continue; |
| } |
| |
| if (valueNull) |
| { |
| if (!keyDeclared) |
| { |
| ReadAndValidateTypeInfo(context, keyTypeId); |
| } |
| |
| TKey key = TKeyCodec.Read(context); |
| TMapOps.Put(map, key, TValueCodec.DefaultValue); |
| readCount += 1; |
| continue; |
| } |
| |
| int chunkSize = context.Reader.ReadUInt8(); |
| if (chunkSize == 0) |
| { |
| throw new InvalidDataException("invalid primitive map chunk size 0"); |
| } |
| |
| if (!keyDeclared) |
| { |
| ReadAndValidateTypeInfo(context, keyTypeId); |
| } |
| |
| if (!valueDeclared) |
| { |
| ReadAndValidateTypeInfo(context, valueTypeId); |
| } |
| |
| for (int i = 0; i < chunkSize; i++) |
| { |
| TKey key = TKeyCodec.Read(context); |
| TValue value = TValueCodec.Read(context); |
| TMapOps.Put(map, key, value); |
| } |
| |
| readCount += chunkSize; |
| } |
| |
| return map; |
| } |
| |
| private static void ReadAndValidateTypeInfo(ReadContext context, TypeId expectedTypeId) |
| { |
| uint actualTypeId = context.Reader.ReadVarUInt32(); |
| if (actualTypeId != (uint)expectedTypeId) |
| { |
| throw new TypeMismatchException((uint)expectedTypeId, actualTypeId); |
| } |
| } |
| } |
| |
| internal class PrimitiveDictionarySerializer<TKey, TValue, TKeyCodec, TValueCodec> : Serializer<Dictionary<TKey, TValue>> |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| |
| |
| |
| public override Dictionary<TKey, TValue> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in Dictionary<TKey, TValue> value, bool hasGenerics) |
| { |
| Dictionary<TKey, TValue> map = value ?? []; |
| PrimitiveDictionaryCodecWriter.WriteMap< |
| Dictionary<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| DictionaryPrimitiveMapOps<TKey, TValue>, |
| Dictionary<TKey, TValue>.Enumerator>(context, map, hasGenerics); |
| } |
| |
| public override Dictionary<TKey, TValue> ReadData(ReadContext context) |
| { |
| return PrimitiveDictionaryCodecReader.ReadMap< |
| Dictionary<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| DictionaryPrimitiveMapOps<TKey, TValue>>(context); |
| } |
| } |
| |
| internal class PrimitiveStringKeyDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveDictionarySerializer<string, TValue, StringPrimitiveDictionaryCodec, TValueCodec> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSameTypeDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveDictionarySerializer<TValue, TValue, TValueCodec, TValueCodec> |
| where TValue : notnull |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSortedDictionarySerializer<TKey, TValue, TKeyCodec, TValueCodec> : Serializer<SortedDictionary<TKey, TValue>> |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| |
| |
| |
| public override SortedDictionary<TKey, TValue> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in SortedDictionary<TKey, TValue> value, bool hasGenerics) |
| { |
| SortedDictionary<TKey, TValue> map = value ?? new SortedDictionary<TKey, TValue>(); |
| PrimitiveDictionaryCodecWriter.WriteMap< |
| SortedDictionary<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| SortedDictionaryPrimitiveMapOps<TKey, TValue>, |
| SortedDictionary<TKey, TValue>.Enumerator>(context, map, hasGenerics); |
| } |
| |
| public override SortedDictionary<TKey, TValue> ReadData(ReadContext context) |
| { |
| return PrimitiveDictionaryCodecReader.ReadMap< |
| SortedDictionary<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| SortedDictionaryPrimitiveMapOps<TKey, TValue>>(context); |
| } |
| } |
| |
| internal class PrimitiveStringKeySortedDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveSortedDictionarySerializer<string, TValue, StringPrimitiveDictionaryCodec, TValueCodec> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSameTypeSortedDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveSortedDictionarySerializer<TValue, TValue, TValueCodec, TValueCodec> |
| where TValue : notnull |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSortedListSerializer<TKey, TValue, TKeyCodec, TValueCodec> : Serializer<SortedList<TKey, TValue>> |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| |
| |
| |
| public override SortedList<TKey, TValue> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in SortedList<TKey, TValue> value, bool hasGenerics) |
| { |
| SortedList<TKey, TValue> map = value ?? new SortedList<TKey, TValue>(); |
| PrimitiveDictionaryCodecWriter.WriteMap< |
| SortedList<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| SortedListPrimitiveMapOps<TKey, TValue>, |
| SortedListPrimitiveEnumerator<TKey, TValue>>(context, map, hasGenerics); |
| } |
| |
| public override SortedList<TKey, TValue> ReadData(ReadContext context) |
| { |
| return PrimitiveDictionaryCodecReader.ReadMap< |
| SortedList<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| SortedListPrimitiveMapOps<TKey, TValue>>(context); |
| } |
| } |
| |
| internal class PrimitiveStringKeySortedListSerializer<TValue, TValueCodec> |
| : PrimitiveSortedListSerializer<string, TValue, StringPrimitiveDictionaryCodec, TValueCodec> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSameTypeSortedListSerializer<TValue, TValueCodec> |
| : PrimitiveSortedListSerializer<TValue, TValue, TValueCodec, TValueCodec> |
| where TValue : notnull |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveConcurrentDictionarySerializer<TKey, TValue, TKeyCodec, TValueCodec> : Serializer<ConcurrentDictionary<TKey, TValue>> |
| where TKey : notnull |
| where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| |
| |
| |
| public override ConcurrentDictionary<TKey, TValue> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in ConcurrentDictionary<TKey, TValue> value, bool hasGenerics) |
| { |
| ConcurrentDictionary<TKey, TValue> map = value ?? new ConcurrentDictionary<TKey, TValue>(); |
| // Use snapshot to keep count and entry enumeration stable under concurrent mutation. |
| PrimitiveDictionaryCodecWriter.WriteMap< |
| KeyValuePair<TKey, TValue>[], |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| ArrayPrimitiveMapWriteOps<TKey, TValue>, |
| KeyValuePairArrayEnumerator<TKey, TValue>>(context, map.ToArray(), hasGenerics); |
| } |
| |
| public override ConcurrentDictionary<TKey, TValue> ReadData(ReadContext context) |
| { |
| return PrimitiveDictionaryCodecReader.ReadMap< |
| ConcurrentDictionary<TKey, TValue>, |
| TKey, |
| TValue, |
| TKeyCodec, |
| TValueCodec, |
| ConcurrentDictionaryPrimitiveMapOps<TKey, TValue>>(context); |
| } |
| } |
| |
| internal class PrimitiveStringKeyConcurrentDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveConcurrentDictionarySerializer<string, TValue, StringPrimitiveDictionaryCodec, TValueCodec> |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| internal class PrimitiveSameTypeConcurrentDictionarySerializer<TValue, TValueCodec> |
| : PrimitiveConcurrentDictionarySerializer<TValue, TValue, TValueCodec, TValueCodec> |
| where TValue : notnull |
| where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue> |
| { |
| } |
| |
| // String-key primitive dictionary serializers. |
| internal sealed class DictionaryStringBoolSerializer : PrimitiveStringKeyDictionarySerializer<bool, BoolPrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringDoubleSerializer : PrimitiveStringKeyDictionarySerializer<double, Float64PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringFloatSerializer : PrimitiveStringKeyDictionarySerializer<float, Float32PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringInt8Serializer : PrimitiveStringKeyDictionarySerializer<sbyte, Int8PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringInt16Serializer : PrimitiveStringKeyDictionarySerializer<short, Int16PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringIntSerializer : PrimitiveStringKeyDictionarySerializer<int, Int32PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringLongSerializer : PrimitiveStringKeyDictionarySerializer<long, Int64PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringStringSerializer : PrimitiveStringKeyDictionarySerializer<string, StringPrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringUInt16Serializer : PrimitiveStringKeyDictionarySerializer<ushort, UInt16PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringUIntSerializer : PrimitiveStringKeyDictionarySerializer<uint, UInt32PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryStringULongSerializer : PrimitiveStringKeyDictionarySerializer<ulong, UInt64PrimitiveDictionaryCodec> { } |
| |
| // Same-type primitive dictionary serializers. |
| internal sealed class DictionaryIntIntSerializer : PrimitiveSameTypeDictionarySerializer<int, Int32PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryLongLongSerializer : PrimitiveSameTypeDictionarySerializer<long, Int64PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryUIntUIntSerializer : PrimitiveSameTypeDictionarySerializer<uint, UInt32PrimitiveDictionaryCodec> { } |
| |
| internal sealed class DictionaryULongULongSerializer : PrimitiveSameTypeDictionarySerializer<ulong, UInt64PrimitiveDictionaryCodec> { } |