Index: core/src/java/org/apache/lucene/util/packed/EliasFanoDecoder.java
===================================================================
--- core/src/java/org/apache/lucene/util/packed/EliasFanoDecoder.java	(revision 1525411)
+++ core/src/java/org/apache/lucene/util/packed/EliasFanoDecoder.java	(working copy)
@@ -24,27 +24,37 @@
   private static final int LOG2_LONG_SIZE = Long.numberOfTrailingZeros(Long.SIZE);
 
   private final EliasFanoEncoder efEncoder;
-  final long numEncoded;
+  private final long numEncoded;
   private long efIndex = -1; // the decoding index.
   private long setBitForIndex = -1; // the index of the high bit at the decoding index.
 
   public final static long NO_MORE_VALUES = -1L;
 
+  private final long numIndexEntries;
+  private final long indexMask;
+
   /** Construct a decoder for a given {@link EliasFanoEncoder}.
    * The decoding index is set to just before the first encoded value.
    */
   public EliasFanoDecoder(EliasFanoEncoder efEncoder) {
     this.efEncoder = efEncoder;
-    this.numEncoded = efEncoder.numEncoded; // numEncoded is not final in EliasFanoEncoder
+    this.numEncoded = efEncoder.numEncoded; // not final in EliasFanoEncoder
+    this.numIndexEntries = efEncoder.currentEntryIndex;  // not final in EliasFanoEncoder
+    this.indexMask = (1L << efEncoder.nIndexEntryBits) - 1;
   }
 
-  /** Return the Elias-Fano encoder that is decoded. */
+  /** @return The Elias-Fano encoder that is decoded. */
   public EliasFanoEncoder getEliasFanoEncoder() {
     return efEncoder;
   }
+  
+  /** @return The number of values encoded by the encoder. */
+  public long numEncoded() { 
+    return numEncoded;
+  }
 
 
-  /** Return the index of the last decoded value.
+  /** @return The index of the last decoded value.
    * The first value encoded by {@link EliasFanoEncoder#encodeNext} has index 0.
    * Only valid directly after
    * {@link #nextValue}, {@link #advanceToValue},
@@ -61,30 +71,34 @@
     return efIndex;
   }
 
-  /** Return the high value for the current decoding index. */
+  /**  @return The high value for the current decoding index. */
   private long currentHighValue() {
     return setBitForIndex - efIndex; // sequence of unary gaps
   }
 
-  /**  Return the low value for the current decoding index. */
-  private long currentLowValue() {
-    assert efIndex >= 0;
-    assert efIndex < numEncoded;
-    if (efEncoder.numLowBits == 0) {
+  private static long unPackValue(long[] longArray, int numBits, long packIndex, long bitsMask) {
+    if (numBits == 0) {
       return 0;
     }
-    long bitPos = efIndex * efEncoder.numLowBits;
-    int lowIndex = (int) (bitPos >>> LOG2_LONG_SIZE);
+    long bitPos = packIndex * numBits;
+    int index = (int) (bitPos >>> LOG2_LONG_SIZE);
     int bitPosAtIndex = (int) (bitPos & (Long.SIZE-1));
-    long lowValue = efEncoder.lowerLongs[lowIndex] >>> bitPosAtIndex;
-    if ((bitPosAtIndex + efEncoder.numLowBits) > Long.SIZE) {
-      lowValue |= (efEncoder.lowerLongs[lowIndex + 1] << (Long.SIZE - bitPosAtIndex));
+    long value = longArray[index] >>> bitPosAtIndex;
+    if ((bitPosAtIndex + numBits) > Long.SIZE) {
+      value |= (longArray[index + 1] << (Long.SIZE - bitPosAtIndex));
     }
-    lowValue &= efEncoder.lowerBitsMask;
-    return lowValue;
+    value &= bitsMask;
+    return value;
   }
 
-  /**  Return the given highValue shifted left by the number of low bits from by the EliasFanoSequence,
+  /**  @return The low value for the current decoding index. */
+  private long currentLowValue() {
+    assert efIndex >= 0;
+    assert efIndex < numEncoded;
+    return unPackValue(efEncoder.lowerLongs, efEncoder.numLowBits, efIndex, efEncoder.lowerBitsMask);
+  }
+
+  /**  @return The given highValue shifted left by the number of low bits from by the EliasFanoSequence,
    *           logically OR-ed with the given lowValue.
    */
   private long combineHighLowValues(long highValue, long lowValue) {
@@ -116,7 +130,7 @@
     setBitForIndex = -1;
   }
 
-  /** Return the number of bits in a long after (setBitForIndex modulo Long.SIZE) */
+  /** @return the number of bits in a long after (setBitForIndex modulo Long.SIZE) */
   private int getCurrentRightShift() {
     int s = (int) (setBitForIndex & (Long.SIZE-1));
     return s;
@@ -211,11 +225,30 @@
 
   /** setBitForIndex and efIndex have just been incremented, scan forward to the high set bit
    *  of at least a given high value
-   *  by incrementing setBitForIndex, and by setting curHighLong accordingly.
+   *  by further incrementing setBitForIndex and efIndex, and by setting curHighLong accordingly.
+   *  On entry, efIndex < numEncoded.
    *  @return the smallest encoded high value that is at least the given one.
    */
   private long advanceToHighValue(long highTarget) {
-    int curSetBits = Long.bitCount(curHighLong); // is shifted by getCurrentRightShift()
+    // determine index entry to advance to
+    long indexEntryIndex = (highTarget / efEncoder.indexInterval) - 1;
+    if (indexEntryIndex >= 0) { // not before first index entry
+      if (indexEntryIndex >= numIndexEntries) {
+      	indexEntryIndex = numIndexEntries - 1; // no further than last index entry
+      }
+      long indexHighValue = (indexEntryIndex + 1) * efEncoder.indexInterval;
+      assert indexHighValue <= highTarget;
+      if (indexHighValue > currentHighValue()) { // advance to index entry
+	setBitForIndex = unPackValue(efEncoder.upperZeroBitPositionIndex, efEncoder.nIndexEntryBits, indexEntryIndex, indexMask);
+	efIndex = setBitForIndex - indexHighValue;
+	assert currentHighValue() == indexHighValue : "" + currentHighValue() + " != " + indexHighValue;
+	int highIndex = (int)(setBitForIndex >>> LOG2_LONG_SIZE);
+	curHighLong = efEncoder.upperLongs[highIndex] >>> getCurrentRightShift();
+      }
+    }
+
+    assert efIndex < numEncoded; // there is a high value to be found.
+    int curSetBits = Long.bitCount(curHighLong); // shifted by getCurrentRightShift()
     int curClearBits = Long.SIZE - curSetBits - getCurrentRightShift();
     while ((currentHighValue() + curClearBits) < highTarget) {
       // curHighLong has not enough clear bits to reach highTarget
@@ -275,7 +308,7 @@
     setBitForIndex = (efEncoder.lastEncoded >>> efEncoder.numLowBits) + numEncoded;
   }
 
-  /** Return the number of bits in a long before (setBitForIndex modulo Long.SIZE) */
+  /** @return the number of bits in a long before (setBitForIndex modulo Long.SIZE) */
   private int getCurrentLeftShift() {
     int s = Long.SIZE - 1 - (int) (setBitForIndex & (Long.SIZE-1));
     return s;
@@ -336,6 +369,7 @@
    *  @return the largest encoded high value that is at most the given one.
    */
   private long backToHighValue(long highTarget) {
+    /* CHECKME: Add using the index as in advanceToHighValue */
     int curSetBits = Long.bitCount(curHighLong); // is shifted by getCurrentLeftShift()
     int curClearBits = Long.SIZE - curSetBits - getCurrentLeftShift();
     while ((currentHighValue() - curClearBits) > highTarget) {
@@ -352,7 +386,7 @@
     // curHighLong has enough clear bits to reach highTarget, but may not have enough set bits.
     long highValue = previousHighValue();
     while (highValue > highTarget) {
-      /* CHECKME: See at advanceToHighValue. */
+      /* CHECKME: See at advanceToHighValue on using broadword bit selection. */
       if (! toBeforeCurrentHighBit()) {
         return NO_MORE_VALUES;
       }
Index: core/src/java/org/apache/lucene/util/packed/EliasFanoDocIdSet.java
===================================================================
--- core/src/java/org/apache/lucene/util/packed/EliasFanoDocIdSet.java	(revision 1525411)
+++ core/src/java/org/apache/lucene/util/packed/EliasFanoDocIdSet.java	(working copy)
@@ -86,7 +86,7 @@
 
       @Override
       public long cost() {
-        return efDecoder.numEncoded;
+        return efDecoder.numEncoded();
       }
     };
   }
Index: core/src/java/org/apache/lucene/util/packed/EliasFanoEncoder.java
===================================================================
--- core/src/java/org/apache/lucene/util/packed/EliasFanoEncoder.java	(revision 1525411)
+++ core/src/java/org/apache/lucene/util/packed/EliasFanoEncoder.java	(working copy)
@@ -19,6 +19,7 @@
 
 import java.util.Arrays;
 
+import org.apache.lucene.util.ToStringUtils;
 import org.apache.lucene.util.FixedBitSet; // for javadocs
 
 
@@ -64,10 +65,12 @@
  * In this implementation the values in the sequence can be given as <code>long</code>,
  * <code>numValues = 0</code> and <code>upperBound = 0</code> are allowed,
  * and each of the upper and lower bit arrays should fit in a <code>long[]</code>.
+ * <br>
+ * An index of positions of zero's in the upper bits is also built.
  * <p>
  * This implementation is based on this article:
  * <br>
- * Sebastiano Vigna, "Quasi Succinct Indices", June 19, 2012, sections 3 and 4.
+ * Sebastiano Vigna, "Quasi Succinct Indices", June 19, 2012, sections 3, 4 and 9.
  * Retrieved from http://arxiv.org/pdf/1206.4300 .
  *
  * <p>The articles originally describing the Elias-Fano representation are:
@@ -91,6 +94,19 @@
   long numEncoded = 0L;
   long lastEncoded = 0L;
 
+  /** The default index interval for zero upper bits. */
+  public static final long DEFAULT_INDEX_INTERVAL = 256;
+  final long numIndexEntries;
+  final long indexInterval;
+  final int nIndexEntryBits;
+  /** upperZeroBitPositionIndex[i] (filled using packValue) will contain the bit position
+   *  of zero bit ((i+1) * indexInterval) in the upper bits.
+   */
+  final long[] upperZeroBitPositionIndex;
+  long currentEntryIndex; // also indicates how many entries in the index are valid.
+
+
+
   /**
    * Construct an Elias-Fano encoder.
    * After construction, call {@link #encodeNext} <code>numValues</code> times to encode
@@ -101,6 +117,10 @@
    *                or is the first higher than the actual maximum.
    *                <br>When <code>numValues >= (upperBound/3)</code>
    *                a {@link FixedBitSet} will take less space.
+   * @param indexInterval The number of high zero bits for which a single index entry is built.
+   *                The index will have at most <code>2 * numValues / indexInterval</code> entries
+   *                and each index entry will use at most <code>ceil(log2(3 * numValues))</code> bits,
+   *                see {@link EliasFanoEncoder}.
    * @throws IllegalArgumentException when:
    *         <ul>
    *         <li><code>numValues</code> is negative, or
@@ -108,10 +128,13 @@
    *         <li>the low bits do not fit in a <code>long[]</code>:
    *             <code>(L * numValues / 64) > Integer.MAX_VALUE</code>, or
    *         <li>the high bits do not fit in a <code>long[]</code>:
-   *             <code>(2 * numValues / 64) > Integer.MAX_VALUE</code>.
+   *             <code>(2 * numValues / 64) > Integer.MAX_VALUE</code>, or
+   *         <li><code>indexInterval < 2</code>,
+   *         <li>the index bits do not fit in a <code>long[]</code>:
+   *             <code>(numValues / indexInterval * ceil(2log(3 * numValues)) / 64) > Integer.MAX_VALUE</code>.
    *         </ul>
    */
-  public EliasFanoEncoder(long numValues, long upperBound) {
+  public EliasFanoEncoder(long numValues, long upperBound, long indexInterval) {
     if (numValues < 0L) {
       throw new IllegalArgumentException("numValues should not be negative: " + numValues);
     }
@@ -145,9 +168,33 @@
       throw new IllegalArgumentException("numLongsForHighBits too large to index a long array: " + numLongsForHighBits);
     }
     this.upperLongs = new long[(int) numLongsForHighBits];
+    if (indexInterval < 2) {
+      throw new IllegalArgumentException("indexInterval should at least 2: " + indexInterval);
+    }
+    // For the index:
+    long maxHighValue = upperBound >>> this.numLowBits;
+    long nIndexEntries = maxHighValue / indexInterval; // no zero value index entry
+    this.numIndexEntries = (nIndexEntries >= 0) ? nIndexEntries : 0;
+    long maxIndexEntry = maxHighValue + numValues - 1; // clear upper bits, set upper bits, start at zero
+    this.nIndexEntryBits = (maxIndexEntry <= 0) ? 0
+			  : (64 - Long.numberOfLeadingZeros(maxIndexEntry - 1));
+    long numLongsForIndexBits = numLongsForBits(numIndexEntries * nIndexEntryBits);
+    if (numLongsForIndexBits > Integer.MAX_VALUE) {
+      throw new IllegalArgumentException("numLongsForIndexBits too large to index a long array: " + numLongsForIndexBits);
+    }
+    this.upperZeroBitPositionIndex = new long[(int) numLongsForIndexBits];
+    this.currentEntryIndex = 0;
+    this.indexInterval = indexInterval;
   }
 
-  private static long numLongsForBits(long numBits) {
+  /**
+  * Construct an Elias-Fano encoder using {@link #DEFAULT_INDEX_INTERVAL}.
+  */
+  public EliasFanoEncoder(long numValues, long upperBound) {
+    this(numValues, upperBound, DEFAULT_INDEX_INTERVAL);
+  }
+
+  protected static long numLongsForBits(long numBits) {
     assert numBits >= 0 : numBits;
     return (numBits + (Long.SIZE-1)) >>> LOG2_LONG_SIZE;
   }
@@ -171,10 +218,19 @@
     if (x > upperBound) {
       throw new IllegalArgumentException(x + " larger than upperBound " + upperBound);
     }
-    encodeUpperBits(x >>> numLowBits);
+    long highValue = x >>> numLowBits;
+    encodeUpperBits(highValue);
     encodeLowerBits(x & lowerBitsMask);
+    lastEncoded = x;
+    // Add index entries:
+    long indexValue = (currentEntryIndex + 1) * indexInterval;
+    while (indexValue <= highValue) { 
+      long afterZeroBitPosition = indexValue + numEncoded;
+      packValue(afterZeroBitPosition, upperZeroBitPositionIndex, nIndexEntryBits, currentEntryIndex);
+      currentEntryIndex += 1;
+      indexValue += indexInterval;
+    }
     numEncoded++;
-    lastEncoded = x;
   }
 
   private void encodeUpperBits(long highValue) {
@@ -186,7 +242,7 @@
     packValue(lowValue, lowerLongs, numLowBits, numEncoded);
   }
 
-  private static void packValue(long value, long[] longArray, int numBits, long packIndex) {
+  protected static void packValue(long value, long[] longArray, int numBits, long packIndex) {
     if (numBits != 0) {
       long bitPos = numBits * packIndex;
       int index = (int) (bitPos >>> LOG2_LONG_SIZE);
@@ -216,7 +272,7 @@
      * For intersecting two EliasFano sequences without index on the upper bits,
      * all (2 * 3 * numValues) upper bits are accessed.
      */
-    return (upperBound / 6) > numValues;
+    return (upperBound / 7) > numValues; // 6 + 1 to have some room for the index
   }
 
   /**
@@ -237,6 +293,11 @@
   public long[] getUpperBits() {
     return upperLongs;
   }
+  
+  /** Expert. The index bits. */
+  public long[] getIndexBits() {
+    return upperZeroBitPositionIndex;
+  }
 
   @Override
   public String toString() {
@@ -248,12 +309,17 @@
     s.append(" numLowBits " + numLowBits);
     s.append("\nupperLongs[" + upperLongs.length + "]");
     for (int i = 0; i < upperLongs.length; i++) {
-      s.append(" " + longHex(upperLongs[i]));
+      s.append(" " + ToStringUtils.longHex(upperLongs[i]));
     }
     s.append("\nlowerLongs[" + lowerLongs.length + "]");
     for (int i = 0; i < lowerLongs.length; i++) {
-      s.append(" " + longHex(lowerLongs[i]));
+      s.append(" " + ToStringUtils.longHex(lowerLongs[i]));
     }
+    s.append("indexInterval: " + indexInterval + ", nIndexEntryBits: " + nIndexEntryBits);
+    s.append("\nupperZeroBitPositionIndex[" + upperZeroBitPositionIndex.length + "]");
+    for (int i = 0; i < upperZeroBitPositionIndex.length; i++) { 
+      s.append(" " + ToStringUtils.longHex(upperZeroBitPositionIndex[i]));
+    }
     return s.toString();
   }
 
@@ -265,31 +331,21 @@
     EliasFanoEncoder oefs = (EliasFanoEncoder) other;
     // no equality needed for upperBound
     return (this.numValues == oefs.numValues)
-        && (this.numEncoded == oefs.numEncoded)
-        && (this.numLowBits == oefs.numLowBits)
-        && Arrays.equals(this.upperLongs, oefs.upperLongs)
-        && Arrays.equals(this.lowerLongs, oefs.lowerLongs);
+	&& (this.numEncoded == oefs.numEncoded)
+	&& (this.numLowBits == oefs.numLowBits)
+	&& (this.numIndexEntries == oefs.numIndexEntries)
+	&& (this.indexInterval == oefs.indexInterval) // no need to check index content
+	&& Arrays.equals(this.upperLongs, oefs.upperLongs)
+	&& Arrays.equals(this.lowerLongs, oefs.lowerLongs);
   }
 
   @Override
   public int hashCode() {
-    int h = ((int) (numValues + numEncoded))
-        ^ numLowBits
+    int h = ((int) (31*(numValues + 7*(numEncoded + 5*(numLowBits + 3*(numIndexEntries + 11*indexInterval))))))
         ^ Arrays.hashCode(upperLongs)
         ^ Arrays.hashCode(lowerLongs);
     return h;
   }
 
-  public static String longHex(long x) {
-    String hx = Long.toHexString(x);
-    StringBuilder sb = new StringBuilder("0x");
-    int l = 16 - hx.length();
-    while (l > 0) {
-      sb.append('0');
-      l--;
-    }
-    sb.append(hx);
-    return sb.toString();
-  }
 }
 
Index: core/src/test/org/apache/lucene/util/packed/TestEliasFanoSequence.java
===================================================================
--- core/src/test/org/apache/lucene/util/packed/TestEliasFanoSequence.java	(revision 1525411)
+++ core/src/test/org/apache/lucene/util/packed/TestEliasFanoSequence.java	(working copy)
@@ -21,13 +21,13 @@
 
 public class TestEliasFanoSequence extends LuceneTestCase {
 
-  private static EliasFanoEncoder makeEncoder(long[] values) {
+  private static EliasFanoEncoder makeEncoder(long[] values, long indexInterval) {
     long upperBound = -1L;
     for (long value: values) {
       assertTrue(value >= upperBound); // test data ok
       upperBound = value;
     }
-    EliasFanoEncoder efEncoder = new EliasFanoEncoder(values.length, upperBound);
+    EliasFanoEncoder efEncoder = new EliasFanoEncoder(values.length, upperBound, indexInterval);
     for (long value: values) {
       efEncoder.encodeNext(value);
     }
@@ -146,25 +146,32 @@
   }
 
   private static void tstEFS(long[] values, long[] expHighLongs, long[] expLowLongs) {
-    EliasFanoEncoder efEncoder = makeEncoder(values);
+    EliasFanoEncoder efEncoder = makeEncoder(values, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
     tstEqual("upperBits", expHighLongs, efEncoder.getUpperBits());
     tstEqual("lowerBits", expLowLongs, efEncoder.getLowerBits());
     tstDecodeAll(efEncoder, values);
   }
 
   private static void tstEFS2(long[] values) {
-    EliasFanoEncoder efEncoder = makeEncoder(values);
+    EliasFanoEncoder efEncoder = makeEncoder(values, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
     tstDecodeAll(efEncoder, values);
   }
 
   private static void tstEFSadvanceToAndBackToMultiples(long[] values, long maxValue, long minAdvanceMultiple) {
-    EliasFanoEncoder efEncoder = makeEncoder(values);
+    EliasFanoEncoder efEncoder = makeEncoder(values, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
     for (long m = minAdvanceMultiple; m <= maxValue; m += 1) {
       tstDecodeAdvanceToMultiples(values, efEncoder.getDecoder(), m);
       tstDecodeBackToMultiples(values, efEncoder.getDecoder(), m);
     }
   }
 
+  private EliasFanoEncoder tstEFVI(long[] values, long indexInterval, long[] expIndexBits) {
+    EliasFanoEncoder efEncVI = makeEncoder(values, indexInterval);
+    tstEqual("upperZeroBitPositionIndex", expIndexBits, efEncVI.getIndexBits());
+    return efEncVI;
+  }
+
+
   public void testEmpty() {
     long[] values = new long[0];
     long[] expHighBits = new long[0];
@@ -223,12 +230,12 @@
 
   public void testHashCodeEquals() {
     long[] values = new long[] {5,8,8,15,32};
-    EliasFanoEncoder efEncoder1 = makeEncoder(values);
-    EliasFanoEncoder efEncoder2 = makeEncoder(values);
+    EliasFanoEncoder efEncoder1 = makeEncoder(values, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
+    EliasFanoEncoder efEncoder2 = makeEncoder(values, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
     assertEquals(efEncoder1, efEncoder2);
     assertEquals(efEncoder1.hashCode(), efEncoder2.hashCode());
 
-    EliasFanoEncoder efEncoder3 = makeEncoder(new long[] {1,2,3});
+    EliasFanoEncoder efEncoder3 = makeEncoder(new long[] {1,2,3}, EliasFanoEncoder.DEFAULT_INDEX_INTERVAL);
     assertFalse(efEncoder1.equals(efEncoder3));
     assertFalse(efEncoder3.equals(efEncoder1));
     assertFalse(efEncoder1.hashCode() == efEncoder3.hashCode()); // implementation ok for these.
@@ -277,5 +284,63 @@
       tstEFSadvanceToAndBackToMultiples(values, values[s-1], 10);
     }
   }
+
+  public void testEmptyIndex() {
+    long[] emptyLongs = new long[0];
+    tstEFVI(emptyLongs, 2, emptyLongs);
+  }
+  public void testMaxContentEmptyIndex() {
+    long[] twoLongs = new long[] {0,1};
+    long[] emptyLongs = new long[0];
+    tstEFVI(twoLongs, 2, emptyLongs);
+  }
+
+  public void testMinContentNonEmptyIndex() {
+    long[] twoLongs = new long[] {0,2};
+    long[] indexLongs = new long[] {3}; // high bits 1001, index position after zero bit.
+    tstEFVI(twoLongs, 2, indexLongs);
+  }
+
+  public void testIndexAdvanceToLast() {
+    long[] twoLongs = new long[] {0,2};
+    long[] indexLongs = new long[] {3}; // high bits 1001
+    EliasFanoEncoder efEncVI = tstEFVI(twoLongs, 2, indexLongs);
+    assertEquals(2, efEncVI.getDecoder().advanceToValue(2));
+  }
+
+  public void testIndexAdvanceToAfterLast() {
+    long[] twoLongs = new long[] {0,2};
+    long[] indexLongs = new long[] {3}; // high bits 1001
+    EliasFanoEncoder efEncVI = tstEFVI(twoLongs, 2, indexLongs);
+    assertEquals(EliasFanoDecoder.NO_MORE_VALUES, efEncVI.getDecoder().advanceToValue(3));
+  }
+
+  public void testIndexAdvanceToFirst() {
+    long[] twoLongs = new long[] {0,2};
+    long[] indexLongs = new long[] {3}; // high bits 1001
+    EliasFanoEncoder efEncVI = tstEFVI(twoLongs, 2, indexLongs);
+    assertEquals(0, efEncVI.getDecoder().advanceToValue(0));
+  }
+  
+  public void testTwoIndexEntries() {
+    long[] twoLongs = new long[] {0,1,2,3,4,5};
+    long[] indexLongs = new long[] {4 + 8*16}; // high bits 0b10101010101
+    EliasFanoEncoder efEncVI = tstEFVI(twoLongs, 2, indexLongs);
+    EliasFanoDecoder efDecVI = efEncVI.getDecoder();
+    assertEquals("advance 0", 0, efDecVI.advanceToValue(0));
+    assertEquals("advance 5", 5, efDecVI.advanceToValue(5));
+    assertEquals("advance 6", EliasFanoDecoder.NO_MORE_VALUES, efDecVI.advanceToValue(5));
+  }
+
+  public void testExample2() { // Figure 2 from Vigna 2012 paper
+    long indexDivisor = 4;
+    long[] values = new long[] {5,8,8,15,32}; // two low bits, high values 1,2,2,3,8.
+    long[] indexLongs = new long[] {8 + 12*16}; // high bits 0b1000001011010
+    EliasFanoEncoder efEncVI = tstEFVI(values, indexDivisor, indexLongs);
+    EliasFanoDecoder efDecVI = efEncVI.getDecoder();
+    assertEquals("initial next", 5, efDecVI.nextValue());
+    assertEquals("advance 22", 32, efDecVI.advanceToValue(22));
+  }
+
 }
 
