@Override
 public void deserialize(DataInput in) throws IOException {
   // little endian
   this.cardinality = 0;
   for (int k = 0; k < bitmap.length; ++k) {
     bitmap[k] = Long.reverseBytes(in.readLong());
     this.cardinality += Long.bitCount(bitmap[k]);
   }
 }
 @Override
 public int rank(short lowbits) {
   int x = Util.toIntUnsigned(lowbits);
   int leftover = (x + 1) & 63;
   int answer = 0;
   for (int k = 0; k < (x + 1) / 64; ++k) answer += Long.bitCount(bitmap[k]);
   if (leftover != 0) {
     answer += Long.bitCount(bitmap[(x + 1) / 64] << (64 - leftover));
   }
   return answer;
 }
 @Override
 public Container limit(int maxcardinality) {
   if (maxcardinality >= this.cardinality) {
     return clone();
   }
   if (maxcardinality <= ArrayContainer.DEFAULT_MAX_SIZE) {
     ArrayContainer ac = new ArrayContainer(maxcardinality);
     int pos = 0;
     for (int k = 0; (ac.cardinality < maxcardinality) && (k < bitmap.length); ++k) {
       long bitset = bitmap[k];
       while ((ac.cardinality < maxcardinality) && (bitset != 0)) {
         long t = bitset & -bitset;
         ac.content[pos++] = (short) (k * 64 + Long.bitCount(t - 1));
         ac.cardinality++;
         bitset ^= t;
       }
     }
     return ac;
   }
   BitmapContainer bc = new BitmapContainer(maxcardinality, this.bitmap);
   int s = Util.toIntUnsigned(select(maxcardinality));
   int usedwords = (s + 63) / 64;
   int todelete = this.bitmap.length - usedwords;
   for (int k = 0; k < todelete; ++k) bc.bitmap[bc.bitmap.length - 1 - k] = 0;
   int lastword = s % 64;
   if (lastword != 0) {
     bc.bitmap[s / 64] = (bc.bitmap[s / 64] << (64 - lastword)) >> (64 - lastword);
   }
   return bc;
 }
 @Override
 public MappeableContainer or(final MappeableArrayContainer value2) {
   final MappeableArrayContainer value1 = this;
   final int totalCardinality = value1.getCardinality() + value2.getCardinality();
   if (totalCardinality > DEFAULT_MAX_SIZE) { // it could be a bitmap!
     final MappeableBitmapContainer bc = new MappeableBitmapContainer();
     if (!BufferUtil.isBackedBySimpleArray(bc.bitmap))
       throw new RuntimeException("Should not happen. Internal bug.");
     long[] bitArray = bc.bitmap.array();
     if (BufferUtil.isBackedBySimpleArray(value2.content)) {
       short[] sarray = value2.content.array();
       for (int k = 0; k < value2.cardinality; ++k) {
         final int i = BufferUtil.toIntUnsigned(sarray[k]) >>> 6;
         bitArray[i] |= (1l << sarray[k]);
       }
     } else
       for (int k = 0; k < value2.cardinality; ++k) {
         short v2 = value2.content.get(k);
         final int i = BufferUtil.toIntUnsigned(v2) >>> 6;
         bitArray[i] |= (1l << v2);
       }
     if (BufferUtil.isBackedBySimpleArray(this.content)) {
       short[] sarray = this.content.array();
       for (int k = 0; k < this.cardinality; ++k) {
         final int i = BufferUtil.toIntUnsigned(sarray[k]) >>> 6;
         bitArray[i] |= (1l << sarray[k]);
       }
     } else
       for (int k = 0; k < this.cardinality; ++k) {
         final int i = BufferUtil.toIntUnsigned(this.content.get(k)) >>> 6;
         bitArray[i] |= (1l << this.content.get(k));
       }
     bc.cardinality = 0;
     int len = bc.bitmap.limit();
     for (int index = 0; index < len; ++index) {
       bc.cardinality += Long.bitCount(bitArray[index]);
     }
     if (bc.cardinality <= DEFAULT_MAX_SIZE) return bc.toArrayContainer();
     return bc;
   }
   final MappeableArrayContainer answer = new MappeableArrayContainer(totalCardinality);
   if (BufferUtil.isBackedBySimpleArray(value1.content)
       && BufferUtil.isBackedBySimpleArray(value2.content))
     answer.cardinality =
         org.roaringbitmap.Util.unsignedUnion2by2(
             value1.content.array(),
             value1.getCardinality(),
             value2.content.array(),
             value2.getCardinality(),
             answer.content.array());
   else
     answer.cardinality =
         BufferUtil.unsignedUnion2by2(
             value1.content,
             value1.getCardinality(),
             value2.content,
             value2.getCardinality(),
             answer.content.array());
   return answer;
 }
  @Override
  int numberOfRuns() {
    int numRuns = 0;
    long nextWord = bitmap[0];

    for (int i = 0; i < bitmap.length - 1; i++) {
      long word = nextWord;
      nextWord = bitmap[i + 1];
      numRuns += Long.bitCount((~word) & (word << 1)) + ((word >>> 63) & ~nextWord);
    }

    long word = nextWord;
    numRuns += Long.bitCount((~word) & (word << 1));
    if ((word & 0x8000000000000000L) != 0) numRuns++;

    return numRuns;
  }
 @Override
 public Container ior(final BitmapContainer b2) {
   this.cardinality = 0;
   for (int k = 0; k < this.bitmap.length; k++) {
     this.bitmap[k] |= b2.bitmap[k];
     this.cardinality += Long.bitCount(this.bitmap[k]);
   }
   return this;
 }
 /**
  * Fill the array with set bits
  *
  * @param array container (should be sufficiently large)
  */
 protected void fillArray(final short[] array) {
   int pos = 0;
   for (int k = 0; k < bitmap.length; ++k) {
     long bitset = bitmap[k];
     while (bitset != 0) {
       long t = bitset & -bitset;
       array[pos++] = (short) (k * 64 + Long.bitCount(t - 1));
       bitset ^= t;
     }
   }
 }
 @Override
 public short next() {
   long t = w & -w;
   short answer = (short) (x * 64 + Long.bitCount(t - 1));
   w ^= t;
   while (w == 0) {
     ++x;
     if (x == bitmap.length) break;
     w = bitmap[x];
   }
   return answer;
 }
 @Override
 public int nextAsInt() {
   long t = w & -w;
   int answer = (x + 1) * 64 - 1 - Long.bitCount(t - 1);
   w ^= t;
   while (w == 0) {
     --x;
     if (x < 0) break;
     w = Long.reverse(bitmap[x]);
   }
   return answer;
 }
 @Override
 public short select(int j) {
   int leftover = j;
   for (int k = 0; k < bitmap.length; ++k) {
     int w = Long.bitCount(bitmap[k]);
     if (w > leftover) {
       return (short) (k * 64 + Util.select(bitmap[k], leftover));
     }
     leftover -= w;
   }
   throw new IllegalArgumentException("Insufficient cardinality.");
 }
 @Override
 public int nextAsInt() {
   long t = w & -w;
   int answer = x * 64 + Long.bitCount(t - 1);
   w ^= t;
   while (w == 0) {
     ++x;
     if (x == bitmap.length) break;
     w = bitmap[x];
   }
   return answer;
 }
 @Override
 public void fillLeastSignificant16bits(int[] x, int i, int mask) {
   int pos = i;
   for (int k = 0; k < bitmap.length; ++k) {
     long bitset = bitmap[k];
     while (bitset != 0) {
       long t = bitset & -bitset;
       x[pos++] = (k * 64 + Long.bitCount(t - 1)) | mask;
       bitset ^= t;
     }
   }
 }
  /**
   * Counts how many runs there is in the bitmap, up to a maximum
   *
   * @param mustNotExceed maximum of runs beyond which counting is pointless
   * @return estimated number of courses
   */
  public int numberOfRunsLowerBound(int mustNotExceed) {
    int numRuns = 0;

    for (int blockOffset = 0; blockOffset < bitmap.length; blockOffset += BLOCKSIZE) {

      for (int i = blockOffset; i < blockOffset + BLOCKSIZE; i++) {
        long word = bitmap[i];
        numRuns += Long.bitCount((~word) & (word << 1));
      }
      if (numRuns > mustNotExceed) return numRuns;
    }
    return numRuns;
  }
 @Override
 public Container or(final BitmapContainer value2) {
   if (USE_IN_PLACE) {
     BitmapContainer value1 = this.clone();
     return value1.ior(value2);
   }
   final BitmapContainer answer = new BitmapContainer();
   answer.cardinality = 0;
   for (int k = 0; k < answer.bitmap.length; ++k) {
     answer.bitmap[k] = this.bitmap[k] | value2.bitmap[k];
     answer.cardinality += Long.bitCount(answer.bitmap[k]);
   }
   return answer;
 }
 @Override
 public Container ixor(BitmapContainer b2) {
   int newCardinality = 0;
   for (int k = 0; k < this.bitmap.length; ++k) {
     newCardinality += Long.bitCount(this.bitmap[k] ^ b2.bitmap[k]);
   }
   if (newCardinality > ArrayContainer.DEFAULT_MAX_SIZE) {
     for (int k = 0; k < this.bitmap.length; ++k) {
       this.bitmap[k] = this.bitmap[k] ^ b2.bitmap[k];
     }
     this.cardinality = newCardinality;
     return this;
   }
   ArrayContainer ac = new ArrayContainer(newCardinality);
   Util.fillArrayXOR(ac.content, this.bitmap, b2.bitmap);
   ac.cardinality = newCardinality;
   return ac;
 }
 @Override
 public Container xor(BitmapContainer value2) {
   int newCardinality = 0;
   for (int k = 0; k < this.bitmap.length; ++k) {
     newCardinality += Long.bitCount(this.bitmap[k] ^ value2.bitmap[k]);
   }
   if (newCardinality > ArrayContainer.DEFAULT_MAX_SIZE) {
     final BitmapContainer answer = new BitmapContainer();
     for (int k = 0; k < answer.bitmap.length; ++k) {
       answer.bitmap[k] = this.bitmap[k] ^ value2.bitmap[k];
     }
     answer.cardinality = newCardinality;
     return answer;
   }
   ArrayContainer ac = new ArrayContainer(newCardinality);
   Util.fillArrayXOR(ac.content, this.bitmap, value2.bitmap);
   ac.cardinality = newCardinality;
   return ac;
 }
 /** Recomputes the cardinality of the bitmap. */
 protected void computeCardinality() {
   this.cardinality = 0;
   for (int k = 0; k < this.bitmap.length; k++) {
     this.cardinality += Long.bitCount(this.bitmap[k]);
   }
 }
  // answer could be a new BitmapContainer, or (for inplace) it can be
  // "this"
  private Container not(BitmapContainer answer, final int firstOfRange, final int lastOfRange) {
    assert bitmap.length == MAX_CAPACITY / 64; // checking assumption
    // that partial
    // bitmaps are not
    // allowed
    // an easy case for full range, should be common
    if (lastOfRange - firstOfRange == MAX_CAPACITY) {
      final int newCardinality = MAX_CAPACITY - cardinality;
      for (int k = 0; k < this.bitmap.length; ++k) answer.bitmap[k] = ~this.bitmap[k];
      answer.cardinality = newCardinality;
      if (newCardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer();
      return answer;
    }

    // could be optimized to first determine the answer cardinality,
    // rather than update/create bitmap and then possibly convert

    int cardinalityChange = 0;
    final int rangeFirstWord = firstOfRange / 64;
    final int rangeFirstBitPos = firstOfRange & 63;
    final int rangeLastWord = (lastOfRange - 1) / 64;
    final long rangeLastBitPos = (lastOfRange - 1) & 63;

    // if not in place, we need to duplicate stuff before
    // rangeFirstWord and after rangeLastWord
    if (answer != this) {
      System.arraycopy(bitmap, 0, answer.bitmap, 0, rangeFirstWord);
      System.arraycopy(
          bitmap,
          rangeLastWord + 1,
          answer.bitmap,
          rangeLastWord + 1,
          bitmap.length - (rangeLastWord + 1));
    }

    // unfortunately, the simple expression gives the wrong mask for
    // rangeLastBitPos==63
    // no branchless way comes to mind
    final long maskOnLeft = (rangeLastBitPos == 63) ? -1L : (1L << (rangeLastBitPos + 1)) - 1;

    long mask = -1L; // now zero out stuff in the prefix
    mask ^= ((1L << rangeFirstBitPos) - 1);

    if (rangeFirstWord == rangeLastWord) {
      // range starts and ends in same word (may have
      // unchanged bits on both left and right)
      mask &= maskOnLeft;
      cardinalityChange = -Long.bitCount(bitmap[rangeFirstWord]);
      answer.bitmap[rangeFirstWord] = bitmap[rangeFirstWord] ^ mask;
      cardinalityChange += Long.bitCount(answer.bitmap[rangeFirstWord]);
      answer.cardinality = cardinality + cardinalityChange;

      if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer();
      return answer;
    }

    // range spans words
    cardinalityChange += -Long.bitCount(bitmap[rangeFirstWord]);
    answer.bitmap[rangeFirstWord] = bitmap[rangeFirstWord] ^ mask;
    cardinalityChange += Long.bitCount(answer.bitmap[rangeFirstWord]);

    cardinalityChange += -Long.bitCount(bitmap[rangeLastWord]);
    answer.bitmap[rangeLastWord] = bitmap[rangeLastWord] ^ maskOnLeft;
    cardinalityChange += Long.bitCount(answer.bitmap[rangeLastWord]);

    // negate the words, if any, strictly between first and last
    for (int i = rangeFirstWord + 1; i < rangeLastWord; ++i) {
      cardinalityChange += (64 - 2 * Long.bitCount(bitmap[i]));
      answer.bitmap[i] = ~bitmap[i];
    }
    answer.cardinality = cardinality + cardinalityChange;

    if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer();
    return answer;
  }