Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.storemate.shared.util;
  
  import java.util.*;


Helper class that is similar to java.io.ByteArrayOutputStream in usage, but bit more efficient for use cases StoreMate has. Instead of a single byte array, underlying storage is a List of arrays (that is, segmented virtual array). The biggest chunk is also recycled as necessary using BufferRecycler)

Note that instances are NOT designed to be reusable, since instance creation is cheap as the underlying buffers are automatically recycled as necessary. So do not try to be clever and reuse instances; this will most likely not work.

 
 public final class ByteAggregator
     extends OutputStream
 {
     private final static byte[] NO_BYTES = new byte[0];
 
     private final static int MIN_FIRST_BLOCK_SIZE = 0x1000; // 4k for first chunk
 
     private final static int MIN_OTHER_BLOCK_SIZE = 0x4000; // 16k at least afterwards
     
    
Maximum block size we will use for individual non-aggregated blocks. Let's limit to using 256k chunks.
 
     private final static int MAX_BLOCK_SIZE = (1 << 18);

    
We can recycle parts of buffer, which is especially useful when dealing with small content, but can also help reduce first-chunk overhead for larger ones.
 
     private final static BufferRecycler _bufferRecycler = new BufferRecycler();
 
     private final BufferRecycler.Holder _bufferHolder;
     
     private LinkedList<byte[]> _pastBlocks = null;

    
Number of bytes within byte arrays in _pastBlocks.
 
     private int _pastLen;

    
Currently active processing block
 
     private byte[] _currBlock;
 
     private int _currBlockPtr;
 
     public ByteAggregator()
     {
          = .getHolder();
          = .borrowBuffer();
          = 0;
     }
 
     public ByteAggregator(int minSize)
     {
          = .getHolder();
          = .borrowBuffer(minSize);
          = 0;
     }
     
     public ByteAggregator(byte[] dataint offsetint len)
     {
          = .getHolder();        
          = .borrowBuffer(len);
          = 0;
         System.arraycopy(dataoffset, 0, len);
          = len;
     }
 
     public static ByteAggregator with(ByteAggregator aggr,
             byte[] dataint offsetint len)
     {
         if (aggr == null) {
             aggr = new ByteAggregator(dataoffsetlen);
         } else {
             aggr.write(dataoffsetlen);
         }
         return aggr;
     }
     
     protected void reset()
     {
          = 0;
          = 0;
         if ( != null) {
             .clear();
         }
         = null;
    }

    
Method called when results are finalized and we can get the full aggregated result buffer to return to the caller. Note that this also implicitly calls reset() so that no content is available for further calls.
    public byte[] toByteArray()
    {
        int totalLen =  + ;
        
        if (totalLen == 0) { // quick check: nothing aggregated?
            return ;
        }
        
        byte[] result = new byte[totalLen];
        int offset = 0;
        if ( != null && !.isEmpty()) {
            for (byte[] block : ) {
                
                int len = block.length;
                System.arraycopy(block, 0, resultoffsetlen);
                offset += len;
            }
        }
        System.arraycopy(, 0, resultoffset);
        offset += ;
        reset();
        if (offset != totalLen) { // just a sanity check
            throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes");
        }
        return result;
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // OutputStream implementation
    ///////////////////////////////////////////////////////////////////////
     */
    @Override
    public void write(byte[] b) {
        write(b, 0, b.length);
    }
    @Override
    public void write(byte[] bint offint len)
    {
        while (true) {
            int max = . - ;
            int toCopy = Math.min(maxlen);
            if (toCopy > 0) {
                System.arraycopy(bofftoCopy);
                off += toCopy;
                 += toCopy;
                len -= toCopy;
            }
            if (len <= 0) break;
            _allocMore();
        }
    }
    @Override
    public void write(int b) {
        if ( >= .) {
            _allocMore();
        }
        [++] = (byteb;
    }
    @Override public void close() { /* NOP */ }
    @Override public void flush() { /* NOP */ }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Other public methods
    ///////////////////////////////////////////////////////////////////////
     */
    public final int size() {
        return  + ;
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Advanced functionality for "filling up" 
    ///////////////////////////////////////////////////////////////////////
     */
    
    
Helper method for trying to read up to specified amount of content into this aggregator. Will try to read up to specified amount, and either read and return that amount (if enough content available); or return number of bytes read (if less content available).

Returns:
Number of bytes actually read
    public int readUpTo(InputStream infinal int maxLen)
        throws IOException
    {
        int readCount = 0;
        while (true) {
            final int leftToRead = maxLen - readCount;
            if (leftToRead <= 0) {
                break;
            }
            // find some space to read stuff into
            int free = . - ;
            if (free == 0) {
                _allocMore();
                free = . - ;
            }
            int count = in.read(, 0, Math.min(freeleftToRead));
            if (count < 0) {
                break;
            }
            readCount += count;
             += count;
        }
        return readCount;
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Internal methods
    ///////////////////////////////////////////////////////////////////////
     */
    private void _allocMore()
    {
         += .;
        /* Let's allocate block that's half the total size, except no smaller
         * than the initial block size (16k)
         */
        int newSize = Math.max(( >> 1), );
        // plus not to exceed max we define...
        if (newSize > ) {
            newSize = ;
        }
        if ( == null) {
             = new LinkedList<byte[]>();
        }
        .add();
         = new byte[newSize];
         = 0;
    }
New to GrepCode? Check out our FAQ X