001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.util; 018 019 import java.lang.reflect.Array; 020 021 /** 022 * A bounded buffer containing elements of type T. When the number of elements to be added will exceed the 023 * size of the buffer the oldest element will be overwritten. Access to the buffer is thread safe. 024 * @param <T> The type of object stored in the buffer. 025 */ 026 public final class CyclicBuffer<T> { 027 private final T[] ring; 028 private int first = 0; 029 private int last = 0; 030 private int numElems = 0; 031 private final Class<T> clazz; 032 033 /** 034 * Instantiate a new CyclicBuffer of at most <code>maxSize</code> events. 035 * @param clazz The Class associate with the type of object in the buffer. 036 * @param size The number of items in the buffer. 037 * @throws IllegalArgumentException if the size is negative. 038 */ 039 public CyclicBuffer(final Class<T> clazz, final int size) throws IllegalArgumentException { 040 if (size < 1) { 041 throw new IllegalArgumentException("The maxSize argument (" + size + ") is not a positive integer."); 042 } 043 this.ring = makeArray(clazz, size); 044 this.clazz = clazz; 045 } 046 047 @SuppressWarnings("unchecked") 048 private T[] makeArray(final Class<T> cls, final int size) { 049 return (T[]) Array.newInstance(cls, size); 050 } 051 052 /** 053 * Add an item as the last event in the buffer. 054 * @param item The item to add to the buffer. 055 */ 056 public synchronized void add(final T item) { 057 ring[last] = item; 058 if (++last == ring.length) { 059 last = 0; 060 } 061 062 if (numElems < ring.length) { 063 numElems++; 064 } else if (++first == ring.length) { 065 first = 0; 066 } 067 } 068 069 /** 070 * Removes all the elements from the buffer and returns them. 071 * @return An array of the elements in the buffer. 072 */ 073 public synchronized T[] removeAll() { 074 final T[] array = makeArray(clazz, numElems); 075 int index = 0; 076 while (numElems > 0) { 077 numElems--; 078 array[index++] = ring[first]; 079 ring[first] = null; 080 if (++first == ring.length) { 081 first = 0; 082 } 083 } 084 return array; 085 } 086 087 /** 088 * Determines if the buffer contains elements. 089 * @return true if the buffer is empty, false otherwise. 090 */ 091 public boolean isEmpty() { 092 return 0 == numElems; 093 } 094 }