@Override
    public int encodeDoubles(int valCount, long inputAddr, long outputAddr, int outputLimit, Wrapper extraInfo) {
        if (valCount == 0) return 0;
        DoubleRBTreeSet dict = new DoubleRBTreeSet();

        int maxDictEntryCount = (int) Math.ceil(valCount * dictEntryRatioThreshold);
        for (int i = 0; i < valCount; i++) {
            if (dict.add(getDouble(inputAddr + (i << 3)))) {
                if (dict.size() > maxDictEntryCount) {
                    dict.clear();
                    return ErrorCode.DATA_IMPROPER;
                }
            }
        }

        DoubleIterator it = dict.iterator();
        double[] entries = new double[dict.size()];
        int id = 0;
        while (it.hasNext()) {
            entries[id] = it.nextDouble();
            id++;
        }
        assert id == dict.size();
        dict.clear();
        int dictEntryCount = entries.length;

        ByteSlice dataEntryIds = ByteSlice.allocateDirect(valCount << 2);
        for (int i = 0; i < valCount; i++) {
            double v = getDouble(inputAddr + (i << 3));
            int vid = DoubleArrays.binarySearch(entries, v);
            assert vid >= 0;
            // data index to entry id
            dataEntryIds.putInt(i << 2, vid);
        }

        // | dictSize |   dict   |  dataSize |  data(encoded ids) |
        //      4       dictSize       4           dataSize

        // Write dictionary entries.
        int dictEntriesCount = entries.length;
        int dictSize = dictEntriesCount << 3;
        UnsafeUtil.setInt(outputAddr, dictEntriesCount);
        UnsafeUtil.copyMemory(
                entries, UnsafeUtil.DOUBLE_ARRAY_OFFSET,
                null, outputAddr + 4,
                dictSize);
        // Write data entry ids.
        RLEPackingHybridCodec dataCodec = new RLEPackingHybridCodec(VarInteger.bitWidth(dictEntriesCount - 1));
        int dataSize = dataCodec.encodeInts(
                valCount,
                dataEntryIds.address(),
                outputAddr + 4 + dictSize + 4,
                outputLimit - (4 + dictSize + 4));
        if (dataSize < 0) {
            dataEntryIds.free();
            return dataSize;
        }
        UnsafeUtil.setInt(outputAddr + 4 + dictSize, dataSize);

        int encodedSize = 4 + dictSize + 4 + dataSize;
        if (encodedSize > outputLimit) {
            return ErrorCode.BUFFER_OVERFLOW;
        }
        return encodedSize;
    }
<pre>
| dictSize |   dict   |  dataSize |  data(encoded ids) |
     4       dictSize       4           dataSize
</pre>
indexr-vlt-segment/src/main/java/io/indexr/vlt/codec/dict/SimpleDictCodec.java