Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* Jackson JSON-processor.
   *
   * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
   */
  
  package com.fasterxml.jackson.core.util;
  
  import java.util.*;

Helper class that is similar to java.io.ByteArrayOutputStream in usage, but more geared to Jackson use cases internally. Specific changes include segment storage (no need to have linear backing buffer, can avoid reallocs, copying), as well API not based on java.io.OutputStream. In short, a very much specialized builder object.

Since version 1.5, also implements java.io.OutputStream to allow efficient aggregation of output content as a byte array, similar to how java.io.ByteArrayOutputStream works, but somewhat more efficiently for many use cases.

 
 public final class ByteArrayBuilder
     extends OutputStream
 {
     private final static byte[] NO_BYTES = new byte[0];
    
    
Size of the first block we will allocate.
 
     private final static int INITIAL_BLOCK_SIZE = 500;
    
    
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);
     
     final static int DEFAULT_BLOCK_ARRAY_SIZE = 40;

    
Optional buffer recycler instance that we can use for allocating the first block.
 
     private final BufferRecycler _bufferRecycler;
     
     private final LinkedList<byte[]> _pastBlocks = new LinkedList<byte[]>();
    
    
Number of bytes within byte arrays in _pastBlocks.
 
     private int _pastLen;
 
     private byte[] _currBlock;
 
     private int _currBlockPtr;
     
     public ByteArrayBuilder() { this(null); }
 
     public ByteArrayBuilder(BufferRecycler br) { this(br); }
 
     public ByteArrayBuilder(int firstBlockSize) { this(nullfirstBlockSize); }
 
     public ByteArrayBuilder(BufferRecycler brint firstBlockSize)
     {
          = br;
         if (br == null) {
              = new byte[firstBlockSize];
         } else {
         }
     }
 
     public void reset()
     {
          = 0;
          = 0;
 
         if (!.isEmpty()) {
             .clear();
         }
     }

    
Clean up method to call to release all buffers this object may be using. After calling the method, no other accessors can be used (and attempt to do so may result in an exception)
 
     public void release() {
         reset();
         if ( != null &&  != null) {
              = null;
         }
     }
 
     public void append(int i)
     {
        if ( >= .) {
            _allocMore();
        }
        [++] = (bytei;
    }
    public void appendTwoBytes(int b16)
    {
        if (( + 1) < .) {
            [++] = (byte) (b16 >> 8);
            [++] = (byteb16;
        } else {
            append(b16 >> 8);
            append(b16);
        }
    }
    public void appendThreeBytes(int b24)
    {
        if (( + 2) < .) {
            [++] = (byte) (b24 >> 16);
            [++] = (byte) (b24 >> 8);
            [++] = (byteb24;
        } else {
            append(b24 >> 16);
            append(b24 >> 8);
            append(b24);
        }
    }

    
Method called when results are finalized and we can get the full aggregated result buffer to return to the caller
    public byte[] toByteArray()
    {
        int totalLen =  + ;
        
        if (totalLen == 0) { // quick check: nothing aggregated?
            return ;
        }
        
        byte[] result = new byte[totalLen];
        int offset = 0;
        for (byte[] block : ) {
            int len = block.length;
            System.arraycopy(block, 0, resultoffsetlen);
            offset += len;
        }
        System.arraycopy(, 0, resultoffset);
        offset += ;
        if (offset != totalLen) { // just a sanity check
            throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes");
        }
        // Let's only reset if there's sizable use, otherwise will get reset later on
        if (!.isEmpty()) {
            reset();
        }
        return result;
    }
    /*
    /**********************************************************
    /* Non-stream API (similar to TextBuffer), since 1.6
    /**********************************************************
     */

    
Method called when starting "manual" output: will clear out current state and return the first segment buffer to fill
    public byte[] resetAndGetFirstSegment() {
        reset();
        return ;
    }

    
Method called when the current segment buffer is full; will append to current contents, allocate a new segment buffer and return it
    public byte[] finishCurrentSegment() {
        _allocMore();
        return ;
    }

    
Method that will complete "manual" output process, coalesce content (if necessary) and return results as a contiguous buffer.

Parameters:
lastBlockLength Amount of content in the current segment buffer.
Returns:
Coalesced contents
    public byte[] completeAndCoalesce(int lastBlockLength)
    {
         = lastBlockLength;
        return toByteArray();
    }
    public byte[] getCurrentSegment() {
        return ;
    }
    public void setCurrentSegmentLength(int len) {
         = len;
    }
    public int getCurrentSegmentLength() {
        return ;
    }
    
    /*
    /**********************************************************
    /* 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) {
        append(b);
    }
    @Override public void close() { /* NOP */ }
    @Override public void flush() { /* NOP */ }
    /*
    /**********************************************************
    /* Internal methods
    /**********************************************************
     */
    
    private void _allocMore()
    {
         += .;
        /* Let's allocate block that's half the total size, except
         * never smaller than twice the initial block size.
         * The idea is just to grow with reasonable rate, to optimize
         * between minimal number of chunks and minimal amount of
         * wasted space.
         */
        int newSize = Math.max(( >> 1), ( + ));
        // plus not to exceed max we define...
        if (newSize > ) {
            newSize = ;
        }
        .add();
         = new byte[newSize];
         = 0;
    }
New to GrepCode? Check out our FAQ X