// PoolOutputBuffer.java
package org.bson.io;
import org.bson.*;
import org.bson.io.*;
import org.bson.util.*;
import java.io.*;
import java.util.*;
public class PoolOutputBuffer extends OutputBuffer {
public static final int BUF_SIZE = 1024 * 16;
public PoolOutputBuffer(){
reset();
}
public void reset(){
_cur.reset();
_end.reset();
for ( int i=0; i<_fromPool.size(); i++ )
_extra.done( _fromPool.get(i) );
_fromPool.clear();
}
public int getPosition(){
return _cur.pos();
}
public void setPosition( int position ){
_cur.reset( position );
}
public void seekEnd(){
_cur.reset( _end );
}
public void seekStart(){
_cur.reset();
}
public int size(){
return _end.pos();
}
public void write(byte[] b){
write( b , 0 , b.length );
}
public void write(byte[] b, int off, int len){
while ( len > 0 ){
byte[] bs = _cur();
int space = Math.min( bs.length - _cur.y , len );
System.arraycopy( b , off , bs , _cur.y , space );
_cur.inc( space );
len -= space;
off += space;
_afterWrite();
}
}
public void write(int b){
byte[] bs = _cur();
bs[_cur.getAndInc()] = (byte)(b&0xFF);
_afterWrite();
}
void _afterWrite(){
if ( _cur.pos() < _end.pos() ){
// we're in the middle of the total space
// just need to make sure we're not at the end of a buffer
if ( _cur.y == BUF_SIZE )
_cur.nextBuffer();
return;
}
_end.reset( _cur );
if ( _end.y < BUF_SIZE )
return;
_fromPool.add( _extra.get() );
_end.nextBuffer();
_cur.reset( _end );
}
byte[] _cur(){
return _get( _cur.x );
}
byte[] _get( int z ){
if ( z < 0 )
return _mine;
return _fromPool.get(z);
}
public int pipe( OutputStream out )
throws IOException {
int total = 0;
for ( int i=-1; i<_fromPool.size(); i++ ){
byte[] b = _get( i );
int amt = _end.len( i );
out.write( b , 0 , amt );
total += amt;
}
return total;
}
static class Position {
Position(){
reset();
}
void reset(){
x = -1;
y = 0;
}
void reset( Position other ){
x = other.x;
y = other.y;
}
void reset( int pos ){
x = ( pos / BUF_SIZE ) - 1;
y = pos % BUF_SIZE;
}
int pos(){
return ( ( x + 1 ) * BUF_SIZE ) + y;
}
int getAndInc(){
return y++;
}
void inc( int amt ){
y += amt;
if ( y > BUF_SIZE )
throw new IllegalArgumentException( "something is wrong" );
}
void nextBuffer(){
if ( y != BUF_SIZE )
throw new IllegalArgumentException( "broken" );
x++;
y = 0;
}
int len( int which ){
if ( which < x )
return BUF_SIZE;
return y;
}
public String toString(){
return x + "," + y;
}
int x; // which buffer -1 == _mine
int y; // position in buffer
}
public String asString(){
if ( _fromPool.size() > 0 )
return super.asString();
return new String( _mine , 0 , size() );
}
public String asString( String encoding )
throws UnsupportedEncodingException {
if ( _fromPool.size() > 0 )
return super.asString( encoding );
return new String( _mine , 0 , size() , encoding );
}
final byte[] _mine = new byte[BUF_SIZE];
final List<byte[]> _fromPool = new ArrayList<byte[]>();
private final Position _cur = new Position();
private final Position _end = new Position();
private static org.bson.util.SimplePool<byte[]> _extra =
new org.bson.util.SimplePool<byte[]>( ( 1024 * 1024 * 10 ) / BUF_SIZE ){
protected byte[] createNew(){
return new byte[BUF_SIZE];
}
};
}