/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sysml.runtime.compress; import java.util.Arrays; import java.util.Iterator; /** * General-purpose iterator to decode a compressed OLE bitmap. * */ public final class BitmapDecoderOLE implements Iterator<Integer> { // pointer to the compressed bitmap private int _bmOff; private int _bmLen; private char[] _bmPtr; // The index of the current block. Block 0 covers bits 1 through 2^16 private int _blockIx; // The offset where the current block starts within the bitmap. private int _blockStartOffset; // The number of offsets in the current block. private int _curBlockSize; // The offset <b>in the current block</b> the <b>next</b> element we will // read from the bitmap, or bmPtr.length if we are done. private int _nextBmOffset; /** * Point this object at the beginning of a particular bitmap. After a call * to this method, the next call to {@link #next()} will return the * offset of the first bit in the specified bitmap. * * @param bmPtr * pointer to a compressed bitmap * @param off offset * @param len length */ public BitmapDecoderOLE(char[] bmPtr, int off, int len) { _bmOff = off; _bmLen = len; _bmPtr = bmPtr; _blockIx = 0; _blockStartOffset = 0; _curBlockSize = _bmPtr[_bmOff+_blockStartOffset]; if (_curBlockSize < 0) { throw new RuntimeException(String.format( "Negative block size %d at position %d of %s", _curBlockSize, _blockStartOffset, Arrays.toString(bmPtr))); } _nextBmOffset = 0; // Advance past any zero-length blocks at the beginning of the array while (_blockStartOffset < _bmLen && _nextBmOffset >= _curBlockSize) { advanceToNextBlock(); } } @Override public Integer next() { if( !hasNext() ) throw new RuntimeException("No next offset existing."); // Grab the lookahead value Note the +1 in the array indexing; // the first number in a block is the block size int offsetFromBlockBegin = _bmPtr[_bmOff+_blockStartOffset + 1 + _nextBmOffset]; int ret = (_blockIx * BitmapEncoder.BITMAP_BLOCK_SZ) + offsetFromBlockBegin; _nextBmOffset++; // Advance to next non-empty block if we reached the end of the block. while (_blockStartOffset < _bmLen && _nextBmOffset >= _curBlockSize) { advanceToNextBlock(); } return ret; } @Override public boolean hasNext() { return _blockStartOffset < _bmLen; } @Override public void remove() { throw new RuntimeException("Not implemented for BitmapDecoderOLE."); } /** * Move forward to the next block. Does not skip empty blocks. */ private void advanceToNextBlock() { _blockStartOffset += (1 + _curBlockSize); _blockIx++; if (_blockStartOffset >= _bmLen) { // Read past last block return; } _curBlockSize = _bmPtr[_bmOff+_blockStartOffset]; if (_curBlockSize < 0) { throw new RuntimeException(String.format( "Negative block size %d at position %d of %s", _curBlockSize, _blockStartOffset, Arrays.toString(_bmPtr))); } _nextBmOffset = 0; } }