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.util.ArrayList;
20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Collections;
21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Comparator;
22d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.LinkedList;
23d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.List;
24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/**
26d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to
27d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * supply those buffers to consumers who need to use them for a short period of time and then
28d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * dispose of them. Simply creating and disposing such buffers in the conventional manner can
29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * considerable heap churn and garbage collection delays on Android, which lacks good management of
30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * short-lived heap objects. It may be advantageous to trade off some memory in the form of a
31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * permanently allocated pool of buffers in order to gain heap performance improvements; that is
32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * what this class does.
33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>
34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A good candidate user for this class is something like an I/O system that uses large temporary
35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants
36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks
37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into
38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * account and also to maximize the odds of being able to reuse a recycled buffer, this class is
39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * free to return buffers larger than the requested size. The caller needs to be able to gracefully
40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * deal with getting buffers any size over the minimum.
41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>
42d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this
43d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * class will allocate a new buffer and return it.
44d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>
45d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * This class has no special ownership of buffers it creates; the caller is free to take a buffer
46d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * it receives from this pool, use it permanently, and never return it to the pool; additionally,
47d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there
48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * are no other lingering references to it.
49d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>
50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * This class ensures that the total size of the buffers in its recycling pool never exceeds a
51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit,
52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * least-recently-used buffers are disposed.
53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */
54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class ByteArrayPool {
55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The buffer pool, arranged both by last use and by buffer size */
56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();
57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);
58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The total size of the buffers in the pool */
60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private int mCurrentSize = 0;
61d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
62d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * under this limit.
65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private final int mSizeLimit;
67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** Compares buffers by size */
69d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {
70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        @Override
71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        public int compare(byte[] lhs, byte[] rhs) {
72d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            return lhs.length - rhs.length;
73d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    };
75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
76d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
77d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param sizeLimit the maximum size of the pool, in bytes
78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public ByteArrayPool(int sizeLimit) {
80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mSizeLimit = sizeLimit;
81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
82d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Returns a buffer from the pool if one is available in the requested size, or allocates a new
85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * one if a pooled one is not available.
86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be
88d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *        larger.
89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @return a byte[] buffer is always returned.
90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
91d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public synchronized byte[] getBuf(int len) {
92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        for (int i = 0; i < mBuffersBySize.size(); i++) {
93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            byte[] buf = mBuffersBySize.get(i);
94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            if (buf.length >= len) {
95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mCurrentSize -= buf.length;
96d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mBuffersBySize.remove(i);
97d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mBuffersByLastUse.remove(buf);
98d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                return buf;
99d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
101d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        return new byte[len];
102d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
103d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
104d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
105d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
106d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * size.
107d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
108d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param buf the buffer to return to the pool.
109d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
110d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public synchronized void returnBuf(byte[] buf) {
111d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (buf == null || buf.length > mSizeLimit) {
112d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            return;
113d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
114d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mBuffersByLastUse.add(buf);
115d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
116d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (pos < 0) {
117d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            pos = -pos - 1;
118d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mBuffersBySize.add(pos, buf);
120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mCurrentSize += buf.length;
121d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        trim();
122d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
123d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
124d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
125d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Removes buffers from the pool until it is under its size limit.
126d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
127d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private synchronized void trim() {
128d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        while (mCurrentSize > mSizeLimit) {
129d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            byte[] buf = mBuffersByLastUse.remove(0);
130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mBuffersBySize.remove(buf);
131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mCurrentSize -= buf.length;
132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
134d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru}
136