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. */ }