private void encodeWithPopulationCodec()

in modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java [380:547]


    private void encodeWithPopulationCodec(String name, int[] band,
            BHSDCodec defaultCodec, BandData bandData, BandAnalysisResults results) throws Pack200Exception {
        results.numCodecsTried += 3; // quite a bit more effort to try this codec
        final Map distinctValues = bandData.distinctValues;

        List favoured = new ArrayList();
        for (Iterator iterator = distinctValues.keySet().iterator(); iterator
                .hasNext();) {
            Integer value = (Integer) iterator.next();
            Integer count = (Integer) distinctValues.get(value);
            if(count.intValue() > 2 || distinctValues.size() < 256) { // TODO: tweak
                favoured.add(value);
            }
        }

        // Sort the favoured list with the most commonly occurring first
        if(distinctValues.size() > 255) {
            Collections.sort(favoured, new Comparator() {
                public int compare(Object arg0, Object arg1) {
                    return ((Integer)distinctValues.get(arg1)).compareTo((Integer)distinctValues.get(arg0));
                }
            });
        }

        IntList unfavoured = new IntList();
        Map favouredToIndex = new HashMap();
        for (int i = 0; i < favoured.size(); i++) {
            Integer value = (Integer) favoured.get(i);
            favouredToIndex.put(value, new Integer(i));
        }

        int[] tokens = new int[band.length];
        for (int i = 0; i < band.length; i++) {
            Integer favouredIndex = (Integer)favouredToIndex.get(new Integer(band[i]));
            if(favouredIndex == null) {
                tokens[i] = 0;
                unfavoured.add(band[i]);
            } else {
                tokens[i] = favouredIndex.intValue() + 1;
            }
        }
        favoured.add(favoured.get(favoured.size() - 1)); // repeat last value
        int[] favouredBand = integerListToArray(favoured);
        int[] unfavouredBand = unfavoured.toArray();

        // Analyse the three bands to get the best codec
        BandAnalysisResults favouredResults = analyseBand("POPULATION", favouredBand, defaultCodec);
        BandAnalysisResults unfavouredResults = analyseBand("POPULATION", unfavouredBand, defaultCodec);

        int tdefL = 0;
        int l = 0;
        Codec tokenCodec = null;
        byte[] tokensEncoded;
        int k = favoured.size() - 1;
        if(k < 256) {
            tdefL = 1;
            tokensEncoded = Codec.BYTE1.encode(tokens);
        } else {
            BandAnalysisResults tokenResults = analyseBand("POPULATION", tokens, defaultCodec);
            tokenCodec = tokenResults.betterCodec;
            tokensEncoded = tokenResults.encodedBand;
            if(tokenCodec == null) {
                tokenCodec = defaultCodec;
            }
            l = ((BHSDCodec) tokenCodec).getL();
            int h = ((BHSDCodec) tokenCodec).getH();
            int s = ((BHSDCodec) tokenCodec).getS();
            int b = ((BHSDCodec) tokenCodec).getB();
            int d = ((BHSDCodec) tokenCodec).isDelta() ? 1 : 0;
            if(s == 0 && d == 0) {
                boolean canUseTDefL = true;
                if(b > 1) {
                    BHSDCodec oneLowerB = new BHSDCodec(b-1, h);
                    if(oneLowerB.largest() >= k) {
                        canUseTDefL = false;
                    }
                }
                if(canUseTDefL) {
                    switch (l) {
                    case 4:
                        tdefL = 1;
                        break;
                    case 8:
                        tdefL = 2;
                        break;
                    case 16:
                        tdefL = 3;
                        break;
                    case 32:
                        tdefL = 4;
                        break;
                    case 64:
                        tdefL = 5;
                        break;
                    case 128:
                        tdefL = 6;
                        break;
                    case 192:
                        tdefL = 7;
                        break;
                    case 224:
                        tdefL = 8;
                        break;
                    case 240:
                        tdefL = 9;
                        break;
                    case 248:
                        tdefL = 10;
                        break;
                    case 252:
                        tdefL = 11;
                        break;
                    }
                }
            }
        }

        byte[] favouredEncoded = favouredResults.encodedBand;
        byte[] unfavouredEncoded = unfavouredResults.encodedBand;
        Codec favouredCodec = favouredResults.betterCodec;
        Codec unfavouredCodec = unfavouredResults.betterCodec;

        int specifier = 141 + (favouredCodec == null ? 1 : 0) + (4 * tdefL) + (unfavouredCodec == null ? 2 : 0);
        IntList extraBandMetadata = new IntList(3);
        if(favouredCodec != null) {
            int[] specifiers = CodecEncoding.getSpecifier(favouredCodec, null);
            for (int i = 0; i < specifiers.length; i++) {
                extraBandMetadata.add(specifiers[i]);
            }
        }
        if(tdefL == 0) {
            int[] specifiers = CodecEncoding.getSpecifier(tokenCodec, null);
            for (int i = 0; i < specifiers.length; i++) {
                extraBandMetadata.add(specifiers[i]);
            }
        }
        if(unfavouredCodec != null) {
            int[] specifiers = CodecEncoding.getSpecifier(unfavouredCodec, null);
            for (int i = 0; i < specifiers.length; i++) {
                extraBandMetadata.add(specifiers[i]);
            }
        }
        int[] extraMetadata = extraBandMetadata.toArray();
        byte[] extraMetadataEncoded = Codec.UNSIGNED5.encode(extraMetadata);
        if(defaultCodec.isSigned()) {
            specifier = -1 -specifier;
        } else {
            specifier = specifier + defaultCodec.getL();
        }
        byte[] firstValueEncoded = defaultCodec.encode(new int[] {specifier});
        int totalBandLength = firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length + unfavouredEncoded.length;

        if(totalBandLength + extraMetadataEncoded.length < results.encodedBand.length) {
            results.saved += results.encodedBand.length - (totalBandLength + extraMetadataEncoded.length);
            byte[] encodedBand = new byte[totalBandLength];
            System.arraycopy(firstValueEncoded, 0, encodedBand, 0, firstValueEncoded.length);
            System.arraycopy(favouredEncoded, 0, encodedBand, firstValueEncoded.length, favouredEncoded.length);
            System.arraycopy(tokensEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length, tokensEncoded.length);
            System.arraycopy(unfavouredEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length, unfavouredEncoded.length);
            results.encodedBand = encodedBand;
            results.extraMetadata = extraMetadata;
            if(l != 0) {
                results.betterCodec = new PopulationCodec(favouredCodec, l, unfavouredCodec);
            } else {
                results.betterCodec = new PopulationCodec(favouredCodec, tokenCodec, unfavouredCodec);
            }
        }
    }