View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.util;
15  
16  import java.util.AbstractList;
17  import java.util.NoSuchElementException;
18  import java.util.Queue;
19  
20  /* ------------------------------------------------------------ */
21  /**
22   * Queue backed by circular array.
23   * <p/>
24   * This partial Queue implementation (also with {@link #remove()} for stack operation)
25   * is backed by a growable circular array.
26   *
27   * @param <E>
28   */
29  public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
30  {
31      public static final int DEFAULT_CAPACITY = 64;
32      public static final int DEFAULT_GROWTH = 32;
33  
34      protected final Object _lock;
35      protected final int _growCapacity;
36      protected Object[] _elements;
37      protected int _nextE;
38      protected int _nextSlot;
39      protected int _size;
40  
41      /* ------------------------------------------------------------ */
42      public ArrayQueue()
43      {
44          this(DEFAULT_CAPACITY, -1);
45      }
46  
47      /* ------------------------------------------------------------ */
48      public ArrayQueue(int capacity)
49      {
50          this(capacity, -1);
51      }
52  
53      /* ------------------------------------------------------------ */
54      public ArrayQueue(int initCapacity, int growBy)
55      {
56          this(initCapacity, growBy, null);
57      }
58  
59      /* ------------------------------------------------------------ */
60      public ArrayQueue(int initCapacity, int growBy, Object lock)
61      {
62          _lock = lock == null ? this : lock;
63          _growCapacity = growBy;
64          _elements = new Object[initCapacity];
65      }
66  
67      /* ------------------------------------------------------------ */
68      public int getCapacity()
69      {
70          synchronized (_lock)
71          {
72              return _elements.length;
73          }
74      }
75  
76      /* ------------------------------------------------------------ */
77      @Override
78      public boolean add(E e)
79      {
80          if (!offer(e))
81              throw new IllegalStateException("Full");
82          return true;
83      }
84  
85      /* ------------------------------------------------------------ */
86      public boolean offer(E e)
87      {
88          synchronized (_lock)
89          {
90              return enqueue(e);
91          }
92      }
93  
94      /* ------------------------------------------------------------ */
95      private boolean enqueue(E e)
96      {
97          if (_size == _elements.length && !grow())
98              return false;
99  
100         _size++;
101         _elements[_nextSlot++] = e;
102         if (_nextSlot == _elements.length)
103             _nextSlot = 0;
104 
105         return true;
106     }
107 
108     /* ------------------------------------------------------------ */
109     /**
110      * Add without synchronization or bounds checking
111      *
112      * @param e the element to add
113      * @see #add(Object)
114      */
115     public void addUnsafe(E e)
116     {
117         if (!enqueue(e))
118             throw new IllegalStateException("Full");
119     }
120 
121     /* ------------------------------------------------------------ */
122     public E element()
123     {
124         synchronized (_lock)
125         {
126             if (isEmpty())
127                 throw new NoSuchElementException();
128             return at(_nextE);
129         }
130     }
131 
132     @SuppressWarnings("unchecked")
133     private E at(int index)
134     {
135         return (E)_elements[index];
136     }
137 
138     /* ------------------------------------------------------------ */
139     public E peek()
140     {
141         synchronized (_lock)
142         {
143             if (isEmpty())
144                 return null;
145             return at(_nextE);
146         }
147     }
148 
149     /* ------------------------------------------------------------ */
150     public E poll()
151     {
152         synchronized (_lock)
153         {
154             if (_size == 0)
155                 return null;
156             return dequeue();
157         }
158     }
159 
160     /* ------------------------------------------------------------ */
161     private E dequeue()
162     {
163         E e = at(_nextE);
164         _elements[_nextE] = null;
165         _size--;
166         if (++_nextE == _elements.length)
167             _nextE = 0;
168         return e;
169     }
170 
171     /* ------------------------------------------------------------ */
172     public E remove()
173     {
174         synchronized (_lock)
175         {
176             if (_size == 0)
177                 throw new NoSuchElementException();
178             return dequeue();
179         }
180     }
181 
182     /* ------------------------------------------------------------ */
183     @Override
184     public void clear()
185     {
186         synchronized (_lock)
187         {
188             _size = 0;
189             _nextE = 0;
190             _nextSlot = 0;
191         }
192     }
193 
194     /* ------------------------------------------------------------ */
195     @Override
196     public boolean isEmpty()
197     {
198         synchronized (_lock)
199         {
200             return _size == 0;
201         }
202     }
203 
204     /* ------------------------------------------------------------ */
205     @Override
206     public int size()
207     {
208         synchronized (_lock)
209         {
210             return _size;
211         }
212     }
213 
214     /* ------------------------------------------------------------ */
215     @Override
216     public E get(int index)
217     {
218         synchronized (_lock)
219         {
220             if (index < 0 || index >= _size)
221                 throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
222             return getUnsafe(index);
223         }
224     }
225 
226     /* ------------------------------------------------------------ */
227     /**
228      * Get without synchronization or bounds checking.
229      *
230      * @param  index index of the element to return
231      * @return the element at the specified index
232      * @see #get(int)
233      */
234     public E getUnsafe(int index)
235     {
236         int i = (_nextE + index) % _elements.length;
237         return at(i);
238     }
239 
240     /* ------------------------------------------------------------ */
241     @Override
242     public E remove(int index)
243     {
244         synchronized (_lock)
245         {
246             if (index < 0 || index >= _size)
247                 throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
248 
249             int i = (_nextE + index) % _elements.length;
250             E old = at(i);
251 
252             if (i < _nextSlot)
253             {
254                 // 0                         _elements.length
255                 //       _nextE........._nextSlot
256                 System.arraycopy(_elements, i + 1, _elements, i, _nextSlot - i);
257                 _nextSlot--;
258                 _size--;
259             }
260             else
261             {
262                 // 0                         _elements.length
263                 // ......_nextSlot   _nextE..........
264                 System.arraycopy(_elements, i + 1, _elements, i, _elements.length - i - 1);
265                 if (_nextSlot > 0)
266                 {
267                     _elements[_elements.length - 1] = _elements[0];
268                     System.arraycopy(_elements, 1, _elements, 0, _nextSlot - 1);
269                     _nextSlot--;
270                 }
271                 else
272                     _nextSlot = _elements.length - 1;
273 
274                 _size--;
275             }
276 
277             return old;
278         }
279     }
280 
281     /* ------------------------------------------------------------ */
282     @Override
283     public E set(int index, E element)
284     {
285         synchronized (_lock)
286         {
287             if (index < 0 || index >= _size)
288                 throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
289 
290             int i = _nextE + index;
291             if (i >= _elements.length)
292                 i -= _elements.length;
293             E old = at(i);
294             _elements[i] = element;
295             return old;
296         }
297     }
298 
299     /* ------------------------------------------------------------ */
300     @Override
301     public void add(int index, E element)
302     {
303         synchronized (_lock)
304         {
305             if (index < 0 || index > _size)
306                 throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
307 
308             if (_size == _elements.length && !grow())
309                 throw new IllegalStateException("Full");
310 
311             if (index == _size)
312             {
313                 add(element);
314             }
315             else
316             {
317                 int i = _nextE + index;
318                 if (i >= _elements.length)
319                     i -= _elements.length;
320 
321                 _size++;
322                 _nextSlot++;
323                 if (_nextSlot == _elements.length)
324                     _nextSlot = 0;
325 
326                 if (i < _nextSlot)
327                 {
328                     // 0                         _elements.length
329                     //       _nextE.....i..._nextSlot
330                     // 0                         _elements.length
331                     // ..i..._nextSlot   _nextE..........
332                     System.arraycopy(_elements, i, _elements, i + 1, _nextSlot - i);
333                     _elements[i] = element;
334                 }
335                 else
336                 {
337                     // 0                         _elements.length
338                     // ......_nextSlot   _nextE.....i....
339                     if (_nextSlot > 0)
340                     {
341                         System.arraycopy(_elements, 0, _elements, 1, _nextSlot);
342                         _elements[0] = _elements[_elements.length - 1];
343                     }
344 
345                     System.arraycopy(_elements, i, _elements, i + 1, _elements.length - i - 1);
346                     _elements[i] = element;
347                 }
348             }
349         }
350     }
351 
352     /* ------------------------------------------------------------ */
353     protected boolean grow()
354     {
355         synchronized (_lock)
356         {
357             if (_growCapacity <= 0)
358                 return false;
359 
360             Object[] elements = new Object[_elements.length + _growCapacity];
361 
362             int split = _elements.length - _nextE;
363             if (split > 0)
364                 System.arraycopy(_elements, _nextE, elements, 0, split);
365             if (_nextE != 0)
366                 System.arraycopy(_elements, 0, elements, split, _nextSlot);
367 
368             _elements = elements;
369             _nextE = 0;
370             _nextSlot = _size;
371             return true;
372         }
373     }
374 }