Home | History | Annotate | Download | only in toolbox
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.volley.toolbox;
     18 
     19 import java.io.ByteArrayOutputStream;
     20 import java.io.IOException;
     21 
     22 /**
     23  * A variation of {@link java.io.ByteArrayOutputStream} that uses a pool of byte[] buffers instead
     24  * of always allocating them fresh, saving on heap churn.
     25  */
     26 public class PoolingByteArrayOutputStream extends ByteArrayOutputStream {
     27     /**
     28      * If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is
     29      * the default size to which the underlying byte array is initialized.
     30      */
     31     private static final int DEFAULT_SIZE = 256;
     32 
     33     private final ByteArrayPool mPool;
     34 
     35     /**
     36      * Constructs a new PoolingByteArrayOutputStream with a default size. If more bytes are written
     37      * to this instance, the underlying byte array will expand.
     38      */
     39     public PoolingByteArrayOutputStream(ByteArrayPool pool) {
     40         this(pool, DEFAULT_SIZE);
     41     }
     42 
     43     /**
     44      * Constructs a new {@code ByteArrayOutputStream} with a default size of {@code size} bytes. If
     45      * more than {@code size} bytes are written to this instance, the underlying byte array will
     46      * expand.
     47      *
     48      * @param size initial size for the underlying byte array. The value will be pinned to a default
     49      *        minimum size.
     50      */
     51     public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) {
     52         mPool = pool;
     53         buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE));
     54     }
     55 
     56     @Override
     57     public void close() throws IOException {
     58         mPool.returnBuf(buf);
     59         buf = null;
     60         super.close();
     61     }
     62 
     63     @Override
     64     public void finalize() {
     65         mPool.returnBuf(buf);
     66     }
     67 
     68     /**
     69      * Ensures there is enough space in the buffer for the given number of additional bytes.
     70      */
     71     private void expand(int i) {
     72         /* Can the buffer handle @i more bytes, if not expand it */
     73         if (count + i <= buf.length) {
     74             return;
     75         }
     76         byte[] newbuf = mPool.getBuf((count + i) * 2);
     77         System.arraycopy(buf, 0, newbuf, 0, count);
     78         mPool.returnBuf(buf);
     79         buf = newbuf;
     80     }
     81 
     82     @Override
     83     public synchronized void write(byte[] buffer, int offset, int len) {
     84         expand(len);
     85         super.write(buffer, offset, len);
     86     }
     87 
     88     @Override
     89     public synchronized void write(int oneByte) {
     90         expand(1);
     91         super.write(oneByte);
     92     }
     93 }
     94