1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.log4j.chainsaw;
19
20 import java.util.AbstractList;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24
25
26 /**
27 * CyclicBuffer implementation that is Object generic, and implements the List interface.
28 * <p>
29 * Original CyclicBuffer @author Ceki Gülcü
30 * <p>
31 * This implementation (although there's very little change) @author Paul Smith <psmith@apache.org>
32 */
33 public class CyclicBufferList extends AbstractList implements List {
34 Object[] ea;
35 int first;
36 int last;
37 int numElems;
38 int maxSize;
39
40 /**
41 * Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
42 * <p>
43 * The <code>maxSize</code> argument must a positive integer.
44 *
45 * @param maxSize The maximum number of elements in the buffer.
46 */
47 public CyclicBufferList(int maxSize) {
48 if (maxSize < 1) {
49 throw new IllegalArgumentException(
50 "The maxSize argument (" + maxSize + ") is not a positive integer.");
51 }
52 this.maxSize = maxSize;
53 clear();
54 }
55
56 public CyclicBufferList() {
57 this(5000);
58 }
59
60 /**
61 * Removes the element at the specified position in this list.
62 * Shifts any subsequent elements to the left (subtracts one from their
63 * indices).
64 *
65 * @param index the index of the element to removed.
66 * @return the element that was removed from the list.
67 * @throws IndexOutOfBoundsException if index out of range <tt>(index
68 * < 0 || index >= size())</tt>.
69 */
70 public Object remove(int index) {
71 Object oldValue = ea[index];
72
73 List list = new ArrayList(Arrays.asList(ea));
74 list.remove(index);
75 ea = list.toArray(ea);
76 numElems = ea.length;
77
78 numElems--;
79 if (--last <= 0) {
80 last = numElems;
81 }
82
83 if (first == maxSize) {
84 first = 0;
85 }
86 return oldValue;
87 }
88
89 public Object set(int index, Object element) {
90 Object previous = ea[index];
91 ea[index] = element;
92
93 return previous;
94 }
95
96 /**
97 * Add an <code>event</code> as the last event in the buffer.
98 */
99 public boolean add(Object event) {
100 ea[last] = event;
101
102 if (++last == maxSize) {
103 last = 0;
104 }
105
106 if (numElems < maxSize) {
107 numElems++;
108 } else if (++first == maxSize) {
109 first = 0;
110 }
111
112 return true;
113 }
114
115 /**
116 * Get the <i>i</i>th oldest event currently in the buffer. If
117 * <em>i</em> is outside the range 0 to the number of elements
118 * currently in the buffer, then <code>null</code> is returned.
119 */
120 public Object get(int i) {
121 if ((i < 0) || (i >= numElems)) {
122 return null;
123 }
124
125 return ea[(first + i) % maxSize];
126 }
127
128 public int getMaxSize() {
129 return maxSize;
130 }
131
132 public int getLast() {
133 return last;
134 }
135
136 /**
137 * Get the oldest (first) element in the buffer. The oldest element
138 * is removed from the buffer.
139 */
140 public Object get() {
141 Object r = null;
142
143 if (numElems > 0) {
144 numElems--;
145 r = ea[first];
146 ea[first] = null;
147
148 if (++first == maxSize) {
149 first = 0;
150 }
151 }
152
153 return r;
154 }
155
156 /**
157 * Get the number of elements in the buffer. This number is
158 * guaranteed to be in the range 0 to <code>maxSize</code>
159 * (inclusive).
160 */
161 public int size() {
162 return numElems;
163 }
164
165 /**
166 * Resize the cyclic buffer to <code>newSize</code>.
167 *
168 * @throws IllegalArgumentException if <code>newSize</code> is negative.
169 */
170 public void resize(int newSize) {
171 if (newSize < 0) {
172 throw new IllegalArgumentException(
173 "Negative array size [" + newSize + "] not allowed.");
174 }
175
176 if (newSize == numElems) {
177 return; // nothing to do
178 }
179
180 Object[] temp = new Object[newSize];
181
182 int loopLen = (newSize < numElems) ? newSize : numElems;
183
184 for (int i = 0; i < loopLen; i++) {
185 temp[i] = ea[first];
186 ea[first] = null;
187
188 if (++first == numElems) {
189 first = 0;
190 }
191 }
192
193 ea = temp;
194 first = 0;
195 numElems = loopLen;
196 maxSize = newSize;
197
198 if (loopLen == newSize) {
199 last = 0;
200 } else {
201 last = loopLen;
202 }
203 }
204
205 /* (non-Javadoc)
206 * @see java.util.Collection#clear()
207 */
208 public void clear() {
209 ea = new Object[maxSize];
210 first = 0;
211 last = 0;
212 numElems = 0;
213
214 }
215
216 }