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