1 /*
2  * Copyright (C) 2016 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.server.wifi.util;
18 
19 import java.util.ArrayList;
20 
21 /**
22  * A ring buffer where each element of the ring is itself a byte array.
23  */
24 public class ByteArrayRingBuffer {
25     private ArrayList<byte[]> mArrayList;
26     private int mMaxBytes;
27     private int mBytesUsed;
28 
29     /**
30      * Creates a ring buffer that holds at most |maxBytes| of data. The overhead for each element
31      * is not included in this limit.
32      * @param maxBytes upper bound on the amount of data to hold
33      */
ByteArrayRingBuffer(int maxBytes)34     public ByteArrayRingBuffer(int maxBytes) {
35         if (maxBytes < 1) {
36             throw new IllegalArgumentException();
37         }
38         mArrayList = new ArrayList<byte[]>();
39         mMaxBytes = maxBytes;
40         mBytesUsed = 0;
41     }
42 
43     /**
44      * Adds |newData| to the ring buffer. Removes existing entries to make room, if necessary.
45      * Existing entries are removed in FIFO order.
46      * <p><b>Note:</b> will fail if |newData| itself exceeds the size limit for this buffer.
47      * Will first remove all existing entries in this case. (This guarantees that the ring buffer
48      * always represents a contiguous sequence of data.)
49      * @param newData data to be added to the ring
50      * @return true if the data was added
51      */
appendBuffer(byte[] newData)52     public boolean appendBuffer(byte[] newData) {
53         pruneToSize(mMaxBytes - newData.length);
54         if (mBytesUsed + newData.length > mMaxBytes) {
55             return false;
56         }
57 
58         mArrayList.add(newData);
59         mBytesUsed += newData.length;
60         return true;
61     }
62 
63     /**
64      * Returns the |i|-th element of the ring. The element retains its position in the ring.
65      * @param i
66      * @return the requested element
67      */
getBuffer(int i)68     public byte[] getBuffer(int i) {
69         return mArrayList.get(i);
70     }
71 
72     /**
73      * Returns the number of elements present in the ring.
74      * @return the number of elements present
75      */
getNumBuffers()76     public int getNumBuffers() {
77         return mArrayList.size();
78     }
79 
80     /**
81      * Resize the buffer, removing existing data if necessary.
82      * @param maxBytes upper bound on the amount of data to hold
83      */
resize(int maxBytes)84     public void resize(int maxBytes) {
85         pruneToSize(maxBytes);
86         mMaxBytes = maxBytes;
87     }
88 
pruneToSize(int sizeBytes)89     private void pruneToSize(int sizeBytes) {
90         int newBytesUsed = mBytesUsed;
91         int i = 0;
92         while (i < mArrayList.size() && newBytesUsed > sizeBytes) {
93             newBytesUsed -= mArrayList.get(i).length;
94             i++;
95         }
96         mArrayList.subList(0, i).clear();
97         mBytesUsed = newBytesUsed;
98     }
99 }
100