bbBlock remove()

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;
    }