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 */ 017package org.apache.logging.log4j.core.util; 018 019import 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 */ 026public 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 * Instantiates 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 < 0) { 041 throw new IllegalArgumentException("The maxSize argument (" + size + ") cannot be negative."); 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 * Adds 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 if (ring.length > 0) { 058 ring[last] = item; 059 if (++last == ring.length) { 060 last = 0; 061 } 062 063 if (numElems < ring.length) { 064 numElems++; 065 } else if (++first == ring.length) { 066 first = 0; 067 } 068 } 069 } 070 071 /** 072 * Removes all the elements from the buffer and returns them. 073 * @return An array of the elements in the buffer. 074 */ 075 public synchronized T[] removeAll() { 076 final T[] array = makeArray(clazz, numElems); 077 int index = 0; 078 while (numElems > 0) { 079 numElems--; 080 array[index++] = ring[first]; 081 ring[first] = null; 082 if (++first == ring.length) { 083 first = 0; 084 } 085 } 086 return array; 087 } 088 089 /** 090 * Determines if the buffer contains elements. 091 * @return true if the buffer is empty, false otherwise. 092 */ 093 public boolean isEmpty() { 094 return 0 == numElems; 095 } 096}