gt:                     chunk = src.next();
context: /*
  
  Copyright (C) SYSTAP, LLC 2006-2015.  All rights reserved.
  
  Contact:
       SYSTAP, LLC
       2501 Calvert ST NW #106
       Washington, DC 20008
       licenses@systap.com
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
  */
  /*
   * Created on Jun 20, 2008
   */
  
  package com.bigdata.relation.accesspath;
  
  import java.util.Arrays;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  import java.util.Queue;
  import java.util.concurrent.LinkedBlockingQueue;
  
  import com.bigdata.striterator.EmptyChunkedIterator;
  import com.bigdata.striterator.IChunkedOrderedIterator;
  import com.bigdata.striterator.IKeyOrder;
  
  /**
   * An unsynchronized buffer backed by a fixed capacity array that migrates
   * references onto an internal {@link Queue}, which may be drained by an
   * {@link #iterator()}.
   * <p>
   * <strong>This implementation is NOT thread-safe.</strong>
   * 
   * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
   * @version $Id$
   * 
   * @see TestUnsynchronizedUnboundedChunkBuffer
   */
  public class UnsynchronizedUnboundedChunkBuffer<E> extends
          AbstractUnsynchronizedArrayBuffer<E> {
  
      /**
       * The queue onto which chunks are evicted by {@link #overflow()}.
       */
      private final Queue<E[]> queue;
      
      /**
       * The order of the elements as they are added to the buffer (iff known).
       */
      private final IKeyOrder<E> keyOrder;
      
      /**
       * From the first element visited.
       * 
       * TODO This is probably no longer required since the component type of the
       * class is now declared in the constructor.
       */
      private Class<E[]> chunkClass = null;
      
      /**
       * @param capacity
       *            The capacity of the backing buffer.
       * @param cls
       *            The component type of the backing array.
       */
      public UnsynchronizedUnboundedChunkBuffer(final int capacity,
              final Class<? extends E> cls) {
  
          this(capacity, cls, null/* filter */, null/* keyOrder */);
  
      }
  
      /**
       * @param capacity
       *            The capacity of the backing buffer.
       * @param cls
       *            The component type of the backing array.
       * @param filter
       *            Filter to keep elements out of the buffer (optional).
       * @param keyOrder
       *            The order of the elements in the chunks written onto the
       *            buffer or <code>null</code> iff not known.
       */
      public UnsynchronizedUnboundedChunkBuffer(final int capacity,
              final Class<? extends E> cls,
              final IElementFilter<E> filter, final IKeyOrder<E> keyOrder) {
  
          super(capacity, cls, filter);
  
          this.keyOrder = keyOrder;
  
          queue = new LinkedBlockingQueue<E[]>(/* unbounded capacity */);
  
      }
  
      /** Add the chunk to the target buffer. */
      final protected void handleChunk(final E[] chunk) {
  
          if (chunkClass == null) {
  
              // Note the Class of the chunk for the snapshot iterator.
              chunkClass = (Class<E[]>) chunk.getClass();
              
          }
          
          queue.add(chunk);
  
      }
  
      /**
       * Iterator drains chunks from a snapshot of the queue (shallow copy).
       * Chunks are drained in a FIFO basis. The internal buffer is flushed onto a
       * chunk on the queue before the snapshot is taken so that any buffered
       * elements will appear in the snapshot.
       */
      public IChunkedOrderedIterator<E> iterator() {
          
          overflow();
          
          /*
           * Snapshot the queue state and wrap as an iterator visiting chunks of
           * elements.
           */
          synchronized (queue) {
              
              if (queue.isEmpty()) {
  
                  // Note: handles case where chunkClass is not defined.
                  return new EmptyChunkedIterator<E>(keyOrder);
  
              }
  
              assert chunkClass != null;
              
              final Iterator<E[]> src = Arrays.asList(
                      (E[][]) queue.toArray((E[][]) java.lang.reflect.Array
                              .newInstance(chunkClass, 0/* size */))).iterator();
              
              // wrap with the IChunkedOrderedIterator API.
              return new ListOfChunksIterator<E>(src, keyOrder);
              
          }
          
      }
  
      /**
       * Drains chunks from a queue. Chunks are drained in a FIFO basis.
       * 
       * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
       * @version $Id$
       */
      static private class ListOfChunksIterator<E> implements
              IChunkedOrderedIterator<E> {
  
          private final Iterator<E[]> src;
  
          private final IKeyOrder<E> keyOrder;
  
          /**
           * 
           * @param src
           *            Iterator visiting dense chunks.
           * @param keyOrder
           *            The order of the elements in the buffer or
           *            <code>null</code> iff not known.
           */
          public ListOfChunksIterator(final Iterator<E[]> src,
                  final IKeyOrder<E> keyOrder) {
  
              this.src = src;
  
              this.keyOrder = keyOrder;
  
          }
  
          /** <code>true</code> iff open. */
          private boolean open = true;
          
          /** Index of the next element to visit in the current chunk. */
          private int i = 0;
  
          /**
           * The current chunk or null if another chunk should be read from the
           * queue.
           */
          private E[] chunk;
          
          public boolean hasNext() {
  
              if (!open)
                  return false;
  
              do {
  
                  if (chunk != null && i >= chunk.length) {
                      
                      // chunk is exhausted.
                      chunk = null;
                      
                      i = 0;
                      
                  }
                  
                  if (chunk == null) {
  
                      if(!src.hasNext()) {
                      
                          // nothing left.
                          return false;
                      
                      }
  
                      // another chunk.
  