001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.helpers; 015 016import java.util.ArrayList; 017import java.util.List; 018 019/** 020 * CyclicBuffer holds values in a cyclic array. 021 * 022 * <p> 023 * It allows read access to any element in the buffer not just the first or last 024 * element. 025 * 026 * @author Ceki Gülcü 027 */ 028public class CyclicBuffer<E> { 029 030 E[] ea; 031 int first; 032 int last; 033 int numElems; 034 int maxSize; 035 036 /** 037 * Instantiate a new CyclicBuffer of at most <code>maxSize</code> events. 038 * 039 * The <code>maxSize</code> argument must a positive integer. 040 * 041 * @param maxSize The maximum number of elements in the buffer. 042 */ 043 public CyclicBuffer(int maxSize) throws IllegalArgumentException { 044 if (maxSize < 1) { 045 throw new IllegalArgumentException("The maxSize argument (" + maxSize + ") is not a positive integer."); 046 } 047 init(maxSize); 048 } 049 050 @SuppressWarnings("unchecked") 051 public CyclicBuffer(CyclicBuffer<E> other) { 052 this.maxSize = other.maxSize; 053 ea = (E[]) new Object[maxSize]; 054 System.arraycopy(other.ea, 0, this.ea, 0, maxSize); 055 this.last = other.last; 056 this.first = other.first; 057 this.numElems = other.numElems; 058 } 059 060 @SuppressWarnings("unchecked") 061 private void init(int maxSize) { 062 this.maxSize = maxSize; 063 ea = (E[]) new Object[maxSize]; 064 first = 0; 065 last = 0; 066 numElems = 0; 067 } 068 069 /** 070 * Clears the buffer and resets all attributes. 071 */ 072 public void clear() { 073 init(this.maxSize); 074 } 075 076 /** 077 * Add an <code>event</code> as the last event in the buffer. 078 * 079 */ 080 public void add(E event) { 081 ea[last] = event; 082 if (++last == maxSize) 083 last = 0; 084 085 if (numElems < maxSize) 086 numElems++; 087 else if (++first == maxSize) 088 first = 0; 089 } 090 091 /** 092 * Get the <i>i</i>th oldest event currently in the buffer. If <em>i</em> is 093 * outside the range 0 to the number of elements currently in the buffer, then 094 * <code>null</code> is returned. 095 */ 096 public E get(int i) { 097 if (i < 0 || i >= numElems) 098 return null; 099 100 return ea[(first + i) % maxSize]; 101 } 102 103 public int getMaxSize() { 104 return maxSize; 105 } 106 107 /** 108 * Get the oldest (first) element in the buffer. The oldest element is removed 109 * from the buffer. 110 */ 111 public E get() { 112 E r = null; 113 if (numElems > 0) { 114 numElems--; 115 r = ea[first]; 116 ea[first] = null; 117 if (++first == maxSize) 118 first = 0; 119 } 120 return r; 121 } 122 123 public List<E> asList() { 124 List<E> tList = new ArrayList<E>(); 125 for (int i = 0; i < length(); i++) { 126 tList.add(get(i)); 127 } 128 return tList; 129 } 130 131 /** 132 * Get the number of elements in the buffer. This number is guaranteed to be in 133 * the range 0 to <code>maxSize</code> (inclusive). 134 */ 135 public int length() { 136 return numElems; 137 } 138 139 /** 140 * Resize the cyclic buffer to <code>newSize</code>. 141 * 142 * @throws IllegalArgumentException if <code>newSize</code> is negative. 143 */ 144 @SuppressWarnings("unchecked") 145 public void resize(int newSize) { 146 if (newSize < 0) { 147 throw new IllegalArgumentException("Negative array size [" + newSize + "] not allowed."); 148 } 149 if (newSize == numElems) 150 return; // nothing to do 151 152 // 153 E[] temp = (E[]) new Object[newSize]; 154 155 int loopLen = newSize < numElems ? newSize : numElems; 156 157 for (int i = 0; i < loopLen; i++) { 158 temp[i] = ea[first]; 159 ea[first] = null; 160 if (++first == numElems) 161 first = 0; 162 } 163 ea = temp; 164 first = 0; 165 numElems = loopLen; 166 maxSize = newSize; 167 if (loopLen == newSize) { 168 last = 0; 169 } else { 170 last = loopLen; 171 } 172 } 173}