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