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  }