Huffman.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. namespace System.Net.ApiService.Compression.Brotli {
  2. /// <summary>Utilities for building Huffman decoding tables.</summary>
  3. internal sealed class Huffman {
  4. /// <summary>
  5. /// Maximum possible Huffman table size for an alphabet size of 704, max code length 15 and root
  6. /// table bits 8.
  7. /// </summary>
  8. internal const int HuffmanMaxTableSize = 1080;
  9. private const int MaxLength = 15;
  10. /// <summary>Returns reverse(reverse(key, len) + 1, len).</summary>
  11. /// <remarks>
  12. /// Returns reverse(reverse(key, len) + 1, len).
  13. /// <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
  14. /// </remarks>
  15. private static int GetNextKey(int key, int len) {
  16. int step = 1 << (len - 1);
  17. while ((key & step) != 0) {
  18. step >>= 1;
  19. }
  20. return (key & (step - 1)) + step;
  21. }
  22. /// <summary>
  23. /// Stores
  24. /// <paramref name="item"/>
  25. /// in
  26. /// <c>table[0], table[step], table[2 * step] .., table[end]</c>
  27. /// .
  28. /// <p> Assumes that end is an integer multiple of step.
  29. /// </summary>
  30. private static void ReplicateValue(int[] table, int offset, int step, int end, int item) {
  31. do {
  32. end -= step;
  33. table[offset + end] = item;
  34. }
  35. while (end > 0);
  36. }
  37. /// <param name="count">histogram of bit lengths for the remaining symbols,</param>
  38. /// <param name="len">code length of the next processed symbol.</param>
  39. /// <returns>table width of the next 2nd level table.</returns>
  40. private static int NextTableBitSize(int[] count, int len, int rootBits) {
  41. int left = 1 << (len - rootBits);
  42. while (len < MaxLength) {
  43. left -= count[len];
  44. if (left <= 0) {
  45. break;
  46. }
  47. len++;
  48. left <<= 1;
  49. }
  50. return len - rootBits;
  51. }
  52. /// <summary>Builds Huffman lookup table assuming code lengths are in symbol order.</summary>
  53. internal static void BuildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths, int codeLengthsSize) {
  54. int key;
  55. // Reversed prefix code.
  56. int[] sorted = new int[codeLengthsSize];
  57. // Symbols sorted by code length.
  58. // TODO: fill with zeroes?
  59. int[] count = new int[MaxLength + 1];
  60. // Number of codes of each length.
  61. int[] offset = new int[MaxLength + 1];
  62. // Offsets in sorted table for each length.
  63. int symbol;
  64. // Build histogram of code lengths.
  65. for (symbol = 0; symbol < codeLengthsSize; symbol++) {
  66. count[codeLengths[symbol]]++;
  67. }
  68. // Generate offsets into sorted symbol table by code length.
  69. offset[1] = 0;
  70. for (int len = 1; len < MaxLength; len++) {
  71. offset[len + 1] = offset[len] + count[len];
  72. }
  73. // Sort symbols by length, by symbol order within each length.
  74. for (symbol = 0; symbol < codeLengthsSize; symbol++) {
  75. if (codeLengths[symbol] != 0) {
  76. sorted[offset[codeLengths[symbol]]++] = symbol;
  77. }
  78. }
  79. int tableBits = rootBits;
  80. int tableSize = 1 << tableBits;
  81. int totalSize = tableSize;
  82. // Special case code with only one value.
  83. if (offset[MaxLength] == 1) {
  84. for (key = 0; key < totalSize; key++) {
  85. rootTable[tableOffset + key] = sorted[0];
  86. }
  87. return;
  88. }
  89. // Fill in root table.
  90. key = 0;
  91. symbol = 0;
  92. for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
  93. for (; count[len] > 0; count[len]--) {
  94. ReplicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
  95. key = GetNextKey(key, len);
  96. }
  97. }
  98. // Fill in 2nd level tables and add pointers to root table.
  99. int mask = totalSize - 1;
  100. int low = -1;
  101. int currentOffset = tableOffset;
  102. for (int len = rootBits + 1, step = 2; len <= MaxLength; len++, step <<= 1) {
  103. for (; count[len] > 0; count[len]--) {
  104. if ((key & mask) != low) {
  105. currentOffset += tableSize;
  106. tableBits = NextTableBitSize(count, len, rootBits);
  107. tableSize = 1 << tableBits;
  108. totalSize += tableSize;
  109. low = key & mask;
  110. rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
  111. }
  112. ReplicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
  113. key = GetNextKey(key, len);
  114. }
  115. }
  116. }
  117. }
  118. }