View Javadoc
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   *
28   * CyclicBuffer implementation that is Object generic, and implements the List interface.
29   *
30   * Original CyclicBuffer @author Ceki Gülcü
31   *
32   * This implementation (although there's very little change) @author Paul Smith <psmith@apache.org>
33   *
34   */
35  public class CyclicBufferList extends AbstractList implements List {
36    Object[] ea;
37    int first;
38    int last;
39    int numElems;
40    int maxSize;
41  
42    /**
43       Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
44  
45       The <code>maxSize</code> argument must a positive integer.
46  
47       @param maxSize The maximum number of elements in the buffer.
48    */
49    public CyclicBufferList(int maxSize) {
50      if (maxSize < 1) {
51        throw new IllegalArgumentException(
52          "The maxSize argument (" + maxSize + ") is not a positive integer.");
53      }
54      this.maxSize = maxSize;
55      clear();
56    }
57  
58    public CyclicBufferList() {
59      this(5000);
60    }
61  
62    /**
63     * Removes the element at the specified position in this list.
64     * Shifts any subsequent elements to the left (subtracts one from their
65     * indices).
66     *
67     * @param index the index of the element to removed.
68     * @return the element that was removed from the list.
69     * @throws    IndexOutOfBoundsException if index out of range <tt>(index
70     *      &lt; 0 || index &gt;= size())</tt>.
71     */
72    public Object remove(int index) {
73      Object oldValue = ea[index];
74  
75      List list = new ArrayList(Arrays.asList(ea));
76      list.remove(index);
77      ea = list.toArray(ea);
78      numElems = ea.length;
79      
80      numElems--;
81      if (--last <= 0) {
82        last = numElems;
83      }
84  
85      if (first == maxSize) {
86        first = 0;
87      }
88      return oldValue;
89    }
90  
91    public Object set(int index, Object element) {
92      Object previous = ea[index];
93      ea[index] = element;
94  
95      return previous;
96    }
97  
98    /**
99       Add an <code>event</code> as the last event in the buffer.
100 
101    */
102   public boolean add(Object event) {
103     ea[last] = event;
104 
105     if (++last == maxSize) {
106       last = 0;
107     }
108 
109     if (numElems < maxSize) {
110       numElems++;
111     } else if (++first == maxSize) {
112       first = 0;
113     }
114 
115     return true;
116   }
117 
118   /**
119      Get the <i>i</i>th oldest event currently in the buffer. If
120      <em>i</em> is outside the range 0 to the number of elements
121      currently in the buffer, then <code>null</code> is returned.
122 
123 
124   */
125   public Object get(int i) {
126     if ((i < 0) || (i >= numElems)) {
127       return null;
128     }
129 
130     return ea[(first + i) % maxSize];
131   }
132 
133   public int getMaxSize() {
134     return maxSize;
135   }
136   
137   public int getLast() {
138       return last;
139   }
140 
141   /**
142      Get the oldest (first) element in the buffer. The oldest element
143      is removed from the buffer.
144   */
145   public Object get() {
146     Object r = null;
147 
148     if (numElems > 0) {
149       numElems--;
150       r = ea[first];
151       ea[first] = null;
152 
153       if (++first == maxSize) {
154         first = 0;
155       }
156     }
157 
158     return r;
159   }
160 
161   /**
162      Get the number of elements in the buffer. This number is
163      guaranteed to be in the range 0 to <code>maxSize</code>
164      (inclusive).
165   */
166   public int size() {
167     return numElems;
168   }
169 
170   /**
171      Resize the cyclic buffer to <code>newSize</code>.
172 
173      @throws IllegalArgumentException if <code>newSize</code> is negative.
174    */
175   public void resize(int newSize) {
176     if (newSize < 0) {
177       throw new IllegalArgumentException(
178         "Negative array size [" + newSize + "] not allowed.");
179     }
180 
181     if (newSize == numElems) {
182       return; // nothing to do
183     }
184 
185     Object[] temp = new Object[newSize];
186 
187     int loopLen = (newSize < numElems) ? newSize : numElems;
188 
189     for (int i = 0; i < loopLen; i++) {
190       temp[i] = ea[first];
191       ea[first] = null;
192 
193       if (++first == numElems) {
194         first = 0;
195       }
196     }
197 
198     ea = temp;
199     first = 0;
200     numElems = loopLen;
201     maxSize = newSize;
202 
203     if (loopLen == newSize) {
204       last = 0;
205     } else {
206       last = loopLen;
207     }
208   }
209   /* (non-Javadoc)
210    * @see java.util.Collection#clear()
211    */
212   public void clear() {
213     ea = new Object[maxSize];
214     first = 0;
215     last = 0;
216     numElems = 0;
217     
218   }
219 
220 }