private void mergeTypeIds() {
    new IdMerger<Integer>(idsDefsOut) {
      @Override
      TableOfContents.Section getSection(TableOfContents tableOfContents) {
        return tableOfContents.typeIds;
      }

      @Override
      Integer read(Dex.Section in, IndexMap indexMap, int index) {
        int stringIndex = in.readInt();
        return indexMap.adjustString(stringIndex);
      }

      @Override
      void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
        if (newIndex < 0 || newIndex > 0xffff) {
          throw new DexIndexOverflowException("type ID not in [0, 0xffff]: " + newIndex);
        }
        indexMap.typeIds[oldIndex] = (short) newIndex;
      }

      @Override
      void write(Integer value) {
        idsDefsOut.writeInt(value);
      }
    }.mergeSorted();
  }
minimum number of wasted bytes before it's worthwhile to compact the result
android/android_framework/dex-maker/src/main/java/com/android/dx/merge/DexMerger.java