/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.io;
import java.util.Stack;
/**
* This class provides a block factory, i.e. this class manages the
* allocation of blocks on an underlying byte array.<p>
*
* Blocks allocated by the same block factory always have the same size.
* Internally, the block factory separates the underlying byte array
* logically in <i>smaller</i> arrays of <tt>blockSize</tt> bytes and
* stores the first indices of this arrays in a stack. Every time the
* allocate method is called, the block factory checks whether the stack
* stores another index and returns a new block of <tt>blockSize</tt>
* bytes that starts at this index or returns <tt>null</tt> if the stack
* is empty.<br>
* When releasing a block allocated by this factory its <i>offset</i> (the
* first index of the block in the byte array) is pushed on the stack.<p>
*
* Example usage (1).
* <pre>
* // create a new byte array of 100 bytes
*
* byte [] array = new byte [100];
*
* // create a new block factory that creates block of 20 bytes
*
* BlockFactory factory = new BlockFactory(array, 20);
*
* // create a new array of 6 blocks
*
* Block [] blocks = new Block [6];
*
* // try to allocate 6 blocks
*
* for (int i = 0; i < 6; i++) {
* blocks[i] = factory.allocate();
* if (blocks[i]==null) {
* System.out.println("array is exhausted");
* break;
* }
* else
* System.out.println("block allocated");
* }
*
* // release a block
*
* blocks[0].release();
*
* // try again to allocate the sixth block
*
* blocks[5] = factory.allocate();
* if (blocks[5] == null)
* System.out.println("array is exhausted");
* else
* System.out.println("block allocated");
*
* // release the rest of the blocks
*
* for (int i = 1; i < 6; i++)
* blocks[i].release();
* </pre>
*
* @see Stack
*/
public class BlockFactory {
/**
* The underlying byte array that stores the blocks allocated by this
* block factory.
*/
protected byte [] array;
/**
* The size of a block allocated by this block factory. Blocks
* allocated by the same block factory always have the same size.
*/
protected int blockSize;
/**
* This stack is used for storing the offsets of empty blocks. Every
* time a new block is allocated, its offset is popped out of the
* stack and every time a block allocated by this factory is released,
* its offset is pushed on the stack. For this reason an empty stack
* signals that the underlying byte array of this block factory is
* exhausted.
*/
Stack stack = new Stack();
/**
* Constructs a new BlockFactory that stores blocks of the specified
* size in the specified byte array. Internally the byte array is
* logically separated in <i>smaller</i> arrays of <tt>blockSize</tt>
* bytes and the first indices of this arrays are stored in the stack.
*
* @param array the byte array that is internally used for storing the
* blocks allocated by this block factory.
* @param blockSize the size of the blocks allocated by this block
* factory.
*/
public BlockFactory (byte [] array, int blockSize) {
this.array = array;
this.blockSize = blockSize;
for (int i = 0; i<array.length/blockSize;)
stack.push(new Integer(i++*blockSize));
}
/**
* Allocates and returns a new block on the underlying array. When
* calling this method it checks wheteher the stack stores another
* index and returns a new block of <tt>blockSize</tt> bytes that
* starts at this index or returns null if the stack is empty. When
* releasing a block allocated by this factory its <i>offset</i> (the
* first index of the block in the byte array) is pushed on the stack.
*
* @return a new block that is stored on the underlying byte array or
* null if the byte array is exhausted.
*/
public Block allocate () {
if (stack.isEmpty())
return null;
else {
int offset = ((Integer)stack.pop()).intValue();
return new Block(array, offset, blockSize) {
public void release () {
super.release();
stack.push(new Integer(this.offset));
}
};
}
}
}