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, but instead rely on lower level byte buffer recycling that occurs automatically, as long as you call release() either directly or indirectly (note: close() will NOT call release()).

 
 public class ByteAggregator
     extends OutputStream
 {
     protected final static byte[] NO_BYTES = new byte[0];
 
     protected final static int DEFAULT_MAX_BLOCK_SIZE = (1 << 18);
     
     protected final static int MIN_FIRST_BLOCK_SIZE = 0x1000; // 4k for first chunk
 
     protected 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.
 
     protected int MAX_BLOCK_SIZE = ;

    
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.
 
     protected final static BufferRecycler _bufferRecycler = new BufferRecycler();
 
     protected final BufferRecycler.Holder _bufferHolder;
 
     protected LinkedList<byte[]> _pastBlocks = null;

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

    
Currently active processing block
 
     protected byte[] _currBlock;
 
     protected int _currBlockPtr;
     
     /*
     /**********************************************************************
     /* Life-cycle
     /**********************************************************************
      */
     
     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;
    }

    
Alias for release().

Deprecated:
Use release() instead
    @Deprecated
    public void reset()
    {
        release();
    }
    
    
Method for clearing out all aggregated content, but without returning all recyclable buffers, to make it possible to use this instance efficiently.
    public void resetForReuse()
    {
         = 0;
         = 0;
        if ( != null) {
            .clear();
        }
    }

    
Method for clearing out all aggregated content and return recyclable buffers for reuse, if possible, rendering this instance unusable for further operations.

Note that instance can NOT be used after this method is called; instead, a new instance must be constructed.

    public void release()
    {
         = 0;
         = 0;
        if ( != null) {
            .clear();
        }
         = null;
    }
    /*
    /**********************************************************************
    /* OutputStream implementation
    /**********************************************************************
     */
    @Override
    public final void write(byte[] b) {
        write(b, 0, b.length);
    }
    @Override
    public final 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() {
        /* Does nothing: should not call 'release' or 'resetForReuse', since content will
         * most likely be needed...
         */
    }
    @Override public void flush() { /* NOP */ }
    
    /*
    /**********************************************************************
    /* Access to contents
    /**********************************************************************
     */
    
    
Method called when results are finalized and we can get the full aggregated result buffer to return to the caller. Equivalent to:
   toByteArray(true, null);
 that is, this also implicitly calls release() so that no
 content is available for further calls; and no prefix will be
 prepended.
 
    public byte[] toByteArray()
    {
        return toByteArray(truenull);
    }
    
    
Method called when results are finalized and we can get the full aggregated result buffer to return to the caller.

Parameters:
release Whether contents should be release() after the call or not
    public byte[] toByteArray(boolean release)
    {
        return toByteArray(releasenull);
    }

    

Parameters:
release Whether contents should be release() after the call or not
prefix Optional prefix to prepend before actual contents
    public byte[] toByteArray(boolean releasebyte[] prefix)
    {
        int totalLen =  + ;
        if (prefix != null) {
            totalLen += prefix.length;
        }
        if (totalLen == 0) { // quick check: nothing aggregated?
            return ;
        }
        byte[] result = new byte[totalLen];
        int offset = 0;
        if (prefix != null) {
            final int len = prefix.length;
            if (len > 0) {
                System.arraycopy(prefix, 0, resultoffsetlen);
                offset += len;
            }
        }
        
        if ( != null && !.isEmpty()) {
            for (byte[] block : ) {
                final int len = block.length;
                System.arraycopy(block, 0, resultoffsetlen);
                offset += len;
            }
        }
        System.arraycopy(, 0, resultoffset);
        offset += ;
        if (release) {
            release();
        }
        if (offset != totalLen) { // just a sanity check
            throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes");
        }
        return result;
    }
    /*
    /**********************************************************************
    /* Traversal/consumption methods
    /**********************************************************************
     */

    
Method for writing contents of this aggregator into provided java.io.OutputStream
    public void writeTo(OutputStream outthrows IOException
    {
        if ( != null && !.isEmpty()) {
            for (byte[] block : ) {
                out.write(block, 0, block.length);
            }
        }
        final int len = ;
        if (len > 0) {
            out.write(, 0, len);
        }
    }

    
Method that can be used to access contents aggregated, by getting aggregator to call WithBytesCallback.withBytes(byte[],int,int) once per each segment with data.
    public <T> T withBytes(WithBytesCallback<T> callback)
    {
        T result = null;
        if ( != null && !.isEmpty()) {
            for (byte[] block : ) {
                result = callback.withBytes(block, 0, block.length);
            }
        }
        final int len = ;
        if (len > 0) {
            result = callback.withBytes(, 0, len);
        }
        return result;
    }
    
    
Method for calculating java.util.zip.Checksum over contents of this aggregator.
    {
        if ( != null && !.isEmpty()) {
            for (byte[] block : ) {
                cs.update(block, 0, block.length);
            }
        }
        final int len = ;
        if (len > 0) {
            cs.update(, 0, len);
        }
        return this;
    }
    
    /*
    /**********************************************************************
    /* 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