该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

211 行
7.9 KiB

using Unity.Sample.Core;
using UnityEngine;
namespace NetworkCompression
{
public static class NetworkCompressionUtils
{
public static int CalculateBucket(uint value)
{
int bucketIndex = 0;
while (bucketIndex + 1 < NetworkCompressionConstants.k_NumBuckets && value >= NetworkCompressionConstants.k_BucketOffsets[bucketIndex + 1]) // TODO: use CountLeadingZeros to do this in constant time
bucketIndex++;
return bucketIndex;
}
public static int CountLeadingZeros(uint value)
{
int n = 0;
while (value != 0)
{
value >>= 1;
n++;
}
return 32 - n;
}
public static int CalculateNumGammaBits(long value)
{
int numOutputBits = 1;
int numPrefixBits = 0;
while (value >= (1L << numOutputBits)) // RUTODO: Unroll this and merge with bit output. How do we actually verify inlining in C#?
{
value -= (1L << numOutputBits);
numOutputBits += 2;
numPrefixBits++;
}
return numPrefixBits + 1 + numOutputBits;
}
public static void GenerateLengthLimitedHuffmanCodeLengths(byte[] symbolLengths, int symbolLengthsOffset, int[] symbolFrequencies, int alphabetSize, int maxCodeLength)
{
GameDebug.Assert(alphabetSize <= 255);
GameDebug.Assert(maxCodeLength <= 8);
var sortEntries = new SortEntry[alphabetSize];
int lastNonZeroIndex = 0;
int numSortEntries = 0;
for (int symbol = 0; symbol < alphabetSize; symbol++)
{
symbolLengths[symbol + symbolLengthsOffset] = 0;
int frequency = symbolFrequencies[symbol];
if (frequency > 0)
{
lastNonZeroIndex = symbol;
sortEntries[numSortEntries].frequency = frequency;
sortEntries[numSortEntries].symbol = (byte)symbol;
numSortEntries++;
}
}
if (numSortEntries == 1)
{
symbolLengths[lastNonZeroIndex] = 1;
return;
}
System.Array.Resize(ref sortEntries, numSortEntries);
System.Array.Sort(sortEntries, (a, b) => a.frequency - b.frequency);
int numNodes = alphabetSize * maxCodeLength * 2;
var nodes = new Node[numNodes];
for (int i = 0; i < numNodes; i++)
nodes[i] = new Node();
int nodesPointer = 0;
int numPrevNodes = 0;
int prevNodesPointer = 0;
for (int length = 1; length <= maxCodeLength; length++)
{
int num_a = numPrevNodes;
int num_b = numSortEntries;
int aPointer = prevNodesPointer;
prevNodesPointer = nodesPointer;
numPrevNodes = 0;
while (num_a >= 2 || num_b > 0)
{
if (num_b > 0 && (num_a < 2 || sortEntries[numSortEntries - num_b].frequency <= nodes[aPointer + 0].frequency + nodes[aPointer + 1].frequency))
{
var e = sortEntries[numSortEntries - num_b];
var node = nodes[nodesPointer++];
node.frequency = e.frequency;
node.symbol = e.symbol;
num_b--;
}
else
{
var node = nodes[nodesPointer++];
node.frequency = nodes[aPointer + 0].frequency + nodes[aPointer + 1].frequency;
node.symbol = 0xFF;
node.leftChild = nodes[aPointer + 0];
node.rightChild = nodes[aPointer + 1];
num_a -= 2;
aPointer += 2;
}
numPrevNodes++;
}
}
int numActive = 2 * numSortEntries - 2;
for (int i = 0; i < numActive; i++)
{
GenerateLengthLimitedHuffmanCodeLengthsRecursive(nodes[prevNodesPointer + i], symbolLengths);
}
}
public static void GenerateHuffmanCodes(byte[] symboLCodes, int symbolCodesOffset, byte[] symbolLengths, int symbolLengthsOffset, int alphabetSize, int maxCodeLength)
{
GameDebug.Assert(alphabetSize <= 256);
GameDebug.Assert(maxCodeLength <= 8);
var lengthCounts = new byte[maxCodeLength + 1];
var symbolList = new byte[maxCodeLength + 1, alphabetSize];
//byte[] symbol_list[(MAX_HUFFMAN_CODE_LENGTH + 1u) * MAX_NUM_HUFFMAN_SYMBOLS];
for (int symbol = 0; symbol < alphabetSize; symbol++)
{
int length = symbolLengths[symbol + symbolLengthsOffset];
GameDebug.Assert(length <= maxCodeLength);
symbolList[length, lengthCounts[length]++] = (byte)symbol;
}
uint nextCodeWord = 0;
for (int length = 1; length <= maxCodeLength; length++)
{
int length_count = lengthCounts[length];
for (int i = 0; i < length_count; i++)
{
int symbol = symbolList[length, i];
GameDebug.Assert(symbolLengths[symbol + symbolLengthsOffset] == length);
symboLCodes[symbol + symbolCodesOffset] = (byte)ReverseBits(nextCodeWord++, length);
}
nextCodeWord <<= 1;
}
}
// decode table entries: (symbol << 8) | length
public static void GenerateHuffmanDecodeTable(ushort[] decodeTable, int decodeTableOffset, byte[] symbolLengths, byte[] symbolCodes, int alphabetSize, int maxCodeLength)
{
GameDebug.Assert(alphabetSize <= 256);
GameDebug.Assert(maxCodeLength <= 8);
uint maxCode = 1u << maxCodeLength;
for (int symbol = 0; symbol < alphabetSize; symbol++)
{
int length = symbolLengths[symbol];
GameDebug.Assert(length <= maxCodeLength);
if (length > 0)
{
uint code = symbolCodes[symbol];
uint step = 1u << length;
do
{
decodeTable[decodeTableOffset + code] = (ushort)(symbol << 8 | length);
code += step;
}
while (code < maxCode);
}
}
}
private static uint ReverseBits(uint value, int num_bits)
{
value = ((value & 0x55555555u) << 1) | ((value & 0xAAAAAAAAu) >> 1);
value = ((value & 0x33333333u) << 2) | ((value & 0xCCCCCCCCu) >> 2);
value = ((value & 0x0F0F0F0Fu) << 4) | ((value & 0xF0F0F0F0u) >> 4);
value = ((value & 0x00FF00FFu) << 8) | ((value & 0xFF00FF00u) >> 8);
value = (value << 16) | (value >> 16);
return value >> (32 - num_bits);
}
private class Node
{
public byte symbol;
public int frequency;
public Node leftChild;
public Node rightChild;
};
private struct SortEntry
{
public byte symbol;
public int frequency;
};
private static void GenerateLengthLimitedHuffmanCodeLengthsRecursive(Node node, byte[] symbolLengths)
{
if (node.symbol == 0xFF)
{
GenerateLengthLimitedHuffmanCodeLengthsRecursive(node.leftChild, symbolLengths);
GenerateLengthLimitedHuffmanCodeLengthsRecursive(node.rightChild, symbolLengths);
}
else
{
symbolLengths[node.symbol]++;
}
}
}
}