@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 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; }
/** * 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 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 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; }
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--]); }
@Override public int nextAsInt() { return BufferUtil.toIntUnsigned(parent.content.get(pos--)); }