Index: lucene/test-framework/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesConsumer.java
===================================================================
--- lucene/test-framework/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesConsumer.java	(révision 1531385)
+++ lucene/test-framework/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesConsumer.java	(copie de travail)
@@ -168,7 +168,7 @@
       data.writeLong(gcd);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, acceptableOverheadRatio);
       for (Number nv : values) {
         long value = nv == null ? 0 : nv.longValue();
         writer.add((value - minValue) / gcd);
@@ -180,7 +180,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, acceptableOverheadRatio);
       for (Number nv : values) {
         writer.add(nv == null ? 0 : nv.longValue());
       }
@@ -235,7 +235,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       meta.writeVInt(BLOCK_SIZE);
 
-      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE);
+      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE, acceptableOverheadRatio);
       long addr = 0;
       for (BytesRef v : values) {
         if (v != null) {
Index: lucene/core/src/test/org/apache/lucene/util/packed/TestPackedInts.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/util/packed/TestPackedInts.java	(révision 1531385)
+++ lucene/core/src/test/org/apache/lucene/util/packed/TestPackedInts.java	(copie de travail)
@@ -1118,7 +1118,7 @@
   
       final Directory dir = newDirectory();
       final IndexOutput out = dir.createOutput("out.bin", IOContext.DEFAULT);
-      final BlockPackedWriter writer = new BlockPackedWriter(out, blockSize);
+      final BlockPackedWriter writer = new BlockPackedWriter(out, blockSize, random().nextFloat() / 2);
       for (int i = 0; i < valueCount; ++i) {
         assertEquals(i, writer.ord());
         writer.add(values[i]);
@@ -1214,7 +1214,7 @@
 
       final Directory dir = newDirectory();
       final IndexOutput out = dir.createOutput("out.bin", IOContext.DEFAULT);
-      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(out, blockSize);
+      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(out, blockSize, random().nextFloat() / 2);
       for (int i = 0; i < valueCount; ++i) {
         assertEquals(i, writer.ord());
         writer.add(values[i]);
@@ -1242,7 +1242,7 @@
     final int blockSize = 1 << _TestUtil.nextInt(random(), 20, 22);
     final Directory dir = newDirectory();
     final IndexOutput out = dir.createOutput("out.bin", IOContext.DEFAULT);
-    final BlockPackedWriter writer = new BlockPackedWriter(out, blockSize);
+    final BlockPackedWriter writer = new BlockPackedWriter(out, blockSize, random().nextFloat() / 2);
     long value = random().nextInt() & 0xFFFFFFFFL;
     long valueOffset = _TestUtil.nextLong(random(), 0, valueCount - 1);
     for (long i = 0; i < valueCount; ) {
Index: lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42NormsConsumer.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42NormsConsumer.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42NormsConsumer.java	(copie de travail)
@@ -155,7 +155,7 @@
       data.writeLong(gcd);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, acceptableOverheadRatio);
       for (Number nv : values) {
         long value = nv == null ? 0 : nv.longValue();
         writer.add((value - minValue) / gcd);
@@ -167,7 +167,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, acceptableOverheadRatio);
       for (Number nv : values) {
         writer.add(nv == null ? 0 : nv.longValue());
       }
Index: lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesConsumer.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesConsumer.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesConsumer.java	(copie de travail)
@@ -164,7 +164,7 @@
       case GCD_COMPRESSED:
         meta.writeLong(minValue);
         meta.writeLong(gcd);
-        final BlockPackedWriter quotientWriter = new BlockPackedWriter(data, BLOCK_SIZE);
+        final BlockPackedWriter quotientWriter = new BlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
         for (Number nv : values) {
           long value = nv == null ? 0 : nv.longValue();
           quotientWriter.add((value - minValue) / gcd);
@@ -172,7 +172,7 @@
         quotientWriter.finish();
         break;
       case DELTA_COMPRESSED:
-        final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+        final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
         for (Number nv : values) {
           writer.add(nv == null ? 0 : nv.longValue());
         }
@@ -263,7 +263,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       meta.writeVInt(BLOCK_SIZE);
 
-      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE);
+      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
       long addr = 0;
       for (BytesRef v : values) {
         if (v != null) {
@@ -298,7 +298,7 @@
       // currently, we have to store the delta from expected for every 1/nth term
       // we could avoid this, but its not much and less overall RAM than the previous approach!
       RAMOutputStream addressBuffer = new RAMOutputStream();
-      MonotonicBlockPackedWriter termAddresses = new MonotonicBlockPackedWriter(addressBuffer, BLOCK_SIZE);
+      MonotonicBlockPackedWriter termAddresses = new MonotonicBlockPackedWriter(addressBuffer, BLOCK_SIZE, PackedInts.COMPACT);
       BytesRef lastTerm = new BytesRef();
       long count = 0;
       for (BytesRef v : values) {
@@ -361,7 +361,7 @@
     meta.writeVLong(maxDoc);
     meta.writeVInt(BLOCK_SIZE);
 
-    final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE);
+    final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
     long addr = 0;
     for (Number v : docToOrdCount) {
       addr += v.longValue();
Index: lucene/core/src/java/org/apache/lucene/codecs/compressing/CompressingTermVectorsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/compressing/CompressingTermVectorsWriter.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/codecs/compressing/CompressingTermVectorsWriter.java	(copie de travail)
@@ -236,7 +236,7 @@
 
       vectorsStream.writeVInt(PackedInts.VERSION_CURRENT);
       vectorsStream.writeVInt(chunkSize);
-      writer = new BlockPackedWriter(vectorsStream, BLOCK_SIZE);
+      writer = new BlockPackedWriter(vectorsStream, BLOCK_SIZE, PackedInts.COMPACT);
 
       positionsBuf = new int[1024];
       startOffsetsBuf = new int[1024];
Index: lucene/core/src/java/org/apache/lucene/util/packed/MonotonicBlockPackedWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/packed/MonotonicBlockPackedWriter.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/util/packed/MonotonicBlockPackedWriter.java	(copie de travail)
@@ -57,8 +57,8 @@
    * Sole constructor.
    * @param blockSize the number of values of a single block, must be a power of 2
    */
-  public MonotonicBlockPackedWriter(DataOutput out, int blockSize) {
-    super(out, blockSize);
+  public MonotonicBlockPackedWriter(DataOutput out, int blockSize, float acceptableOverheadRatio) {
+    super(out, blockSize, acceptableOverheadRatio);
   }
 
   @Override
@@ -67,6 +67,7 @@
     super.add(l);
   }
 
+  @Override
   protected void flush() throws IOException {
     assert off > 0;
 
@@ -85,7 +86,7 @@
     if (maxZigZagDelta == 0) {
       out.writeVInt(0);
     } else {
-      final int bitsRequired = PackedInts.bitsRequired(maxZigZagDelta);
+      final int bitsRequired = bitsRequired(maxZigZagDelta);
       out.writeVInt(bitsRequired);
       writeValues(bitsRequired);
     }
Index: lucene/core/src/java/org/apache/lucene/util/packed/AbstractBlockPackedWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/packed/AbstractBlockPackedWriter.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/util/packed/AbstractBlockPackedWriter.java	(copie de travail)
@@ -46,6 +46,7 @@
   }
 
   protected DataOutput out;
+  protected final float acceptableOverheadRatio;
   protected final long[] values;
   protected byte[] blocks;
   protected int off;
@@ -56,8 +57,9 @@
    * Sole constructor.
    * @param blockSize the number of values of a single block, must be a multiple of <tt>64</tt>
    */
-  public AbstractBlockPackedWriter(DataOutput out, int blockSize) {
+  public AbstractBlockPackedWriter(DataOutput out, int blockSize, float acceptableOverheadRatio) {
     checkBlockSize(blockSize, MIN_BLOCK_SIZE, MAX_BLOCK_SIZE);
+    this.acceptableOverheadRatio = acceptableOverheadRatio;
     reset(out);
     values = new long[blockSize];
   }
@@ -119,6 +121,15 @@
 
   protected abstract void flush() throws IOException;
 
+  protected final int bitsRequired(long delta) {
+    final int bitsRequired = delta < 0 ? 64 : delta == 0L ? 0 : PackedInts.bitsRequired(delta);
+    final PackedInts.FormatAndBits fastestFormatAndBits = PackedInts.fastestFormatAndBits(off, bitsRequired, acceptableOverheadRatio);
+    // The initial version of this class only supported Format.PACKED, maybe we should make it support PACKED_SINGLE_BLOCK in the future
+    // but this can be tricky backward-compatibility-wise since this class is used in many codecs
+    final int bitsPerValue = fastestFormatAndBits.format == PackedInts.Format.PACKED ? fastestFormatAndBits.bitsPerValue : bitsRequired;
+    return bitsPerValue;
+  }
+
   protected final void writeValues(int bitsRequired) throws IOException {
     final PackedInts.Encoder encoder = PackedInts.getEncoder(PackedInts.Format.PACKED, PackedInts.VERSION_CURRENT, bitsRequired);
     final int iterations = values.length / encoder.byteValueCount();
Index: lucene/core/src/java/org/apache/lucene/util/packed/BlockPackedWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/packed/BlockPackedWriter.java	(révision 1531385)
+++ lucene/core/src/java/org/apache/lucene/util/packed/BlockPackedWriter.java	(copie de travail)
@@ -61,8 +61,8 @@
    * Sole constructor.
    * @param blockSize the number of values of a single block, must be a power of 2
    */
-  public BlockPackedWriter(DataOutput out, int blockSize) {
-    super(out, blockSize);
+  public BlockPackedWriter(DataOutput out, int blockSize, float acceptableOverheadRatio) {
+    super(out, blockSize, acceptableOverheadRatio);
   }
 
   protected void flush() throws IOException {
@@ -74,7 +74,7 @@
     }
 
     final long delta = max - min;
-    final int bitsRequired = delta < 0 ? 64 : delta == 0L ? 0 : PackedInts.bitsRequired(delta);
+    final int bitsRequired = bitsRequired(delta);
     if (bitsRequired == 64) {
       // no need to delta-encode
       min = 0L;
Index: lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/FixedGapTermsIndexWriter.java
===================================================================
--- lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/FixedGapTermsIndexWriter.java	(révision 1531385)
+++ lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/FixedGapTermsIndexWriter.java	(copie de travail)
@@ -125,11 +125,11 @@
     private long numTerms;
 
     private RAMOutputStream offsetsBuffer = new RAMOutputStream();
-    private MonotonicBlockPackedWriter termOffsets = new MonotonicBlockPackedWriter(offsetsBuffer, BLOCKSIZE);
+    private MonotonicBlockPackedWriter termOffsets = new MonotonicBlockPackedWriter(offsetsBuffer, BLOCKSIZE, PackedInts.COMPACT);
     private long currentOffset;
 
     private RAMOutputStream addressBuffer = new RAMOutputStream();
-    private MonotonicBlockPackedWriter termAddresses = new MonotonicBlockPackedWriter(addressBuffer, BLOCKSIZE);
+    private MonotonicBlockPackedWriter termAddresses = new MonotonicBlockPackedWriter(addressBuffer, BLOCKSIZE, PackedInts.COMPACT);
 
     private final BytesRef lastTerm = new BytesRef();
 
Index: lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesConsumer.java
===================================================================
--- lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesConsumer.java	(révision 1531385)
+++ lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesConsumer.java	(copie de travail)
@@ -182,7 +182,7 @@
       data.writeLong(gcd);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
       for (Number nv : values) {
         long value = nv == null ? 0 : nv.longValue();
         writer.add((value - minValue) / gcd);
@@ -194,7 +194,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       data.writeVInt(BLOCK_SIZE);
 
-      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE);
+      final BlockPackedWriter writer = new BlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
       for (Number nv : values) {
         writer.add(nv == null ? 0 : nv.longValue());
       }
@@ -264,7 +264,7 @@
       meta.writeVInt(PackedInts.VERSION_CURRENT);
       meta.writeVInt(BLOCK_SIZE);
 
-      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE);
+      final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE, PackedInts.COMPACT);
       long addr = 0;
       for (BytesRef v : values) {
         if (v != null) {
