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       * Instantiate 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 < 1) {
41              throw new IllegalArgumentException("The maxSize argument (" + size + ") is not a positive integer.");
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       * Add 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          ring[last] = item;
58          if (++last == ring.length) {
59              last = 0;
60          }
61  
62          if (numElems < ring.length) {
63              numElems++;
64          } else if (++first == ring.length) {
65              first = 0;
66          }
67      }
68  
69      /**
70       * Removes all the elements from the buffer and returns them.
71       * @return An array of the elements in the buffer.
72       */
73      public synchronized T[] removeAll() {
74          final T[] array = makeArray(clazz, numElems);
75          int index = 0;
76          while (numElems > 0) {
77              numElems--;
78              array[index++] = ring[first];
79              ring[first] = null;
80              if (++first == ring.length) {
81                  first = 0;
82              }
83          }
84          return array;
85      }
86  
87      /**
88       * Determines if the buffer contains elements.
89       * @return true if the buffer is empty, false otherwise.
90       */
91      public boolean isEmpty() {
92          return 0 == numElems;
93      }
94  }