in src/com/amazon/ion/impl/BlockedBuffer.java [730:818]
bbBlock remove(Object caller, int version, bbBlock curr, int pos, int len)
{
assert mutation_in_progress(caller, version);
if (len == 0) return curr;
if (len < 0 || (pos + len) > this._buf_limit) {
throw new IllegalArgumentException();
}
int amountToRemove = len;
int removedBlocks = 0;
int startingIdx = curr._idx;
int currIdx = curr._idx;
bbBlock currBlock = curr;
assert (curr._offset <= pos);
assert (pos - curr._offset <= curr._limit);
assert _validate();
// this is to simply eliminate a big edge case
if (pos == 0 && len == this._buf_limit) {
this.clear(caller, version);
notifyRemove(0, len);
return null;
}
// remove from the initial block
int currBlockPosition = currBlock.blockOffsetFromAbsolute(pos);
int removedFromThisBlock = currBlock._limit - currBlockPosition;
if (removedFromThisBlock > amountToRemove) removedFromThisBlock = amountToRemove;
if (removedFromThisBlock == currBlock._limit) {
// we'll be removing the whole block in the whole block loop below
startingIdx--; // so we have to back up on to fix the next block that will
// "fall" down into the soon to be emptied slot here
}
else {
// we always copy into position, and we copy whatever is still
// left in the end of the block
int moveAmount = currBlock._limit - currBlockPosition - removedFromThisBlock;
if (moveAmount > 0) {
System.arraycopy(currBlock._buffer, currBlock._limit - moveAmount
,currBlock._buffer, currBlockPosition, moveAmount);
}
amountToRemove -= removedFromThisBlock;
currBlock._limit -= removedFromThisBlock;
if (amountToRemove > 0) {
// when we're on the last block, there'll be nothing to remove,
// and no block to get either
currIdx = currBlock._idx + 1;
currBlock = this._blocks.get(currIdx);
}
}
while (amountToRemove > 0 && amountToRemove >= currBlock._limit) {
amountToRemove -= currBlock._limit;
// remove the whole block - so first hang onto a reference
bbBlock temp = currBlock;
this._blocks.remove(currIdx);
removedBlocks++;
temp.clearBlock();
this._blocks.add(temp); // dump it at the end (marked as not in use)
// and we don't move currIdx because we bumped it out of the whole array
if (currIdx < this._next_block_position - removedBlocks) {
currBlock = this._blocks.get(currIdx);
}
else if (currIdx > 0) {
currIdx--;
currBlock = this._blocks.get(currIdx);
}
else {
throw new BlockedBufferException("fatal - no current block!");
}
}
if (amountToRemove > 0) {
assert amountToRemove < currBlock._limit;
System.arraycopy(currBlock._buffer, amountToRemove
,currBlock._buffer, 0, currBlock._limit - amountToRemove);
assert amountToRemove < currBlock._limit;
currBlock._limit -= amountToRemove;
currBlock._offset += amountToRemove;
}
// we'll even adjust the offset of the first block (if it's the last as well)
adjustOffsets(startingIdx, -len, -removedBlocks);
notifyRemove(pos, len);
// DEBUG: int shouldBe = 0;
// DEBUG: int is = currBlock._offset;
// DEBUG: if (currBlock._idx > 0) {
// DEBUG: shouldBe = this._blocks.get(currBlock._idx - 1)._offset + this._blocks.get(currBlock._idx - 1)._limit;
// DEBUG: if (currIdx != startingIdx) assert (shouldBe == this._buf_position);
// DEBUG: }
// DEBUG: int delta = shouldBe - is;
// DEBUG: assert(delta == 0);
assert _validate();
return currBlock;
}