Example #1
0
int ZopfliLengthLimitedCodeLengths(
    const size_t* frequencies, int n, int maxbits, unsigned* bitlengths) {
  Node* pool;
  int i;
  int numsymbols = 0;  /* Amount of symbols with frequency > 0. */
  int numBoundaryPMRuns;
  Node* nodes;
  unsigned char stack[16];

  /* Array of lists of chains. Each list requires only two lookahead chains at
  a time, so each list is a array of two Node*'s. */
  Node* (*lists)[2];

  /* One leaf per symbol. Only numsymbols leaves will be used. */
  Node* leaves = (Node*)malloc(n * sizeof(*leaves));

  /* Initialize all bitlengths at 0. */
  for (i = 0; i < n; i++) {
    bitlengths[i] = 0;
  }

  /* Count used symbols and place them in the leaves. */
  for (i = 0; i < n; i++) {
    if (frequencies[i]) {
      leaves[numsymbols].weight = frequencies[i];
      leaves[numsymbols].count = i;  /* Index of symbol this leaf represents. */
      numsymbols++;
    }
  }

  /* Check special cases and error conditions. */
  if ((1 << maxbits) < numsymbols) {
    free(leaves);
    return 1;  /* Error, too few maxbits to represent symbols. */
  }
  if (numsymbols == 0) {
    free(leaves);
    return 0;  /* No symbols at all. OK. */
  }
  if (numsymbols == 1) {
    bitlengths[leaves[0].count] = 1;
    free(leaves);
    return 0;  /* Only one symbol, give it bitlength 1, not 0. OK. */
  }
  if (numsymbols == 2) {
    bitlengths[leaves[0].count]++;
    bitlengths[leaves[1].count]++;
    free(leaves);
    return 0;
  }

  /* Sort the leaves from lightest to heaviest. Add count into the same
  variable for stable sorting. */
  for (i = 0; i < numsymbols; i++) {
    if (leaves[i].weight >=
        ((size_t)1 << (sizeof(leaves[0].weight) * CHAR_BIT - 9))) {
      free(leaves);
      return 1;  /* Error, we need 9 bits for the count. */
    }
    leaves[i].weight = (leaves[i].weight << 9) | leaves[i].count;
  }
  qsort(leaves, numsymbols, sizeof(Node), LeafComparator);
  for (i = 0; i < numsymbols; i++) {
    leaves[i].weight >>= 9;
  }

  if (numsymbols - 1 < maxbits) {
    maxbits = numsymbols - 1;
  }

  /* Initialize node memory pool. */
  nodes = (Node*)malloc(maxbits * 2 * numsymbols * sizeof(Node));
  pool = nodes;

  lists = (Node* (*)[2])malloc(maxbits * sizeof(*lists));
  InitLists(pool, leaves, maxbits, lists);
  pool += 2;

  /* In the last list, 2 * numsymbols - 2 active chains need to be created. Two
  are already created in the initialization. Each BoundaryPM run creates one. */
  numBoundaryPMRuns = 2 * numsymbols - 4;
  for (i = 0; i < numBoundaryPMRuns - 1; i++) {
    /*
    Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
    new chain is, depending on the weights, a leaf or a combination of two chains
    from the previous list.
    */
    unsigned stackpos;
    stack[0] = maxbits - 1;

    for (stackpos = 0; ;) {
      unsigned char index = stack[stackpos];

      int lastcount = lists[index][1]->count;  /* Count of last chain of list. */

      Node* newchain = pool++;
      Node* oldchain = lists[index][1];
      size_t sum;

      /* These are set up before the recursive calls below, so that there is a list
      pointing to the new node, to let the garbage collection know it's in use. */
      lists[index][0] = oldchain;
      lists[index][1] = newchain;

      sum = lists[index - 1][0]->weight + lists[index - 1][1]->weight;

      if (lastcount < numsymbols && sum > leaves[lastcount].weight) {
        /* New leaf inserted in list, so count is incremented. */
        InitNode(leaves[lastcount].weight, lastcount + 1, oldchain->tail, newchain);
      } else {
        InitNode(sum, lastcount, lists[index - 1][1], newchain);
        /* Two lookahead chains of previous list used up, create new ones. */
        if (index == 1) {
          if (lists[0][1]->count < numsymbols) {
            lastcount = lists[0][1]->count;
            lists[0][0] = lists[0][1];
            lists[0][1] = pool++;
            InitNode(leaves[lastcount].weight, lastcount + 1, 0, lists[0][1]);
            lastcount++;
            if(lastcount < numsymbols){
              lists[0][0] = lists[0][1];
              lists[0][1] = pool++;
              InitNode(leaves[lastcount].weight, lastcount + 1, 0, lists[0][1]);
            }
          }
        }
        else {
          stack[stackpos++] = index - 1;
          stack[stackpos++] = index - 1;
        }
      }
      if (!stackpos--) {
        break;
      }
    }
  }
  BoundaryPMFinal(lists, leaves, numsymbols, pool, maxbits - 1);

  ExtractBitLengths(lists[maxbits - 1][1], leaves, bitlengths);

  free(lists);
  free(leaves);
  free(nodes);
  return 0;  /* OK. */
}
void ZopfliLengthLimitedCodeLengths(const size_t* frequencies, int n, int maxbits, unsigned* bitlengths) {
  int i;
  int numsymbols = 0;  /* Amount of symbols with frequency > 0. */

  /* Array of lists of chains. Each list requires only two lookahead chains at
  a time, so each list is a array of two Node*'s. */

  /* One leaf per symbol. Only numsymbols leaves will be used. */
  Node* leaves = (Node*)malloc(n * sizeof(*leaves));
  if (!leaves){
    exit(1);
  }

  /* Initialize all bitlengths at 0. */
  memset(bitlengths, 0, n * sizeof(int));

  /* Count used symbols and place them in the leaves. */
  for (i = 0; i < n; i++) {
    if (frequencies[i]) {
      leaves[numsymbols].weight = frequencies[i];
      leaves[numsymbols].count = i;  /* Index of symbol this leaf represents. */
      numsymbols++;
    }
  }

  /* Check special cases and error conditions. */
  assert((1 << maxbits) >= numsymbols); /* Error, too few maxbits to represent symbols. */
  if (numsymbols == 0) {
    free(leaves);
    return;  /* No symbols at all. OK. */
  }
  if (numsymbols == 1) {
    bitlengths[leaves[0].count] = 1;
    free(leaves);
    return;  /* Only one symbol, give it bitlength 1, not 0. OK. */
  }
  if (numsymbols == 2){
    bitlengths[leaves[0].count]++;
    bitlengths[leaves[1].count]++;

    free(leaves);
    return;
  }

  /* Sort the leaves from lightest to heaviest. */
  qsort(leaves, numsymbols, sizeof(Node), LeafComparator);

  /* Initialize node memory pool. */
  NodePool pool;
  pool.size = 2 * maxbits * (maxbits + 1);
  pool.nodes = (Node*)calloc(pool.size, sizeof(*pool.nodes));
  if (!pool.nodes){
    exit(1);
  }
  pool.next = pool.nodes;

  Node* (*lists)[2] = (Node* (*)[2])malloc(maxbits * sizeof(*lists));
  if (!lists || !lists[0] || !lists[1]){
    exit(1);
  }
  InitLists(&pool, leaves, maxbits, lists);

  /* In the last list, 2 * numsymbols - 2 active chains need to be created. Two
  are already created in the initialization. Each BoundaryPM run creates one. */
  int numBoundaryPMRuns = 2 * numsymbols - 4;
  for (i = 0; i < numBoundaryPMRuns - 1; i++) {
    BoundaryPM(lists, maxbits, leaves, numsymbols, &pool, maxbits - 1);
  }
  BoundaryPMfinal(lists, maxbits, leaves, numsymbols, &pool, maxbits - 1);

  ExtractBitLengths(lists[maxbits - 1][1], leaves, bitlengths);

  free(lists);
  free(leaves);
  free(pool.nodes);
  return;  /* OK. */
}