@Override
    public int drain(Consumer<E> c, int limit)
    {
        if (null == c)
            throw new IllegalArgumentException("c is null");
        if (limit < 0)
            throw new IllegalArgumentException("limit is negative: " + limit);
        if (limit == 0)
            return 0;

        final int chunkMask = this.chunkMask;

        long cIndex = this.lpConsumerIndex();

        MpscUnboundedXaddChunk<E> cChunk = this.lpConsumerChunk();

        for (int i = 0; i < limit; i++)
        {
            final int consumerOffset = (int) (cIndex & chunkMask);
            E e;
            if (consumerOffset == 0 && cIndex != 0)
            {
                final MpscUnboundedXaddChunk<E> next = cChunk.lvNext();
                if (next == null)
                {
                    return i;
                }
                e = next.lvElement(0);

                // if the next chunk doesn't have the first element set we give up
                if (e == null)
                {
                    return i;
                }
                moveToNextConsumerChunk(cChunk, next);

                cChunk = next;
            }
            else
            {
                e = cChunk.lvElement(consumerOffset);
                if (e == null)
                {
                    return i;
                }
            }
            cChunk.soElement(consumerOffset, null);
            final long nextConsumerIndex = cIndex + 1;
            soConsumerIndex(nextConsumerIndex);
            c.accept(e);
            cIndex = nextConsumerIndex;
        }
        return limit;
    }
@param chunkSize The buffer size to be used in each chunk of this queue
@param maxPooledChunks The maximum number of reused chunks kept around to avoid allocation, chunks are pre-allocated
jctools-core/src/main/java/org/jctools/queues/MpscUnboundedXaddArrayQueue.java