Skip to content

Commit eb0f785

Browse files
committed
[Proto] Refactor ZigZag encoding and decoding methods for improved clarity and performance
1 parent 7b8bd36 commit eb0f785

4 files changed

Lines changed: 46 additions & 171 deletions

File tree

Lagrange.Proto.Test/SimpleZigZagTest.cs

Lines changed: 0 additions & 76 deletions
This file was deleted.

Lagrange.Proto.Test/ZigZagBugTest.cs

Lines changed: 0 additions & 74 deletions
This file was deleted.

Lagrange.Proto/Serialization/Converter/Value/ProtoNumberConverter.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,24 @@ public override T Read(int field, WireType wireType, ref ProtoReader reader)
105105
};
106106
}
107107

108-
public override T ReadWithNumberHandling(int field, WireType wireType, ref ProtoReader reader, ProtoNumberHandling numberHandling)
108+
public override unsafe T ReadWithNumberHandling(int field, WireType wireType, ref ProtoReader reader, ProtoNumberHandling numberHandling)
109109
{
110-
T value = Read(field, wireType, ref reader);
111-
return (numberHandling & ProtoNumberHandling.Signed) != 0 ? ProtoHelper.ZigZagDecode(value) : value;
110+
if ((numberHandling & ProtoNumberHandling.Signed) != 0 && wireType == WireType.VarInt)
111+
{
112+
T value = sizeof(T) switch
113+
{
114+
1 => T.CreateTruncating(reader.DecodeVarInt<byte>()),
115+
2 => T.CreateTruncating(reader.DecodeVarInt<ushort>()),
116+
4 => T.CreateTruncating(reader.DecodeVarInt<uint>()),
117+
8 => T.CreateTruncating(reader.DecodeVarInt<ulong>()),
118+
_ => Read(field, wireType, ref reader)
119+
};
120+
return ProtoHelper.ZigZagDecode(value);
121+
}
122+
else
123+
{
124+
T value = Read(field, wireType, ref reader);
125+
return (numberHandling & ProtoNumberHandling.Signed) != 0 ? ProtoHelper.ZigZagDecode(value) : value;
126+
}
112127
}
113128
}

Lagrange.Proto/Utility/ProtoHelper.cs

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,41 @@ public static unsafe int GetVarIntLength<T>(T value) where T : unmanaged, INumbe
4141
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4242
public static unsafe T ZigZagEncode<T>(T value) where T : unmanaged, INumber<T>
4343
{
44-
if (sizeof(T) <= 4)
45-
{
46-
int v = int.CreateSaturating(value);
47-
return T.CreateTruncating((v << 1) ^ (v >> 31));
48-
}
49-
else
44+
return sizeof(T) switch
5045
{
51-
long v = long.CreateSaturating(value);
52-
return T.CreateTruncating((v << 1) ^ (v >> 63));
53-
}
46+
1 or 2 or 4 => T.CreateTruncating(EncodeZigZag32(int.CreateSaturating(value))),
47+
8 => T.CreateTruncating(EncodeZigZag64(long.CreateSaturating(value))),
48+
_ => sizeof(T) <= 4
49+
? T.CreateTruncating(EncodeZigZag32(int.CreateSaturating(value)))
50+
: T.CreateTruncating(EncodeZigZag64(long.CreateSaturating(value)))
51+
};
52+
53+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
54+
static uint EncodeZigZag32(int n) => (uint)((n << 1) ^ (n >> 31));
55+
56+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57+
static ulong EncodeZigZag64(long n) => (ulong)((n << 1) ^ (n >> 63));
5458
}
5559

5660
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5761
public static unsafe T ZigZagDecode<T>(T value) where T : unmanaged, INumber<T>
5862
{
59-
if (sizeof(T) <= 4)
60-
{
61-
int v = int.CreateSaturating(value);
62-
return T.CreateTruncating((v >> 1) ^ -(v & 1));
63-
}
64-
else
63+
return sizeof(T) switch
6564
{
66-
long v = long.CreateSaturating(value);
67-
return T.CreateTruncating((v >> 1) ^ -(v & 1));
68-
}
65+
1 => T.CreateTruncating(DecodeZigZag32(uint.CreateTruncating(value) & 0xFF)),
66+
2 => T.CreateTruncating(DecodeZigZag32(uint.CreateTruncating(value) & 0xFFFF)),
67+
4 => T.CreateTruncating(DecodeZigZag32(uint.CreateTruncating(value))),
68+
8 => T.CreateTruncating(DecodeZigZag64(ulong.CreateTruncating(value))),
69+
_ => sizeof(T) <= 4
70+
? T.CreateTruncating(DecodeZigZag32(uint.CreateTruncating(value)))
71+
: T.CreateTruncating(DecodeZigZag64(ulong.CreateTruncating(value)))
72+
};
73+
74+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
75+
static int DecodeZigZag32(uint n) => (int)((n >> 1) ^ (uint)(-(int)(n & 1)));
76+
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
static long DecodeZigZag64(ulong n) => (long)((n >> 1) ^ (ulong)(-(long)(n & 1)));
6979
}
7080

7181
[MethodImpl(MethodImplOptions.AggressiveInlining)]

0 commit comments

Comments
 (0)