PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/collections-3.2.1/src/java/org/apache/commons/collections/buffer/BoundedFifoBuffer.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 388 lines | 184 code | 48 blank | 156 comment | 40 complexity | 70643038300f42e4bd6b817f8192635b MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.commons.collections.buffer;
  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.Serializable;
  22. import java.util.AbstractCollection;
  23. import java.util.Arrays;
  24. import java.util.Collection;
  25. import java.util.Iterator;
  26. import java.util.NoSuchElementException;
  27. import org.apache.commons.collections.BoundedCollection;
  28. import org.apache.commons.collections.Buffer;
  29. import org.apache.commons.collections.BufferOverflowException;
  30. import org.apache.commons.collections.BufferUnderflowException;
  31. /**
  32. * The BoundedFifoBuffer is a very efficient implementation of
  33. * <code>Buffer</code> that is of a fixed size.
  34. * <p>
  35. * The removal order of a <code>BoundedFifoBuffer</code> is based on the
  36. * insertion order; elements are removed in the same order in which they
  37. * were added. The iteration order is the same as the removal order.
  38. * <p>
  39. * The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
  40. * all perform in constant time. All other operations perform in linear
  41. * time or worse.
  42. * <p>
  43. * Note that this implementation is not synchronized. The following can be
  44. * used to provide synchronized access to your <code>BoundedFifoBuffer</code>:
  45. * <pre>
  46. * Buffer fifo = BufferUtils.synchronizedBuffer(new BoundedFifoBuffer());
  47. * </pre>
  48. * <p>
  49. * This buffer prevents null objects from being added.
  50. * <p>
  51. * This class is Serializable from Commons Collections 3.1.
  52. *
  53. * @since Commons Collections 3.0 (previously in main package v2.1)
  54. * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
  55. *
  56. * @author Avalon
  57. * @author Berin Loritsch
  58. * @author Paul Jack
  59. * @author Stephen Colebourne
  60. * @author Herve Quiroz
  61. */
  62. public class BoundedFifoBuffer extends AbstractCollection
  63. implements Buffer, BoundedCollection, Serializable {
  64. /** Serialization version */
  65. private static final long serialVersionUID = 5603722811189451017L;
  66. /** Underlying storage array */
  67. private transient Object[] elements;
  68. /** Array index of first (oldest) buffer element */
  69. private transient int start = 0;
  70. /**
  71. * Index mod maxElements of the array position following the last buffer
  72. * element. Buffer elements start at elements[start] and "wrap around"
  73. * elements[maxElements-1], ending at elements[decrement(end)].
  74. * For example, elements = {c,a,b}, start=1, end=1 corresponds to
  75. * the buffer [a,b,c].
  76. */
  77. private transient int end = 0;
  78. /** Flag to indicate if the buffer is currently full. */
  79. private transient boolean full = false;
  80. /** Capacity of the buffer */
  81. private final int maxElements;
  82. /**
  83. * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
  84. * 32 elements.
  85. */
  86. public BoundedFifoBuffer() {
  87. this(32);
  88. }
  89. /**
  90. * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
  91. * the specified number of elements.
  92. *
  93. * @param size the maximum number of elements for this fifo
  94. * @throws IllegalArgumentException if the size is less than 1
  95. */
  96. public BoundedFifoBuffer(int size) {
  97. if (size <= 0) {
  98. throw new IllegalArgumentException("The size must be greater than 0");
  99. }
  100. elements = new Object[size];
  101. maxElements = elements.length;
  102. }
  103. /**
  104. * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold all
  105. * of the elements in the specified collection. That collection's
  106. * elements will also be added to the buffer.
  107. *
  108. * @param coll the collection whose elements to add, may not be null
  109. * @throws NullPointerException if the collection is null
  110. */
  111. public BoundedFifoBuffer(Collection coll) {
  112. this(coll.size());
  113. addAll(coll);
  114. }
  115. //-----------------------------------------------------------------------
  116. /**
  117. * Write the buffer out using a custom routine.
  118. *
  119. * @param out the output stream
  120. * @throws IOException
  121. */
  122. private void writeObject(ObjectOutputStream out) throws IOException {
  123. out.defaultWriteObject();
  124. out.writeInt(size());
  125. for (Iterator it = iterator(); it.hasNext();) {
  126. out.writeObject(it.next());
  127. }
  128. }
  129. /**
  130. * Read the buffer in using a custom routine.
  131. *
  132. * @param in the input stream
  133. * @throws IOException
  134. * @throws ClassNotFoundException
  135. */
  136. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  137. in.defaultReadObject();
  138. elements = new Object[maxElements];
  139. int size = in.readInt();
  140. for (int i = 0; i < size; i++) {
  141. elements[i] = in.readObject();
  142. }
  143. start = 0;
  144. full = (size == maxElements);
  145. if (full) {
  146. end = 0;
  147. } else {
  148. end = size;
  149. }
  150. }
  151. //-----------------------------------------------------------------------
  152. /**
  153. * Returns the number of elements stored in the buffer.
  154. *
  155. * @return this buffer's size
  156. */
  157. public int size() {
  158. int size = 0;
  159. if (end < start) {
  160. size = maxElements - start + end;
  161. } else if (end == start) {
  162. size = (full ? maxElements : 0);
  163. } else {
  164. size = end - start;
  165. }
  166. return size;
  167. }
  168. /**
  169. * Returns true if this buffer is empty; false otherwise.
  170. *
  171. * @return true if this buffer is empty
  172. */
  173. public boolean isEmpty() {
  174. return size() == 0;
  175. }
  176. /**
  177. * Returns true if this collection is full and no new elements can be added.
  178. *
  179. * @return <code>true</code> if the collection is full
  180. */
  181. public boolean isFull() {
  182. return size() == maxElements;
  183. }
  184. /**
  185. * Gets the maximum size of the collection (the bound).
  186. *
  187. * @return the maximum number of elements the collection can hold
  188. */
  189. public int maxSize() {
  190. return maxElements;
  191. }
  192. /**
  193. * Clears this buffer.
  194. */
  195. public void clear() {
  196. full = false;
  197. start = 0;
  198. end = 0;
  199. Arrays.fill(elements, null);
  200. }
  201. /**
  202. * Adds the given element to this buffer.
  203. *
  204. * @param element the element to add
  205. * @return true, always
  206. * @throws NullPointerException if the given element is null
  207. * @throws BufferOverflowException if this buffer is full
  208. */
  209. public boolean add(Object element) {
  210. if (null == element) {
  211. throw new NullPointerException("Attempted to add null object to buffer");
  212. }
  213. if (full) {
  214. throw new BufferOverflowException("The buffer cannot hold more than " + maxElements + " objects.");
  215. }
  216. elements[end++] = element;
  217. if (end >= maxElements) {
  218. end = 0;
  219. }
  220. if (end == start) {
  221. full = true;
  222. }
  223. return true;
  224. }
  225. /**
  226. * Returns the least recently inserted element in this buffer.
  227. *
  228. * @return the least recently inserted element
  229. * @throws BufferUnderflowException if the buffer is empty
  230. */
  231. public Object get() {
  232. if (isEmpty()) {
  233. throw new BufferUnderflowException("The buffer is already empty");
  234. }
  235. return elements[start];
  236. }
  237. /**
  238. * Removes the least recently inserted element from this buffer.
  239. *
  240. * @return the least recently inserted element
  241. * @throws BufferUnderflowException if the buffer is empty
  242. */
  243. public Object remove() {
  244. if (isEmpty()) {
  245. throw new BufferUnderflowException("The buffer is already empty");
  246. }
  247. Object element = elements[start];
  248. if (null != element) {
  249. elements[start++] = null;
  250. if (start >= maxElements) {
  251. start = 0;
  252. }
  253. full = false;
  254. }
  255. return element;
  256. }
  257. /**
  258. * Increments the internal index.
  259. *
  260. * @param index the index to increment
  261. * @return the updated index
  262. */
  263. private int increment(int index) {
  264. index++;
  265. if (index >= maxElements) {
  266. index = 0;
  267. }
  268. return index;
  269. }
  270. /**
  271. * Decrements the internal index.
  272. *
  273. * @param index the index to decrement
  274. * @return the updated index
  275. */
  276. private int decrement(int index) {
  277. index--;
  278. if (index < 0) {
  279. index = maxElements - 1;
  280. }
  281. return index;
  282. }
  283. /**
  284. * Returns an iterator over this buffer's elements.
  285. *
  286. * @return an iterator over this buffer's elements
  287. */
  288. public Iterator iterator() {
  289. return new Iterator() {
  290. private int index = start;
  291. private int lastReturnedIndex = -1;
  292. private boolean isFirst = full;
  293. public boolean hasNext() {
  294. return isFirst || (index != end);
  295. }
  296. public Object next() {
  297. if (!hasNext()) {
  298. throw new NoSuchElementException();
  299. }
  300. isFirst = false;
  301. lastReturnedIndex = index;
  302. index = increment(index);
  303. return elements[lastReturnedIndex];
  304. }
  305. public void remove() {
  306. if (lastReturnedIndex == -1) {
  307. throw new IllegalStateException();
  308. }
  309. // First element can be removed quickly
  310. if (lastReturnedIndex == start) {
  311. BoundedFifoBuffer.this.remove();
  312. lastReturnedIndex = -1;
  313. return;
  314. }
  315. int pos = lastReturnedIndex + 1;
  316. if (start < lastReturnedIndex && pos < end) {
  317. // shift in one part
  318. System.arraycopy(elements, pos, elements,
  319. lastReturnedIndex, end - pos);
  320. } else {
  321. // Other elements require us to shift the subsequent elements
  322. while (pos != end) {
  323. if (pos >= maxElements) {
  324. elements[pos - 1] = elements[0];
  325. pos = 0;
  326. } else {
  327. elements[decrement(pos)] = elements[pos];
  328. pos = increment(pos);
  329. }
  330. }
  331. }
  332. lastReturnedIndex = -1;
  333. end = decrement(end);
  334. elements[end] = null;
  335. full = false;
  336. index = decrement(index);
  337. }
  338. };
  339. }
  340. }