@Override public MappeableContainer andNot(final MappeableRunContainer x) { int writeLocation = 0; int runStart, runEnd; // the current or upcoming run. int whichRun; if (x.nbrruns == 0) return clone(); ShortBuffer buffer = ShortBuffer.allocate(cardinality); runStart = BufferUtil.toIntUnsigned(x.getValue(0)); runEnd = runStart + BufferUtil.toIntUnsigned(x.getLength(0)); whichRun = 0; short val; for (int i = 0; i < cardinality; ++i) { val = content.get(i); int valInt = BufferUtil.toIntUnsigned(val); if (valInt < runStart) { buffer.put(writeLocation++, val); } else if (valInt <= runEnd) ; // don't want item else { // greater than this run, need to do an advanceUntil on runs // done sequentially for now (no galloping attempts). do { if (whichRun + 1 < x.nbrruns) { whichRun++; runStart = BufferUtil.toIntUnsigned(x.getValue(whichRun)); runEnd = runStart + BufferUtil.toIntUnsigned(x.getLength(whichRun)); } else runStart = runEnd = (1 << 16) + 1; // infinity.... } while (valInt > runEnd); --i; // need to re-process this val } } return new MappeableArrayContainer(writeLocation, buffer); }
@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; }
/** * 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 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 iadd(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); } if (newcardinality >= this.content.limit()) increaseCapacity(newcardinality); BufferUtil.arraycopy( content, indexend, content, indexstart + rangelength, cardinality - indexend); if (BufferUtil.isBackedBySimpleArray(content)) { short[] contentarray = content.array(); for (int k = 0; k < rangelength; ++k) { contentarray[k + indexstart] = (short) (begin + k); } } else { for (int k = 0; k < rangelength; ++k) { content.put(k + indexstart, (short) (begin + k)); } } cardinality = newcardinality; return this; }
@Override int numberOfRuns() { if (cardinality == 0) return 0; // should never happen if (BufferUtil.isBackedBySimpleArray(content)) { short[] c = content.array(); int numRuns = 1; for (int i = 0; i < cardinality - 1; i++) { // this way of doing the computation maximizes superscalar opportunities, can even // vectorize! if (BufferUtil.toIntUnsigned(c[i]) + 1 != BufferUtil.toIntUnsigned(c[i + 1])) ++numRuns; } return numRuns; } else { int numRuns = 0; int previous = -2; // we do not proceed like above for fear that calling "get" twice per loop would be too much for (int i = 0; i < cardinality; i++) { int val = BufferUtil.toIntUnsigned(content.get(i)); if (val != previous + 1) ++numRuns; previous = val; } return numRuns; } }
@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 MappeableContainer flip(short x) { if (BufferUtil.isBackedBySimpleArray(this.content)) { short[] sarray = content.array(); int loc = Util.unsignedBinarySearch(sarray, 0, cardinality, x); if (loc < 0) { // Transform the ArrayContainer to a BitmapContainer // when cardinality = DEFAULT_MAX_SIZE if (cardinality >= DEFAULT_MAX_SIZE) { MappeableBitmapContainer a = this.toBitmapContainer(); a.add(x); return a; } if (cardinality >= sarray.length) { increaseCapacity(); sarray = content.array(); } // insertion : shift the elements > x by one position to // the right // and put x in it's appropriate place System.arraycopy(sarray, -loc - 1, sarray, -loc, cardinality + loc + 1); sarray[-loc - 1] = x; ++cardinality; } else { System.arraycopy(sarray, loc + 1, sarray, loc, cardinality - loc - 1); --cardinality; } return this; } else { int loc = BufferUtil.unsignedBinarySearch(content, 0, cardinality, x); if (loc < 0) { // Transform the ArrayContainer to a BitmapContainer // when cardinality = DEFAULT_MAX_SIZE if (cardinality >= DEFAULT_MAX_SIZE) { MappeableBitmapContainer a = this.toBitmapContainer(); a.add(x); return a; } if (cardinality >= content.limit()) { increaseCapacity(); } // insertion : shift the elements > x by one position to // the right // and put x in it's appropriate place for (int k = cardinality; k > -loc - 1; --k) content.put(k, content.get(k - 1)); content.put(-loc - 1, x); ++cardinality; } else { for (int k = loc + 1; k < cardinality; --k) { content.put(k - 1, content.get(k)); } --cardinality; } return this; } }
@Override public void fillLeastSignificant16bits(int[] x, int i, int mask) { if (BufferUtil.isBackedBySimpleArray(this.content)) { short[] c = this.content.array(); for (int k = 0; k < this.cardinality; ++k) x[k + i] = BufferUtil.toIntUnsigned(c[k]) | mask; } else for (int k = 0; k < this.cardinality; ++k) x[k + i] = BufferUtil.toIntUnsigned(this.content.get(k)) | mask; }
// 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; }
@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 MappeableContainer iremove(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; BufferUtil.arraycopy( content, indexstart + rangelength, content, indexstart, cardinality - indexstart - rangelength); cardinality -= rangelength; return this; }
@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 int rank(short lowbits) { int answer = BufferUtil.unsignedBinarySearch(content, 0, cardinality, lowbits); if (answer >= 0) { return answer + 1; } else { return -answer - 1; } }
@Override public MappeableArrayContainer iandNot(MappeableBitmapContainer value2) { if (!BufferUtil.isBackedBySimpleArray(this.content)) throw new RuntimeException("Should not happen. Internal bug."); short[] c = this.content.array(); int pos = 0; for (int k = 0; k < cardinality; ++k) if (!value2.contains(c[k])) c[pos++] = c[k]; this.cardinality = pos; return this; }
@Override public MappeableContainer inot(final int firstOfRange, final int lastOfRange) { // TODO: this can be optimized for performance // 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 - 1 - 1; final int currentValuesInRange = lastIndex - startIndex + 1; final int spanToBeFlipped = lastOfRange - firstOfRange; final int newValuesInRange = spanToBeFlipped - currentValuesInRange; final ShortBuffer buffer = ShortBuffer.allocate(newValuesInRange); final int cardinalityChange = newValuesInRange - currentValuesInRange; final int newCardinality = cardinality + cardinalityChange; if (cardinalityChange > 0) { // expansion, right shifting needed if (newCardinality > content.limit()) { // so big we need a bitmap? if (newCardinality > DEFAULT_MAX_SIZE) return toBitmapContainer().inot(firstOfRange, lastOfRange); final ShortBuffer co = ShortBuffer.allocate(newCardinality); content.rewind(); co.put(content); content = co; } // slide right the contents after the range for (int pos = cardinality - 1; pos > lastIndex; --pos) content.put(pos + cardinalityChange, content.get(pos)); negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange); } else { // no expansion needed negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange); if (cardinalityChange < 0) // contraction, left sliding. // Leave array oversize for (int i = startIndex + newValuesInRange; i < newCardinality; ++i) content.put(i, content.get(i - cardinalityChange)); } cardinality = newCardinality; return this; }
@Override public void trim() { if (this.content.limit() == this.cardinality) return; if (BufferUtil.isBackedBySimpleArray(content)) { this.content = ShortBuffer.wrap(Arrays.copyOf(content.array(), cardinality)); } else { final ShortBuffer co = ShortBuffer.allocate(this.cardinality); // can assume that new co is array backed short[] x = co.array(); for (int k = 0; k < this.cardinality; ++k) x[k] = this.content.get(k); this.content = co; } }
@Override public MappeableContainer remove(final short x) { if (BufferUtil.isBackedBySimpleArray(this.content)) { final int loc = Util.unsignedBinarySearch(content.array(), 0, cardinality, x); if (loc >= 0) { // insertion System.arraycopy(content.array(), loc + 1, content.array(), loc, cardinality - loc - 1); --cardinality; } return this; } else { final int loc = BufferUtil.unsignedBinarySearch(content, 0, cardinality, x); if (loc >= 0) { // insertion for (int k = loc + 1; k < cardinality; --k) { content.put(k - 1, content.get(k)); } --cardinality; } return this; } }
@Override public boolean equals(Object o) { if (o instanceof MappeableArrayContainer) { final MappeableArrayContainer srb = (MappeableArrayContainer) o; if (srb.cardinality != this.cardinality) return false; if (BufferUtil.isBackedBySimpleArray(this.content) && BufferUtil.isBackedBySimpleArray(srb.content)) { short[] t = this.content.array(); short[] sr = srb.content.array(); for (int i = 0; i < this.cardinality; ++i) { if (t[i] != sr[i]) return false; } } else for (int i = 0; i < this.cardinality; ++i) { if (this.content.get(i) != srb.content.get(i)) return false; } return true; } else if (o instanceof MappeableRunContainer) return o.equals(this); return false; }
@Override protected void writeArray(DataOutput out) throws IOException { // little endian if (BufferUtil.isBackedBySimpleArray(content)) { short[] a = content.array(); for (int k = 0; k < this.cardinality; ++k) { out.writeShort(Short.reverseBytes(a[k])); } } else { for (int k = 0; k < this.cardinality; ++k) { out.writeShort(Short.reverseBytes(content.get(k))); } } }
@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 writeExternal(ObjectOutput out) throws IOException { out.write(this.cardinality & 0xFF); out.write((this.cardinality >>> 8) & 0xFF); if (BufferUtil.isBackedBySimpleArray(content)) { short[] a = content.array(); for (int k = 0; k < this.cardinality; ++k) { out.writeShort(Short.reverseBytes(a[k])); } } else { for (int k = 0; k < this.cardinality; ++k) { out.writeShort(Short.reverseBytes(content.get(k))); } } }
@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; }
/** * Reads an image from an archived file and return it as ByteBuffer object. * * @author Mike Butler, Kiet Le */ private ByteBuffer readImage(String filename, Dimension dim) { if (dim == null) dim = new Dimension(0, 0); ByteBuffer bytes = null; try { DataInputStream dis = new DataInputStream(getClass().getClassLoader().getResourceAsStream(filename)); dim.width = dis.readInt(); dim.height = dis.readInt(); System.out.println("Creating buffer, width: " + dim.width + " height: " + dim.height); // byte[] buf = new byte[3 * dim.height * dim.width]; bytes = BufferUtil.newByteBuffer(3 * dim.width * dim.height); for (int i = 0; i < bytes.capacity(); i++) { bytes.put(dis.readByte()); } dis.close(); } catch (Exception e) { e.printStackTrace(); } bytes.rewind(); return bytes; }
@Override public void advanceIfNeeded(short minval) { pos = BufferUtil.advanceUntil(parent.content, pos - 1, parent.cardinality, minval); }
@Override public int nextAsInt() { return BufferUtil.toIntUnsigned(parent.content.get(pos--)); }
private int advance(ShortIterator it) { if (it.hasNext()) return BufferUtil.toIntUnsigned(it.next()); else return -1; }
@Override public int nextAsInt() { return BufferUtil.toIntUnsigned(content[pos--]); }
protected void loadData(final MappeableBitmapContainer bitmapContainer) { this.cardinality = bitmapContainer.cardinality; if (!BufferUtil.isBackedBySimpleArray(this.content)) throw new RuntimeException("Should not happen. Internal bug."); bitmapContainer.fillArray(content.array()); }
@Override public boolean contains(final short x) { return BufferUtil.unsignedBinarySearch(content, 0, cardinality, x) >= 0; }