2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2026-04-29 06:48:41 +00:00

Gvwie updated

This commit is contained in:
2026-04-09 16:36:05 +03:00
parent 15479288cc
commit ae524f577a
9 changed files with 575 additions and 509 deletions
+60 -59
View File
@@ -6,17 +6,6 @@ namespace Esiur.Data.Gvwie;
public static class GroupInt16Codec public static class GroupInt16Codec
{ {
// Header layout:
// 1 | cccccc | w
//
// MSB = 1 => grouped form
// cccccc = 0..62 => short count = cccccc + 1 (1..63)
// cccccc = 63 => extended count, followed by varint(count - 64)
// w = 0 => width = 1 byte
// w = 1 => width = 2 bytes
//
// MSB = 0 => literal fast path for ZigZag values in 7 bits
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<short> values) public static byte[] Encode(IList<short> values)
{ {
@@ -36,7 +25,7 @@ public static class GroupInt16Codec
} }
int start = i; int start = i;
int width = WidthFromZigZag(zz); // 1 or 2 int width = WidthFromZigZag(zz); // 1..2
int count = 1; int count = 1;
// Build a run of same-width non-literal values // Build a run of same-width non-literal values
@@ -55,10 +44,11 @@ public static class GroupInt16Codec
count++; count++;
} }
if (count <= 63) if (count <= 60)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[6 bits] | (width-1)[1 bit] // Header: 1 | (count-1)[6 bits] | (width-1)[1 bit]
// count field 000000..111011 => count 1..60
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x3F) << 1); header |= (byte)(((count - 1) & 0x3F) << 1);
header |= (byte)((width - 1) & 0x01); header |= (byte)((width - 1) & 0x01);
@@ -67,13 +57,33 @@ public static class GroupInt16Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 111111 | (width-1)[1 bit] // Header: 1 | g[6 bits] | (width-1)[1 bit]
// Followed by varint(count - 64) //
// g = 111100 => LoL = 1 byte
// g = 111101 => LoL = 2 bytes
// g = 111110 => LoL = 3 bytes
// g = 111111 => LoL = 4 bytes
//
// LoL stores (count - 61) in little-endian form.
uint extra = checked((uint)(count - 61));
int lol = LengthOfLength(extra);
byte groupBits = lol switch
{
1 => 0b111100,
2 => 0b111101,
3 => 0b111110,
4 => 0b111111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x7E; // count bits = 111111 header |= (byte)(groupBits << 1);
header |= (byte)((width - 1) & 0x01); header |= (byte)((width - 1) & 0x01);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, (uint)(count - 64));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' zigzag values, LE, 'width' bytes each // Payload: 'count' zigzag values, LE, 'width' bytes each
@@ -98,24 +108,33 @@ public static class GroupInt16Codec
if ((h & 0x80) == 0) if ((h & 0x80) == 0)
{ {
// Fast path: 7-bit ZigZag in low bits // Fast path: 7-bit zigzag in low bits
ushort zz7 = (ushort)(h & 0x7F); ushort zz7 = (ushort)(h & 0x7F);
result.Add(UnZigZag16(zz7)); result.Add(UnZigZag16(zz7));
continue; continue;
} }
int countField = (h >> 1) & 0x3F; int countField = (h >> 1) & 0x3F;
int width = (h & 0x01) + 1; // 1 or 2 int width = (h & 0x01) + 1;
int count; int count;
if (countField == 63)
if (countField <= 59)
{ {
uint extra = ReadVarUInt32(src, ref pos); // Short group: 0..59 => count 1..60
count = checked(64 + (int)extra); count = countField + 1;
} }
else else
{ {
count = countField + 1; // Extended group:
// 60 => LoL=1
// 61 => LoL=2
// 62 => LoL=3
// 63 => LoL=4
int lol = countField - 59;
uint extra = checked((uint)ReadLE(src, ref pos, lol));
count = checked(61 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
@@ -142,6 +161,15 @@ public static class GroupInt16Codec
return z <= 0xFF ? 1 : 2; return z <= 0xFF ? 1 : 2;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, ushort value, int width) private static void WriteLE(List<byte> dst, ushort value, int width)
{ {
@@ -149,50 +177,23 @@ public static class GroupInt16Codec
dst.Add((byte)((value >> (8 * i)) & 0xFF)); dst.Add((byte)((value >> (8 * i)) & 0xFF));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width)
{
for (int i = 0; i < width; i++)
dst.Add((byte)((value >> (8 * i)) & 0xFF));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
uint v = 0; uint v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (uint)src[pos++] << (8 * i); v |= (uint)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
+251 -51
View File
@@ -1,4 +1,200 @@
using System; //using System;
//using System.Collections.Generic;
//using System.Runtime.CompilerServices;
//namespace Esiur.Data.Gvwie;
//public static class GroupInt32Codec
//{
// // ----------------- Encoder -----------------
// public static byte[] Encode(IList<int> values, bool aligned = false)
// {
// var dst = new List<byte>(values.Count * 2);
// int i = 0;
// while (i < values.Count)
// {
// uint zz = ZigZag32(values[i]);
// // Fast path: single byte (MSB=0) when zigzag fits in 7 bits
// if (zz <= 0x7Fu)
// {
// dst.Add((byte)zz);
// i++;
// continue;
// }
// int start = i;
// int width = WidthFromZigZag(zz, aligned);
// int count = 1;
// // Build a run of same-width non-literal values
// while ((i + count) < values.Count)
// {
// uint z2 = ZigZag32(values[i + count]);
// // Do not absorb literal-fast-path values into groups
// if (z2 <= 0x7Fu)
// break;
// int w2 = WidthFromZigZag(z2, aligned);
// if (w2 != width)
// break;
// count++;
// }
// if (count <= 31)
// {
// // Short group:
// // Header: 1 | (count-1)[5 bits] | (width-1)[2 bits]
// byte header = 0x80;
// header |= (byte)(((count - 1) & 0x1F) << 2);
// header |= (byte)((width - 1) & 0x03);
// dst.Add(header);
// }
// else
// {
// // Extended group:
// // Header: 1 | 11111 | (width-1)[2 bits]
// // Followed by varint(count - 32)
// byte header = 0x80;
// header |= 0x7C; // count bits = 11111
// header |= (byte)((width - 1) & 0x03);
// dst.Add(header);
// WriteVarUInt32(dst, (uint)(count - 32));
// }
// // Payload: 'count' zigzag values, LE, 'width' bytes each
// for (int k = 0; k < count; k++)
// WriteLE(dst, ZigZag32(values[start + k]), width);
// i += count;
// }
// return dst.ToArray();
// }
// // ----------------- Decoder -----------------
// public static int[] Decode(ReadOnlySpan<byte> src)
// {
// var result = new List<int>();
// int pos = 0;
// while (pos < src.Length)
// {
// byte h = src[pos++];
// if ((h & 0x80) == 0)
// {
// // Fast path: 7-bit ZigZag in low bits
// uint zz7 = (uint)(h & 0x7F);
// result.Add(UnZigZag32(zz7));
// continue;
// }
// int countField = (h >> 2) & 0x1F;
// int width = (h & 0x03) + 1;
// int count;
// if (countField == 31)
// {
// // Extended group length
// uint extra = ReadVarUInt32(src, ref pos);
// count = checked(32 + (int)extra);
// }
// else
// {
// count = countField + 1;
// }
// for (int j = 0; j < count; j++)
// {
// uint raw = (uint)ReadLE(src, ref pos, width);
// int val = UnZigZag32(raw);
// result.Add(val);
// }
// }
// return result.ToArray();
// }
// // ----------------- Helpers -----------------
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static uint ZigZag32(int v) => (uint)((v << 1) ^ (v >> 31));
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static int UnZigZag32(uint u) => (int)((u >> 1) ^ (uint)-(int)(u & 1));
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static int WidthFromZigZag(uint z, bool aligned = false)
// {
// if (z <= 0xFFu) return 1;
// if (z <= 0xFFFFu) return 2;
// if (z <= 0xFFFFFFu) return aligned ? 4 : 3;
// return 4;
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static void WriteLE(List<byte> dst, uint value, int width)
// {
// for (int i = 0; i < width; i++)
// dst.Add((byte)((value >> (8 * i)) & 0xFF));
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
// {
// if ((uint)(pos + width) > (uint)src.Length)
// throw new ArgumentException("Buffer underflow while reading group payload.");
// ulong v = 0;
// for (int i = 0; i < width; i++)
// v |= (ulong)src[pos++] << (8 * i);
// return v;
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static void WriteVarUInt32(List<byte> dst, uint value)
// {
// while (value >= 0x80)
// {
// dst.Add((byte)((value & 0x7F) | 0x80));
// value >>= 7;
// }
// dst.Add((byte)value);
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
// {
// uint result = 0;
// int shift = 0;
// while (true)
// {
// if (pos >= src.Length)
// throw new ArgumentException("Buffer underflow while reading varint.");
// byte b = src[pos++];
// result |= (uint)(b & 0x7F) << shift;
// if ((b & 0x80) == 0)
// return result;
// shift += 7;
// if (shift >= 35)
// throw new ArgumentException("Varint is too long for UInt32.");
// }
// }
//}
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -6,9 +202,8 @@ namespace Esiur.Data.Gvwie;
public static class GroupInt32Codec public static class GroupInt32Codec
{ {
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<int> values, bool use4for3 = false) public static byte[] Encode(IList<int> values, bool aligned = false)
{ {
var dst = new List<byte>(values.Count * 2); var dst = new List<byte>(values.Count * 2);
int i = 0; int i = 0;
@@ -26,7 +221,7 @@ public static class GroupInt32Codec
} }
int start = i; int start = i;
int width = WidthFromZigZag(zz, use4for3); int width = WidthFromZigZag(zz, aligned);
int count = 1; int count = 1;
// Build a run of same-width non-literal values // Build a run of same-width non-literal values
@@ -38,17 +233,19 @@ public static class GroupInt32Codec
if (z2 <= 0x7Fu) if (z2 <= 0x7Fu)
break; break;
int w2 = WidthFromZigZag(z2, use4for3); int w2 = WidthFromZigZag(z2, aligned);
if (w2 != width) if (w2 != width)
break; break;
count++; count++;
} }
if (count <= 31) if (count <= 28)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[5 bits] | (width-1)[2 bits] // Header: 1 | (count-1)[5 bits] | (width-1)[2 bits]
// count field values:
// 00000..11011 => count = 1..28
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x1F) << 2); header |= (byte)(((count - 1) & 0x1F) << 2);
header |= (byte)((width - 1) & 0x03); header |= (byte)((width - 1) & 0x03);
@@ -57,13 +254,33 @@ public static class GroupInt32Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 11111 | (width-1)[2 bits] // Header: 1 | g[5 bits] | (width-1)[2 bits]
// Followed by varint(count - 32) //
// g = 11100 => LoL = 1 byte
// g = 11101 => LoL = 2 bytes
// g = 11110 => LoL = 3 bytes
// g = 11111 => LoL = 4 bytes
//
// LoL stores (count - 29) in little-endian form.
uint extra = checked((uint)(count - 29));
int lol = LengthOfLength(extra); // 1..4
byte groupBits = lol switch
{
1 => 0b11100,
2 => 0b11101,
3 => 0b11110,
4 => 0b11111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x7C; // count bits = 11111 header |= (byte)(groupBits << 2);
header |= (byte)((width - 1) & 0x03); header |= (byte)((width - 1) & 0x03);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, (uint)(count - 32));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' zigzag values, LE, 'width' bytes each // Payload: 'count' zigzag values, LE, 'width' bytes each
@@ -98,15 +315,23 @@ public static class GroupInt32Codec
int width = (h & 0x03) + 1; int width = (h & 0x03) + 1;
int count; int count;
if (countField == 31)
if (countField <= 27)
{ {
// Extended group length // Short group: 0..27 => count 1..28
uint extra = ReadVarUInt32(src, ref pos); count = countField + 1;
count = checked(32 + (int)extra);
} }
else else
{ {
count = countField + 1; // Extended group:
// 28 => LoL=1
// 29 => LoL=2
// 30 => LoL=3
// 31 => LoL=4
int lol = countField - 27;
uint extra = checked((uint)ReadLE(src, ref pos, lol));
count = checked(29 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
@@ -137,6 +362,15 @@ public static class GroupInt32Codec
return 4; return 4;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width) private static void WriteLE(List<byte> dst, uint value, int width)
{ {
@@ -148,46 +382,12 @@ public static class GroupInt32Codec
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
ulong v = 0; ulong v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (ulong)src[pos++] << (8 * i); v |= (ulong)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
+58 -196
View File
@@ -1,141 +1,4 @@
//using System; using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//using System;
//using System.Collections.Generic;
//using System.Runtime.CompilerServices;
//namespace Esiur.Data.Gvwie;
//public static class GroupInt64Codec
//{
// // ----------------- Encoder -----------------
// public static byte[] Encode(IList<long> values)
// {
// var dst = new List<byte>(values.Count * 2);
// int i = 0;
// while (i < values.Count)
// {
// ulong zz = ZigZag64(values[i]);
// // Fast path: 1 byte when ZigZag fits in 7 bits
// if (zz <= 0x7Ful)
// {
// dst.Add((byte)zz); // MSB = 0 implicitly
// i++;
// continue;
// }
// // Group path: up to 16 items sharing a common width (1..8 bytes)
// int start = i;
// int count = 1;
// int width = WidthFromZigZag(zz);
// while (count < 16 && (i + count) < values.Count)
// {
// ulong z2 = ZigZag64(values[i + count]);
// int w2 = WidthFromZigZag(z2);
// width = Math.Max(width, w2); // widen as needed
// count++;
// }
// // Header: 1 | (count-1)[4 bits] | (width-1)[3 bits]
// byte header = 0x80;
// header |= (byte)(((count - 1) & 0x0F) << 3);
// header |= (byte)((width - 1) & 0x07);
// dst.Add(header);
// // Payload: 'count' ZigZag values, LE, 'width' bytes each
// for (int k = 0; k < count; k++)
// {
// ulong z = ZigZag64(values[start + k]);
// WriteLE(dst, z, width);
// }
// i += count;
// }
// return dst.ToArray();
// }
// // ----------------- Decoder -----------------
// public static long[] Decode(ReadOnlySpan<byte> src)
// {
// var result = new List<long>();
// int pos = 0;
// while (pos < src.Length)
// {
// byte h = src[pos++];
// if ((h & 0x80) == 0)
// {
// // Fast path: 7-bit ZigZag
// ulong zz7 = (ulong)(h & 0x7F);
// result.Add(UnZigZag64(zz7));
// continue;
// }
// int count = ((h >> 3) & 0x0F) + 1; // 1..16
// int width = (h & 0x07) + 1; // 1..8
// for (int j = 0; j < count; j++)
// {
// ulong raw = ReadLE(src, ref pos, width);
// long val = UnZigZag64(raw);
// result.Add(val);
// }
// }
// return result.ToArray();
// }
// // ----------------- Helpers -----------------
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static ulong ZigZag64(long v) => (ulong)((v << 1) ^ (v >> 63));
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static long UnZigZag64(ulong u) => (long)((u >> 1) ^ (ulong)-(long)(u & 1));
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static int WidthFromZigZag(ulong z)
// {
// if (z <= 0xFFUL) return 1;
// if (z <= 0xFFFFUL) return 2;
// if (z <= 0xFFFFFFUL) return 3;
// if (z <= 0xFFFFFFFFUL) return 4;
// if (z <= 0xFFFFFFFFFFUL) return 5;
// if (z <= 0xFFFFFFFFFFFFUL) return 6;
// if (z <= 0xFFFFFFFFFFFFFFUL) return 7;
// return 8;
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static void WriteLE(List<byte> dst, ulong value, int width)
// {
// for (int i = 0; i < width; i++)
// dst.Add((byte)((value >> (8 * i)) & 0xFF));
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
// {
// if ((uint)(pos + width) > (uint)src.Length)
// throw new ArgumentException("Buffer underflow while reading group payload.");
// ulong v = 0;
// for (int i = 0; i < width; i++)
// v |= (ulong)src[pos++] << (8 * i);
// return v;
// }
//}
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -143,16 +6,6 @@ namespace Esiur.Data.Gvwie;
public static class GroupInt64Codec public static class GroupInt64Codec
{ {
// Header layout for grouped values:
// 1 | cccc | www
//
// MSB = 1 => grouped form
// cccc = 0..14 => short count = cccc + 1 (1..15)
// cccc = 15 => extended count, followed by varint(count - 16)
// www = 0..7 => width = www + 1 (1..8)
//
// MSB = 0 => literal fast path for ZigZag values in 7 bits
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<long> values, bool aligned = false) public static byte[] Encode(IList<long> values, bool aligned = false)
{ {
@@ -191,10 +44,11 @@ public static class GroupInt64Codec
count++; count++;
} }
if (count <= 15) if (count <= 12)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[4 bits] | (width-1)[3 bits] // Header: 1 | (count-1)[4 bits] | (width-1)[3 bits]
// count field 0000..1011 => count 1..12
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x0F) << 3); header |= (byte)(((count - 1) & 0x0F) << 3);
header |= (byte)((width - 1) & 0x07); header |= (byte)((width - 1) & 0x07);
@@ -203,13 +57,33 @@ public static class GroupInt64Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 1111 | (width-1)[3 bits] // Header: 1 | g[4 bits] | (width-1)[3 bits]
// Followed by varint(count - 16) //
// g = 1100 => LoL = 1 byte
// g = 1101 => LoL = 2 bytes
// g = 1110 => LoL = 3 bytes
// g = 1111 => LoL = 4 bytes
//
// LoL stores (count - 13) in little-endian form.
uint extra = checked((uint)(count - 13));
int lol = LengthOfLength(extra); // 1..4
byte groupBits = lol switch
{
1 => 0b1100,
2 => 0b1101,
3 => 0b1110,
4 => 0b1111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x78; // count bits = 1111 header |= (byte)(groupBits << 3);
header |= (byte)((width - 1) & 0x07); header |= (byte)((width - 1) & 0x07);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, checked((uint)(count - 16)));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' zigzag values, LE, 'width' bytes each // Payload: 'count' zigzag values, LE, 'width' bytes each
@@ -244,22 +118,29 @@ public static class GroupInt64Codec
int width = (h & 0x07) + 1; int width = (h & 0x07) + 1;
int count; int count;
if (countField == 15)
if (countField <= 11)
{ {
// Extended group length // Short group: 0..11 => count 1..12
uint extra = ReadVarUInt32(src, ref pos); count = countField + 1;
count = checked(16 + (int)extra);
} }
else else
{ {
count = countField + 1; // Extended group:
// 12 => LoL=1
// 13 => LoL=2
// 14 => LoL=3
// 15 => LoL=4
int lol = countField - 11;
uint extra = checked((uint)ReadLE(src, ref pos, lol));
count = checked(13 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ {
ulong raw = ReadLE(src, ref pos, width); ulong raw = ReadLE(src, ref pos, width);
long val = UnZigZag64(raw); result.Add(UnZigZag64(raw));
result.Add(val);
} }
} }
@@ -285,7 +166,15 @@ public static class GroupInt64Codec
if (z <= 0xFFFFFFFFFFFFul) return aligned ? 8 : 6; if (z <= 0xFFFFFFFFFFFFul) return aligned ? 8 : 6;
if (z <= 0xFFFFFFFFFFFFFFul) return aligned ? 8 : 7; if (z <= 0xFFFFFFFFFFFFFFul) return aligned ? 8 : 7;
return 8; return 8;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -295,50 +184,23 @@ public static class GroupInt64Codec
dst.Add((byte)((value >> (8 * i)) & 0xFF)); dst.Add((byte)((value >> (8 * i)) & 0xFF));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width)
{
for (int i = 0; i < width; i++)
dst.Add((byte)((value >> (8 * i)) & 0xFF));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
ulong v = 0; ulong v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (ulong)src[pos++] << (8 * i); v |= (ulong)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
+63 -65
View File
@@ -6,17 +6,6 @@ namespace Esiur.Data.Gvwie;
public static class GroupUInt16Codec public static class GroupUInt16Codec
{ {
// Header layout:
// 1 | cccccc | w
//
// MSB = 1 => grouped form
// cccccc = 0..62 => short count = cccccc + 1 (1..63)
// cccccc = 63 => extended count, followed by varint(count - 64)
// w = 0 => width = 1 byte
// w = 1 => width = 2 bytes
//
// MSB = 0 => literal fast path for values in 7 bits
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<ushort> values) public static byte[] Encode(IList<ushort> values)
{ {
@@ -36,7 +25,7 @@ public static class GroupUInt16Codec
} }
int start = i; int start = i;
int width = WidthFromValue(v); // 1 or 2 int width = WidthFromUInt16(v); // 1..2
int count = 1; int count = 1;
// Build a run of same-width non-literal values // Build a run of same-width non-literal values
@@ -48,17 +37,18 @@ public static class GroupUInt16Codec
if (v2 <= 0x7F) if (v2 <= 0x7F)
break; break;
int w2 = WidthFromValue(v2); int w2 = WidthFromUInt16(v2);
if (w2 != width) if (w2 != width)
break; break;
count++; count++;
} }
if (count <= 63) if (count <= 60)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[6 bits] | (width-1)[1 bit] // Header: 1 | (count-1)[6 bits] | (width-1)[1 bit]
// count field 000000..111011 => count 1..60
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x3F) << 1); header |= (byte)(((count - 1) & 0x3F) << 1);
header |= (byte)((width - 1) & 0x01); header |= (byte)((width - 1) & 0x01);
@@ -67,13 +57,33 @@ public static class GroupUInt16Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 111111 | (width-1)[1 bit] // Header: 1 | g[6 bits] | (width-1)[1 bit]
// Followed by varint(count - 64) //
// g = 111100 => LoL = 1 byte
// g = 111101 => LoL = 2 bytes
// g = 111110 => LoL = 3 bytes
// g = 111111 => LoL = 4 bytes
//
// LoL stores (count - 61) in little-endian form.
uint extra = checked((uint)(count - 61));
int lol = LengthOfLength(extra);
byte groupBits = lol switch
{
1 => 0b111100,
2 => 0b111101,
3 => 0b111110,
4 => 0b111111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x7E; // count bits = 111111 header |= (byte)(groupBits << 1);
header |= (byte)((width - 1) & 0x01); header |= (byte)((width - 1) & 0x01);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, (uint)(count - 64));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' values, LE, 'width' bytes each // Payload: 'count' values, LE, 'width' bytes each
@@ -98,30 +108,36 @@ public static class GroupUInt16Codec
if ((h & 0x80) == 0) if ((h & 0x80) == 0)
{ {
// Fast path: literal 7-bit unsigned value // Fast path: 7-bit literal in low bits
result.Add((ushort)(h & 0x7F)); result.Add((ushort)(h & 0x7F));
continue; continue;
} }
int countField = (h >> 1) & 0x3F; int countField = (h >> 1) & 0x3F;
int width = (h & 0x01) + 1; // 1 or 2 int width = (h & 0x01) + 1;
int count; int count;
if (countField == 63)
if (countField <= 59)
{ {
uint extra = ReadVarUInt32(src, ref pos); // Short group: 0..59 => count 1..60
count = checked(64 + (int)extra); count = countField + 1;
} }
else else
{ {
count = countField + 1; // Extended group:
// 60 => LoL=1
// 61 => LoL=2
// 62 => LoL=3
// 63 => LoL=4
int lol = countField - 59;
uint extra = ReadLE(src, ref pos, lol);
count = checked(61 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ result.Add((ushort)ReadLE(src, ref pos, width));
ushort raw = (ushort)ReadLE(src, ref pos, width);
result.Add(raw);
}
} }
return result.ToArray(); return result.ToArray();
@@ -130,11 +146,20 @@ public static class GroupUInt16Codec
// ----------------- Helpers ----------------- // ----------------- Helpers -----------------
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int WidthFromValue(ushort v) private static int WidthFromUInt16(ushort v)
{ {
return v <= 0xFF ? 1 : 2; return v <= 0xFF ? 1 : 2;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, ushort value, int width) private static void WriteLE(List<byte> dst, ushort value, int width)
{ {
@@ -142,50 +167,23 @@ public static class GroupUInt16Codec
dst.Add((byte)((value >> (8 * i)) & 0xFF)); dst.Add((byte)((value >> (8 * i)) & 0xFF));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width)
{
for (int i = 0; i < width; i++)
dst.Add((byte)((value >> (8 * i)) & 0xFF));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
uint v = 0; uint v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (uint)src[pos++] << (8 * i); v |= (uint)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
+59 -67
View File
@@ -6,16 +6,6 @@ namespace Esiur.Data.Gvwie;
public static class GroupUInt32Codec public static class GroupUInt32Codec
{ {
// Header layout:
// 1 | ccccc | ww
//
// MSB = 1 => grouped form
// ccccc = 0..30 => short count = ccccc + 1 (1..31)
// ccccc = 31 => extended count, followed by varint(count - 32)
// ww = 0..3 => width = ww + 1 (1..4)
//
// MSB = 0 => literal fast path for values in 7 bits
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<uint> values, bool aligned = false) public static byte[] Encode(IList<uint> values, bool aligned = false)
{ {
@@ -35,7 +25,7 @@ public static class GroupUInt32Codec
} }
int start = i; int start = i;
int width = WidthFromValue(v, aligned); int width = WidthFromUInt32(v, aligned);
int count = 1; int count = 1;
// Build a run of same-width non-literal values // Build a run of same-width non-literal values
@@ -47,17 +37,18 @@ public static class GroupUInt32Codec
if (v2 <= 0x7Fu) if (v2 <= 0x7Fu)
break; break;
int w2 = WidthFromValue(v2, aligned); int w2 = WidthFromUInt32(v2, aligned);
if (w2 != width) if (w2 != width)
break; break;
count++; count++;
} }
if (count <= 31) if (count <= 28)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[5 bits] | (width-1)[2 bits] // Header: 1 | (count-1)[5 bits] | (width-1)[2 bits]
// count field 00000..11011 => count 1..28
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x1F) << 2); header |= (byte)(((count - 1) & 0x1F) << 2);
header |= (byte)((width - 1) & 0x03); header |= (byte)((width - 1) & 0x03);
@@ -66,13 +57,33 @@ public static class GroupUInt32Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 11111 | (width-1)[2 bits] // Header: 1 | g[5 bits] | (width-1)[2 bits]
// Followed by varint(count - 32) //
// g = 11100 => LoL = 1 byte
// g = 11101 => LoL = 2 bytes
// g = 11110 => LoL = 3 bytes
// g = 11111 => LoL = 4 bytes
//
// LoL stores (count - 29) in little-endian form.
uint extra = checked((uint)(count - 29));
int lol = LengthOfLength(extra);
byte groupBits = lol switch
{
1 => 0b11100,
2 => 0b11101,
3 => 0b11110,
4 => 0b11111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x7C; // count bits = 11111 header |= (byte)(groupBits << 2);
header |= (byte)((width - 1) & 0x03); header |= (byte)((width - 1) & 0x03);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, (uint)(count - 32));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' values, LE, 'width' bytes each // Payload: 'count' values, LE, 'width' bytes each
@@ -97,30 +108,36 @@ public static class GroupUInt32Codec
if ((h & 0x80) == 0) if ((h & 0x80) == 0)
{ {
// Fast path: literal 7-bit unsigned value // Fast path: 7-bit literal in low bits
result.Add((uint)(h & 0x7F)); result.Add((uint)(h & 0x7F));
continue; continue;
} }
int countField = (h >> 2) & 0x1F; int countField = (h >> 2) & 0x1F;
int width = (h & 0x03) + 1; // 1..4 int width = (h & 0x03) + 1;
int count; int count;
if (countField == 31)
if (countField <= 27)
{ {
uint extra = ReadVarUInt32(src, ref pos); // Short group: 0..27 => count 1..28
count = checked(32 + (int)extra); count = countField + 1;
} }
else else
{ {
count = countField + 1; // Extended group:
// 28 => LoL=1
// 29 => LoL=2
// 30 => LoL=3
// 31 => LoL=4
int lol = countField - 27;
uint extra = ReadLE(src, ref pos, lol);
count = checked(29 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ result.Add(ReadLE(src, ref pos, width));
uint raw = (uint)ReadLE(src, ref pos, width);
result.Add(raw);
}
} }
return result.ToArray(); return result.ToArray();
@@ -129,7 +146,7 @@ public static class GroupUInt32Codec
// ----------------- Helpers ----------------- // ----------------- Helpers -----------------
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int WidthFromValue(uint v, bool aligned = false) private static int WidthFromUInt32(uint v, bool aligned = false)
{ {
if (v <= 0xFFu) return 1; if (v <= 0xFFu) return 1;
if (v <= 0xFFFFu) return 2; if (v <= 0xFFFFu) return 2;
@@ -137,6 +154,15 @@ public static class GroupUInt32Codec
return 4; return 4;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width) private static void WriteLE(List<byte> dst, uint value, int width)
{ {
@@ -145,49 +171,15 @@ public static class GroupUInt32Codec
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
ulong v = 0; uint v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (ulong)src[pos++] << (8 * i); v |= (uint)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
+65 -66
View File
@@ -6,16 +6,6 @@ namespace Esiur.Data.Gvwie;
public static class GroupUInt64Codec public static class GroupUInt64Codec
{ {
// Header layout:
// 1 | cccc | www
//
// MSB = 1 => grouped form
// cccc = 0..14 => short count = cccc + 1 (1..15)
// cccc = 15 => extended count, followed by varint(count - 16)
// www = 0..7 => width = www + 1 (1..8)
//
// MSB = 0 => literal fast path for values in 7 bits
// ----------------- Encoder ----------------- // ----------------- Encoder -----------------
public static byte[] Encode(IList<ulong> values, bool aligned = false) public static byte[] Encode(IList<ulong> values, bool aligned = false)
{ {
@@ -35,7 +25,7 @@ public static class GroupUInt64Codec
} }
int start = i; int start = i;
int width = WidthFromValue(v, aligned); int width = WidthFromUInt64(v, aligned);
int count = 1; int count = 1;
// Build a run of same-width non-literal values // Build a run of same-width non-literal values
@@ -47,17 +37,18 @@ public static class GroupUInt64Codec
if (v2 <= 0x7Ful) if (v2 <= 0x7Ful)
break; break;
int w2 = WidthFromValue(v2, aligned); int w2 = WidthFromUInt64(v2, aligned);
if (w2 != width) if (w2 != width)
break; break;
count++; count++;
} }
if (count <= 15) if (count <= 12)
{ {
// Short group: // Short group:
// Header: 1 | (count-1)[4 bits] | (width-1)[3 bits] // Header: 1 | (count-1)[4 bits] | (width-1)[3 bits]
// count field 0000..1011 => count 1..12
byte header = 0x80; byte header = 0x80;
header |= (byte)(((count - 1) & 0x0F) << 3); header |= (byte)(((count - 1) & 0x0F) << 3);
header |= (byte)((width - 1) & 0x07); header |= (byte)((width - 1) & 0x07);
@@ -66,13 +57,33 @@ public static class GroupUInt64Codec
else else
{ {
// Extended group: // Extended group:
// Header: 1 | 1111 | (width-1)[3 bits] // Header: 1 | g[4 bits] | (width-1)[3 bits]
// Followed by varint(count - 16) //
// g = 1100 => LoL = 1 byte
// g = 1101 => LoL = 2 bytes
// g = 1110 => LoL = 3 bytes
// g = 1111 => LoL = 4 bytes
//
// LoL stores (count - 13) in little-endian form.
uint extra = checked((uint)(count - 13));
int lol = LengthOfLength(extra);
byte groupBits = lol switch
{
1 => 0b1100,
2 => 0b1101,
3 => 0b1110,
4 => 0b1111,
_ => throw new InvalidOperationException("Invalid LoL.")
};
byte header = 0x80; byte header = 0x80;
header |= 0x78; // count bits = 1111 header |= (byte)(groupBits << 3);
header |= (byte)((width - 1) & 0x07); header |= (byte)((width - 1) & 0x07);
dst.Add(header); dst.Add(header);
WriteVarUInt32(dst, checked((uint)(count - 16)));
WriteLE(dst, extra, lol);
} }
// Payload: 'count' values, LE, 'width' bytes each // Payload: 'count' values, LE, 'width' bytes each
@@ -97,30 +108,36 @@ public static class GroupUInt64Codec
if ((h & 0x80) == 0) if ((h & 0x80) == 0)
{ {
// Fast path: literal 7-bit unsigned value // Fast path: 7-bit literal in low bits
result.Add((ulong)(h & 0x7F)); result.Add((ulong)(h & 0x7F));
continue; continue;
} }
int countField = (h >> 3) & 0x0F; int countField = (h >> 3) & 0x0F;
int width = (h & 0x07) + 1; // 1..8 int width = (h & 0x07) + 1;
int count; int count;
if (countField == 15)
if (countField <= 11)
{ {
uint extra = ReadVarUInt32(src, ref pos); // Short group: 0..11 => count 1..12
count = checked(16 + (int)extra); count = countField + 1;
} }
else else
{ {
count = countField + 1; // Extended group:
// 12 => LoL=1
// 13 => LoL=2
// 14 => LoL=3
// 15 => LoL=4
int lol = countField - 11;
uint extra = checked((uint)ReadLE(src, ref pos, lol));
count = checked(13 + (int)extra);
} }
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ result.Add(ReadLE(src, ref pos, width));
ulong raw = ReadLE(src, ref pos, width);
result.Add(raw);
}
} }
return result.ToArray(); return result.ToArray();
@@ -129,18 +146,27 @@ public static class GroupUInt64Codec
// ----------------- Helpers ----------------- // ----------------- Helpers -----------------
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int WidthFromValue(ulong v, bool aligned = false) private static int WidthFromUInt64(ulong v, bool aligned = false)
{ {
if (v <= 0xFFul) return 1; if (v <= 0xFFul) return 1;
if (v <= 0xFFFFul) return 2; if (v <= 0xFFFFul) return 2;
if (v <= 0xFFFFFFul) return aligned ? 4 : 3; if (v <= 0xFFFFFFul) return aligned ? 4 : 3;
if (v <= 0xFFFFFFFFul) return 4; if (v <= 0xFFFFFFFFul) return 4;
if (v <= 0xFFFFFFFFFFul) return aligned ? 8: 5; if (v <= 0xFFFFFFFFFFul) return aligned ? 8 : 5;
if (v <= 0xFFFFFFFFFFFFul) return aligned ? 8: 6; if (v <= 0xFFFFFFFFFFFFul) return aligned ? 8 : 6;
if (v <= 0xFFFFFFFFFFFFFFul) return aligned ? 8 : 7; if (v <= 0xFFFFFFFFFFFFFFul) return aligned ? 8 : 7;
return 8; return 8;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LengthOfLength(uint value)
{
if (value <= 0xFFu) return 1;
if (value <= 0xFFFFu) return 2;
if (value <= 0xFFFFFFu) return 3;
return 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, ulong value, int width) private static void WriteLE(List<byte> dst, ulong value, int width)
{ {
@@ -148,50 +174,23 @@ public static class GroupUInt64Codec
dst.Add((byte)((value >> (8 * i)) & 0xFF)); dst.Add((byte)((value >> (8 * i)) & 0xFF));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteLE(List<byte> dst, uint value, int width)
{
for (int i = 0; i < width; i++)
dst.Add((byte)((value >> (8 * i)) & 0xFF));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width) private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
{ {
if ((uint)(pos + width) > (uint)src.Length) if ((uint)(pos + width) > (uint)src.Length)
throw new ArgumentException("Buffer underflow while reading group payload."); throw new ArgumentException("Buffer underflow while reading payload.");
ulong v = 0; ulong v = 0;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
v |= (ulong)src[pos++] << (8 * i); v |= (ulong)src[pos++] << (8 * i);
return v; return v;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteVarUInt32(List<byte> dst, uint value)
{
while (value >= 0x80)
{
dst.Add((byte)((value & 0x7F) | 0x80));
value >>= 7;
}
dst.Add((byte)value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadVarUInt32(ReadOnlySpan<byte> src, ref int pos)
{
uint result = 0;
int shift = 0;
while (true)
{
if (pos >= src.Length)
throw new ArgumentException("Buffer underflow while reading varint.");
byte b = src[pos++];
result |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
if (shift >= 35)
throw new ArgumentException("Varint is too long for UInt32.");
}
}
} }
@@ -24,7 +24,7 @@ public static class IntArrayGenerator
/// - minGap / maxGap: approximate gap between runs (large gaps produce the jump examples) /// - minGap / maxGap: approximate gap between runs (large gaps produce the jump examples)
/// </summary> /// </summary>
/// ///
public static void InitRng() => rng = new Random(24241564); public static void InitRng(int seed= 24241564) => rng = new Random(seed);
public static long[] GenerateRuns(int length, public static long[] GenerateRuns(int length,
int minRunSize = 3, int minRunSize = 3,
+2 -2
View File
@@ -32,7 +32,7 @@ namespace Esiur.Tests.Gvwie
const int TEST_ITERATIONS = 100; const int TEST_ITERATIONS = 100;
const int SAMPLE_SIZE = 100; const int SAMPLE_SIZE = 100;
Console.WriteLine(";Esiur;FlatBuffer;ProtoBuffer,MessagePack;BSON;CBOR;Avro,Optimal"); Console.WriteLine(";Esiur;Aligned;FlatBuffer;ProtoBuffer,MessagePack;BSON;CBOR;Avro,Optimal");
@@ -177,7 +177,7 @@ namespace Esiur.Tests.Gvwie
var file = $"run_chart_{gen.name}.csv"; var file = $"run_chart_{gen.name}.csv";
System.IO.File.WriteAllText(file, sb.ToString()); System.IO.File.WriteAllText(file, sb.ToString());
var file2 = $"optimal_chart_{gen.name}.csv"; var file2 = $"optimal_chart_{gen.name}.csv";
System.IO.File.WriteAllText(file, sbr.ToString()); System.IO.File.WriteAllText(file2, sbr.ToString());
Console.WriteLine($"Chart CSV written to: {file} {file2}"); Console.WriteLine($"Chart CSV written to: {file} {file2}");
} }
+16 -2
View File
@@ -5,13 +5,27 @@ using MessagePack;
var e = GroupInt32Codec.Encode(new int[] {-12000, 15000, -1, 32760 }); var e = GroupInt32Codec.Encode(new int[] {-12000, 15000, -1, 32760 });
var test = IntArrayGenerator.GenerateInt32(5000, GeneratorPattern.Uniform);
var aligned = GroupInt32Codec.Encode(test, true);
var nonAligned = GroupInt32Codec.Encode(test, false);
var result1 = GroupInt32Codec.Decode(aligned);
var result2 = GroupInt32Codec.Decode(nonAligned);
if (result1.SequenceEqual(result2))
Console.WriteLine($"Passed {aligned.Length}");
if (result1.SequenceEqual(test))
Console.WriteLine($"Passed {nonAligned.Length}");
MessagePack.MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard MessagePack.MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard
.WithCompression(MessagePackCompression.None); // optional; remove if you want raw size .WithCompression(MessagePackCompression.None); // optional; remove if you want raw size
var ints = new IntArrayRunner(); var ints = new IntArrayRunner();
IntArrayGenerator.InitRng(); //IntArrayGenerator.InitRng();
ints.Run(); //ints.Run();
IntArrayGenerator.InitRng(); IntArrayGenerator.InitRng();
ints.RunChart(); ints.RunChart();