static int BuildHuffmanTable()

in Extended/libwebp/src/utils/huffman_utils.c [80:206]


static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
                             const int code_lengths[], int code_lengths_size,
                             uint16_t sorted[]) {
  HuffmanCode* table = root_table;  // next available space in table
  int total_size = 1 << root_bits;  // total size root table + 2nd level table
  int len;                          // current code length
  int symbol;                       // symbol index in original or sorted table
  // number of codes of each length:
  int count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
  // offsets in sorted table for each length:
  int offset[MAX_ALLOWED_CODE_LENGTH + 1];

  assert(code_lengths_size != 0);
  assert(code_lengths != NULL);
  assert((root_table != NULL && sorted != NULL) ||
         (root_table == NULL && sorted == NULL));
  assert(root_bits > 0);

  // Build histogram of code lengths.
  for (symbol = 0; symbol < code_lengths_size; ++symbol) {
    if (code_lengths[symbol] > MAX_ALLOWED_CODE_LENGTH) {
      return 0;
    }
    ++count[code_lengths[symbol]];
  }

  // Error, all code lengths are zeros.
  if (count[0] == code_lengths_size) {
    return 0;
  }

  // Generate offsets into sorted symbol table by code length.
  offset[1] = 0;
  for (len = 1; len < MAX_ALLOWED_CODE_LENGTH; ++len) {
    if (count[len] > (1 << len)) {
      return 0;
    }
    offset[len + 1] = offset[len] + count[len];
  }

  // Sort symbols by length, by symbol order within each length.
  for (symbol = 0; symbol < code_lengths_size; ++symbol) {
    const int symbol_code_length = code_lengths[symbol];
    if (code_lengths[symbol] > 0) {
      if (sorted != NULL) {
        sorted[offset[symbol_code_length]++] = symbol;
      } else {
        offset[symbol_code_length]++;
      }
    }
  }

  // Special case code with only one value.
  if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
    if (sorted != NULL) {
      HuffmanCode code;
      code.bits = 0;
      code.value = (uint16_t)sorted[0];
      ReplicateValue(table, 1, total_size, code);
    }
    return total_size;
  }

  {
    int step;              // step size to replicate values in current table
    uint32_t low = -1;     // low bits for current root entry
    uint32_t mask = total_size - 1;    // mask for low bits
    uint32_t key = 0;      // reversed prefix code
    int num_nodes = 1;     // number of Huffman tree nodes
    int num_open = 1;      // number of open branches in current tree level
    int table_bits = root_bits;        // key length of current table
    int table_size = 1 << table_bits;  // size of current table
    symbol = 0;
    // Fill in root table.
    for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {
      num_open <<= 1;
      num_nodes += num_open;
      num_open -= count[len];
      if (num_open < 0) {
        return 0;
      }
      if (root_table == NULL) continue;
      for (; count[len] > 0; --count[len]) {
        HuffmanCode code;
        code.bits = (uint8_t)len;
        code.value = (uint16_t)sorted[symbol++];
        ReplicateValue(&table[key], step, table_size, code);
        key = GetNextKey(key, len);
      }
    }

    // Fill in 2nd level tables and add pointers to root table.
    for (len = root_bits + 1, step = 2; len <= MAX_ALLOWED_CODE_LENGTH;
         ++len, step <<= 1) {
      num_open <<= 1;
      num_nodes += num_open;
      num_open -= count[len];
      if (num_open < 0) {
        return 0;
      }
      if (root_table == NULL) continue;
      for (; count[len] > 0; --count[len]) {
        HuffmanCode code;
        if ((key & mask) != low) {
          table += table_size;
          table_bits = NextTableBitSize(count, len, root_bits);
          table_size = 1 << table_bits;
          total_size += table_size;
          low = key & mask;
          root_table[low].bits = (uint8_t)(table_bits + root_bits);
          root_table[low].value = (uint16_t)((table - root_table) - low);
        }
        code.bits = (uint8_t)(len - root_bits);
        code.value = (uint16_t)sorted[symbol++];
        ReplicateValue(&table[key >> root_bits], step, table_size, code);
        key = GetNextKey(key, len);
      }
    }

    // Check if tree is full.
    if (num_nodes != 2 * offset[MAX_ALLOWED_CODE_LENGTH] - 1) {
      return 0;
    }
  }

  return total_size;
}