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>It allows read access to any element in the buffer not just the first or
23 * last element.
24 *
25 * @author Ceki Gülcü
26 */
27 public class CyclicBuffer<E> {
28
29 E[] ea;
30 int first;
31 int last;
32 int numElems;
33 int maxSize;
34
35 /**
36 * Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
37 *
38 * The <code>maxSize</code> argument must a positive integer.
39 *
40 * @param maxSize
41 * 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 public CyclicBuffer(CyclicBuffer<E> other) {
51 this.maxSize = other.maxSize;
52 ea = (E[]) new Object[maxSize];
53 System.arraycopy(other.ea, 0, this.ea, 0, maxSize);
54 this.last = other.last;
55 this.first = other.first;
56 this.numElems = other.numElems;
57 }
58
59 @SuppressWarnings("unchecked")
60 private void init(int maxSize) {
61 this.maxSize = maxSize;
62 ea = (E[]) new Object[maxSize];
63 first = 0;
64 last = 0;
65 numElems = 0;
66 }
67
68 /**
69 * Clears the buffer and resets all attributes.
70 */
71 public void clear() {
72 init(this.maxSize);
73 }
74
75 /**
76 * Add an <code>event</code> as the last event in the buffer.
77 *
78 */
79 public void add(E event) {
80 ea[last] = event;
81 if (++last == maxSize)
82 last = 0;
83
84 if (numElems < maxSize)
85 numElems++;
86 else if (++first == maxSize)
87 first = 0;
88 }
89
90 /**
91 * Get the <i>i</i>th oldest event currently in the buffer. If <em>i</em>
92 * is outside the range 0 to the number of elements currently in the buffer,
93 * then <code>null</code> is returned.
94 */
95 public E get(int i) {
96 if (i < 0 || i >= numElems)
97 return null;
98
99 return ea[(first + i) % maxSize];
100 }
101
102 public int getMaxSize() {
103 return maxSize;
104 }
105
106 /**
107 * Get the oldest (first) element in the buffer. The oldest element is removed
108 * from the buffer.
109 */
110 public E get() {
111 E r = null;
112 if (numElems > 0) {
113 numElems--;
114 r = ea[first];
115 ea[first] = null;
116 if (++first == maxSize)
117 first = 0;
118 }
119 return r;
120 }
121
122 public List<E> asList() {
123 List<E> tList = new ArrayList<E>();
124 for (int i = 0; i < length(); i++) {
125 tList.add(get(i));
126 }
127 return tList;
128 }
129
130 /**
131 * Get the number of elements in the buffer. This number is guaranteed to be
132 * in the range 0 to <code>maxSize</code> (inclusive).
133 */
134 public int length() {
135 return numElems;
136 }
137
138 /**
139 * Resize the cyclic buffer to <code>newSize</code>.
140 *
141 * @throws IllegalArgumentException
142 * 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 }
174