@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
  public MappeableContainer add(int begin, int end) {

    int indexstart = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) begin);
    if (indexstart < 0) indexstart = -indexstart - 1;
    int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (end - 1));
    if (indexend < 0) indexend = -indexend - 1;
    else indexend++;
    int rangelength = end - begin;
    int newcardinality = indexstart + (cardinality - indexend) + rangelength;
    if (newcardinality > DEFAULT_MAX_SIZE) {
      MappeableBitmapContainer a = this.toBitmapContainer();
      return a.iadd(begin, end);
    }
    MappeableArrayContainer answer = new MappeableArrayContainer(newcardinality, content);
    if (!BufferUtil.isBackedBySimpleArray(answer.content))
      throw new RuntimeException("Should not happen. Internal bug.");
    BufferUtil.arraycopy(
        content, indexend, answer.content, indexstart + rangelength, cardinality - indexend);
    short[] answerarray = answer.content.array();
    for (int k = 0; k < rangelength; ++k) {
      answerarray[k + indexstart] = (short) (begin + k);
    }
    answer.cardinality = newcardinality;
    return answer;
  }
  @Override
  public MappeableArrayContainer and(final MappeableArrayContainer value2) {

    MappeableArrayContainer value1 = this;
    final int desiredCapacity = Math.min(value1.getCardinality(), value2.getCardinality());
    MappeableArrayContainer answer = new MappeableArrayContainer(desiredCapacity);
    if (BufferUtil.isBackedBySimpleArray(this.content)
        && BufferUtil.isBackedBySimpleArray(value2.content))
      answer.cardinality =
          org.roaringbitmap.Util.unsignedIntersect2by2(
              value1.content.array(),
              value1.getCardinality(),
              value2.content.array(),
              value2.getCardinality(),
              answer.content.array());
    else
      answer.cardinality =
          BufferUtil.unsignedIntersect2by2(
              value1.content,
              value1.getCardinality(),
              value2.content,
              value2.getCardinality(),
              answer.content.array());
    return answer;
  }
  boolean validate(MappeableBitmapContainer bc, MappeableArrayContainer ac) {
    // Checking the cardinalities of each container

    if (bc.getCardinality() != ac.getCardinality()) {
      System.out.println("cardinality differs");
      return false;
    }
    // Checking that the two containers contain the same values
    int counter = 0;

    int i = bc.nextSetBit(0);
    while (i >= 0) {
      ++counter;
      if (!ac.contains((short) i)) {
        System.out.println("content differs");
        System.out.println(bc);
        System.out.println(ac);
        return false;
      }
      i = bc.nextSetBit(i + 1);
    }

    // checking the cardinality of the BitmapContainer
    return counter == bc.getCardinality();
  }
  @Test
  public void ContainerFactory() {
    MappeableBitmapContainer bc1, bc2, bc3;
    MappeableArrayContainer ac1, ac2, ac3;

    bc1 = new MappeableBitmapContainer();
    bc2 = new MappeableBitmapContainer();
    bc3 = new MappeableBitmapContainer();
    ac1 = new MappeableArrayContainer();
    ac2 = new MappeableArrayContainer();
    ac3 = new MappeableArrayContainer();

    for (short i = 0; i < 5000; i++) bc1.add((short) (i * 70));
    for (short i = 0; i < 5000; i++) bc2.add((short) (i * 70));
    for (short i = 0; i < 5000; i++) bc3.add((short) (i * 70));

    for (short i = 0; i < 4000; i++) ac1.add((short) (i * 50));
    for (short i = 0; i < 4000; i++) ac2.add((short) (i * 50));
    for (short i = 0; i < 4000; i++) ac3.add((short) (i * 50));

    MappeableBitmapContainer rbc;

    rbc = ac1.clone().toBitmapContainer();
    Assert.assertTrue(validate(rbc, ac1));
    rbc = ac2.clone().toBitmapContainer();
    Assert.assertTrue(validate(rbc, ac2));
    rbc = ac3.clone().toBitmapContainer();
    Assert.assertTrue(validate(rbc, ac3));
  }
 @Test
 public void ArrayContainerCardinalityTest() {
   final MappeableArrayContainer ac = new MappeableArrayContainer();
   for (short k = 0; k < 100; ++k) {
     ac.add(k);
     Assert.assertEquals(ac.getCardinality(), k + 1);
   }
   for (short k = 0; k < 100; ++k) {
     ac.add(k);
     Assert.assertEquals(ac.getCardinality(), 100);
   }
 }
 @Test
 public void arraytest() {
   final MappeableArrayContainer rr = new MappeableArrayContainer();
   rr.add((short) 110);
   rr.add((short) 114);
   rr.add((short) 115);
   final short[] array = new short[3];
   int pos = 0;
   for (final short i : rr) array[pos++] = i;
   Assert.assertEquals(array[0], (short) 110);
   Assert.assertEquals(array[1], (short) 114);
   Assert.assertEquals(array[2], (short) 115);
 }
  // shares lots of code with inot; candidate for refactoring
  @Override
  public MappeableContainer not(final int firstOfRange, final int lastOfRange) {
    // TODO: this can be optimized for performance
    if (firstOfRange >= lastOfRange) {
      return clone(); // empty range
    }

    // determine the span of array indices to be affected
    int startIndex = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) firstOfRange);
    if (startIndex < 0) startIndex = -startIndex - 1;
    int lastIndex =
        BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (lastOfRange - 1));
    if (lastIndex < 0) lastIndex = -lastIndex - 2;
    final int currentValuesInRange = lastIndex - startIndex + 1;
    final int spanToBeFlipped = lastOfRange - firstOfRange;
    final int newValuesInRange = spanToBeFlipped - currentValuesInRange;
    final int cardinalityChange = newValuesInRange - currentValuesInRange;
    final int newCardinality = cardinality + cardinalityChange;

    if (newCardinality > DEFAULT_MAX_SIZE)
      return toBitmapContainer().not(firstOfRange, lastOfRange);

    final MappeableArrayContainer answer = new MappeableArrayContainer(newCardinality);
    if (!BufferUtil.isBackedBySimpleArray(answer.content))
      throw new RuntimeException("Should not happen. Internal bug.");
    short[] sarray = answer.content.array();

    for (int i = 0; i < startIndex; ++i)
      // copy stuff before the active area
      sarray[i] = content.get(i);

    int outPos = startIndex;
    int inPos = startIndex; // item at inPos always >= valInRange

    int valInRange = firstOfRange;
    for (; valInRange < lastOfRange && inPos <= lastIndex; ++valInRange) {
      if ((short) valInRange != content.get(inPos)) sarray[outPos++] = (short) valInRange;
      else {
        ++inPos;
      }
    }

    for (; valInRange < lastOfRange; ++valInRange) {
      answer.content.put(outPos++, (short) valInRange);
    }

    // content after the active range
    for (int i = lastIndex + 1; i < cardinality; ++i) answer.content.put(outPos++, content.get(i));
    answer.cardinality = newCardinality;
    return answer;
  }
  /**
   * it must return items in (unsigned) sorted order. Possible candidate for Container interface? *
   */
  private MappeableContainer or(ShortIterator it, boolean exclusive) {
    MappeableArrayContainer ac = new MappeableArrayContainer();
    int myItPos = 0;
    ac.cardinality = 0;
    // do a merge.  int -1 denotes end of input.
    int myHead = (myItPos == cardinality) ? -1 : BufferUtil.toIntUnsigned(content.get(myItPos++));
    int hisHead = advance(it);

    while (myHead != -1 && hisHead != -1) {
      if (myHead < hisHead) {
        ac.emit((short) myHead);
        myHead = (myItPos == cardinality) ? -1 : BufferUtil.toIntUnsigned(content.get(myItPos++));
      } else if (myHead > hisHead) {
        ac.emit((short) hisHead);
        hisHead = advance(it);
      } else {
        if (!exclusive) ac.emit((short) hisHead);
        hisHead = advance(it);
        myHead = (myItPos == cardinality) ? -1 : BufferUtil.toIntUnsigned(content.get(myItPos++));
      }
    }

    while (myHead != -1) {
      ac.emit((short) myHead);
      myHead = (myItPos == cardinality) ? -1 : BufferUtil.toIntUnsigned(content.get(myItPos++));
    }

    while (hisHead != -1) {
      ac.emit((short) hisHead);
      hisHead = advance(it);
    }

    if (ac.cardinality > DEFAULT_MAX_SIZE) return ac.toBitmapContainer();
    else return ac;
  }
 @Override
 public MappeableArrayContainer iand(final MappeableArrayContainer value2) {
   final MappeableArrayContainer value1 = this;
   if (!BufferUtil.isBackedBySimpleArray(value1.content))
     throw new RuntimeException("Should not happen. Internal bug.");
   value1.cardinality =
       BufferUtil.unsignedIntersect2by2(
           value1.content,
           value1.getCardinality(),
           value2.content,
           value2.getCardinality(),
           value1.content.array());
   return this;
 }
  @Override
  public MappeableArrayContainer andNot(MappeableBitmapContainer value2) {

    final MappeableArrayContainer answer = new MappeableArrayContainer(content.limit());
    int pos = 0;
    short[] sarray = answer.content.array();
    if (BufferUtil.isBackedBySimpleArray(this.content)) {
      short[] c = content.array();
      for (int k = 0; k < cardinality; ++k) if (!value2.contains(c[k])) sarray[pos++] = c[k];
    } else
      for (int k = 0; k < cardinality; ++k) {
        short v = this.content.get(k);
        if (!value2.contains(v)) sarray[pos++] = v;
      }
    answer.cardinality = pos;
    return answer;
  }
 @Override
 public MappeableContainer remove(int begin, int end) {
   int indexstart = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) begin);
   if (indexstart < 0) indexstart = -indexstart - 1;
   int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (end - 1));
   if (indexend < 0) indexend = -indexend - 1;
   else indexend++;
   int rangelength = indexend - indexstart;
   MappeableArrayContainer answer = clone();
   BufferUtil.arraycopy(
       content,
       indexstart + rangelength,
       answer.content,
       indexstart,
       cardinality - indexstart - rangelength);
   answer.cardinality = cardinality - rangelength;
   return answer;
 }
  @Override
  public MappeableArrayContainer iandNot(final MappeableArrayContainer value2) {
    if (!BufferUtil.isBackedBySimpleArray(this.content))
      throw new RuntimeException("Should not happen. Internal bug.");
    if (BufferUtil.isBackedBySimpleArray(value2.content))
      this.cardinality =
          org.roaringbitmap.Util.unsignedDifference(
              this.content.array(),
              this.getCardinality(),
              value2.content.array(),
              value2.getCardinality(),
              this.content.array());
    else
      this.cardinality =
          BufferUtil.unsignedDifference(
              this.content,
              this.getCardinality(),
              value2.content,
              value2.getCardinality(),
              this.content.array());

    return this;
  }
 @Override
 public void remove() {
   parent.remove((short) (pos + 1));
   pos++;
 }
 RawReverseArrayContainerShortIterator(MappeableArrayContainer p) {
   parent = p;
   if (!p.isArrayBacked()) throw new RuntimeException("internal bug");
   content = p.content.array();
   pos = parent.cardinality - 1;
 }