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  package org.apache.logging.log4j.core.util;
18  
19  import java.lang.reflect.Array;
20  
21  /**
22   * A bounded buffer containing elements of type T. When the number of elements to be added will exceed the
23   * size of the buffer the oldest element will be overwritten. Access to the buffer is thread safe.
24   * @param <T> The type of object stored in the buffer.
25   */
26  public final class CyclicBuffer<T> {
27      private final T[] ring;
28      private int first = 0;
29      private int last = 0;
30      private int numElems = 0;
31      private final Class<T> clazz;
32  
33      /**
34       * Instantiates a new CyclicBuffer of at most <code>maxSize</code> events.
35       * @param clazz The Class associate with the type of object in the buffer.
36       * @param size The number of items in the buffer.
37       * @throws IllegalArgumentException if the size is negative.
38       */
39      public CyclicBuffer(final Class<T> clazz, final int size) throws IllegalArgumentException {
40          if (size < 0) {
41              throw new IllegalArgumentException("The maxSize argument (" + size + ") cannot be negative.");
42          }
43          this.ring = makeArray(clazz, size);
44          this.clazz = clazz;
45      }
46  
47      @SuppressWarnings("unchecked")
48      private T[] makeArray(final Class<T> cls, final int size) {
49          return (T[]) Array.newInstance(cls, size);
50      }
51  
52      /**
53       * Adds an item as the last event in the buffer.
54       * @param item The item to add to the buffer.
55       */
56      public synchronized void add(final T item) {
57          if (ring.length > 0) {
58              ring[last] = item;
59              if (++last == ring.length) {
60                  last = 0;
61              }
62  
63              if (numElems < ring.length) {
64                  numElems++;
65              } else if (++first == ring.length) {
66                  first = 0;
67              }
68          }
69      }
70  
71      /**
72       * Removes all the elements from the buffer and returns them.
73       * @return An array of the elements in the buffer.
74       */
75      public synchronized T[] removeAll() {
76          final T[] array = makeArray(clazz, numElems);
77          int index = 0;
78          while (numElems > 0) {
79              numElems--;
80              array[index++] = ring[first];
81              ring[first] = null;
82              if (++first == ring.length) {
83                  first = 0;
84              }
85          }
86          return array;
87      }
88  
89      /**
90       * Determines if the buffer contains elements.
91       * @return true if the buffer is empty, false otherwise.
92       */
93      public boolean isEmpty() {
94          return 0 == numElems;
95      }
96  }