1 /**
2 * Logback: the reliable, generic, fast and flexible logging framework.
3 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4 *
5 * This program and the accompanying materials are dual-licensed under
6 * either the terms of the Eclipse Public License v1.0 as published by
7 * the Eclipse Foundation
8 *
9 * or (per the licensee's choosing)
10 *
11 * under the terms of the GNU Lesser General Public License version 2.1
12 * as published by the Free Software Foundation.
13 */
14 package ch.qos.logback.core.helpers;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 /**
20 * CyclicBuffer holds values in a cyclic array.
21 *
22 * <p>
23 * It allows read access to any element in the buffer not just the first or last
24 * element.
25 *
26 * @author Ceki Gülcü
27 */
28 public class CyclicBuffer<E> {
29
30 E[] ea;
31 int first;
32 int last;
33 int numElems;
34 int maxSize;
35
36 /**
37 * Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
38 *
39 * The <code>maxSize</code> argument must a positive integer.
40 *
41 * @param maxSize The maximum number of elements in the buffer.
42 */
43 public CyclicBuffer(int maxSize) throws IllegalArgumentException {
44 if (maxSize < 1) {
45 throw new IllegalArgumentException("The maxSize argument (" + maxSize + ") is not a positive integer.");
46 }
47 init(maxSize);
48 }
49
50 @SuppressWarnings("unchecked")
51 public CyclicBuffer(CyclicBuffer<E> other) {
52 this.maxSize = other.maxSize;
53 ea = (E[]) new Object[maxSize];
54 System.arraycopy(other.ea, 0, this.ea, 0, maxSize);
55 this.last = other.last;
56 this.first = other.first;
57 this.numElems = other.numElems;
58 }
59
60 @SuppressWarnings("unchecked")
61 private void init(int maxSize) {
62 this.maxSize = maxSize;
63 ea = (E[]) new Object[maxSize];
64 first = 0;
65 last = 0;
66 numElems = 0;
67 }
68
69 /**
70 * Clears the buffer and resets all attributes.
71 */
72 public void clear() {
73 init(this.maxSize);
74 }
75
76 /**
77 * Add an <code>event</code> as the last event in the buffer.
78 *
79 */
80 public void add(E event) {
81 ea[last] = event;
82 if (++last == maxSize)
83 last = 0;
84
85 if (numElems < maxSize)
86 numElems++;
87 else if (++first == maxSize)
88 first = 0;
89 }
90
91 /**
92 * Get the <i>i</i>th oldest event currently in the buffer. If <em>i</em> is
93 * outside the range 0 to the number of elements currently in the buffer, then
94 * <code>null</code> is returned.
95 */
96 public E get(int i) {
97 if (i < 0 || i >= numElems)
98 return null;
99
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 }