@Override
    final boolean offerColdPath(final AtomicReferenceArray<E> buffer, final long mask, final long index, final int offset, final E v, final Supplier<? extends E> s) {
        final long lookAheadStep = this.lookAheadStep;
        // normal case, go around the buffer or resize if full (unless we hit max capacity)
        if (lookAheadStep > 0) {
            int lookAheadElementOffset = calcCircularRefElementOffset(index + lookAheadStep, mask);
            // Try and look ahead a number of elements so we don't have to do this all the time
            if (null == lvRefElement(buffer, lookAheadElementOffset)) {
                // joy, there's plenty of room
                producerBufferLimit = index + lookAheadStep - 1;
                writeToQueue(buffer, v == null ? s.get() : v, index, offset);
                return true;
            }
            // we're at max capacity, can use up last element
            final int maxCapacity = maxQueueCapacity;
            if (mask + 1 == maxCapacity) {
                if (null == lvRefElement(buffer, offset)) {
                    writeToQueue(buffer, v == null ? s.get() : v, index, offset);
                    return true;
                }
                // we're full and can't grow
                return false;
            }
            // not at max capacity, so must allow extra slot for next buffer pointer
            if (null == lvRefElement(buffer, calcCircularRefElementOffset(index + 1, mask))) {
                // buffer is not full
                writeToQueue(buffer, v == null ? s.get() : v, index, offset);
            } else {
                // allocate new buffer of same length
                final AtomicReferenceArray<E> newBuffer = allocateRefArray((int) (2 * (mask + 1) + 1));
                producerBuffer = newBuffer;
                producerMask = length(newBuffer) - 2;
                final int offsetInNew = calcCircularRefElementOffset(index, producerMask);
                linkOldToNew(index, buffer, offset, newBuffer, offsetInNew, v == null ? s.get() : v);
                int newCapacity = (int) (producerMask + 1);
                if (newCapacity == maxCapacity) {
                    long currConsumerIndex = lvConsumerIndex();
                    // use lookAheadStep to store the consumer distance from final buffer
                    this.lookAheadStep = -(index - currConsumerIndex);
                    producerBufferLimit = currConsumerIndex + maxCapacity;
                } else {
                    producerBufferLimit = index + producerMask - 1;
                    adjustLookAheadStep(newCapacity);
                }
            }
            return true;
        } else // the step is negative (or zero) in the period between allocating the max sized buffer and the
        // consumer starting on it
        {
            final long prevElementsInOtherBuffers = -lookAheadStep;
            // until the consumer starts using the current buffer we need to check consumer index to
            // verify size
            long currConsumerIndex = lvConsumerIndex();
            int size = (int) (index - currConsumerIndex);
            // we're on max capacity or we wouldn't be here
            int maxCapacity = (int) mask + 1;
            if (size == maxCapacity) {
                // consumer index has not changed since adjusting the lookAhead index, we're full
                return false;
            }
            // if consumerIndex progressed enough so that current size indicates it is on same buffer
            long firstIndexInCurrentBuffer = producerBufferLimit - maxCapacity + prevElementsInOtherBuffers;
            if (currConsumerIndex >= firstIndexInCurrentBuffer) {
                // job done, we've now settled into our final state
                adjustLookAheadStep(maxCapacity);
            } else // consumer is still on some other buffer
            {
                // how many elements out of buffer?
                this.lookAheadStep = (int) (currConsumerIndex - firstIndexInCurrentBuffer);
            }
            producerBufferLimit = currConsumerIndex + maxCapacity;
            writeToQueue(buffer, v == null ? s.get() : v, index, offset);
            return true;
        }
    }
NOTE: This class was automatically generated by org.jctools.queues.atomic.unpadded.JavaParsingAtomicUnpaddedLinkedQueueGenerator
which can found in the jctools-build module. The original source file is SpscGrowableArrayQueue.java.

An SPSC array queue which starts at <i>initialCapacity</i> and grows to <i>maxCapacity</i> in linked chunks,
doubling theirs size every time until the full blown backing array is used.
The queue grows only when the current chunk is full and elements are not copied on
resize, instead a link to the new chunk is stored in the old chunk for the consumer to follow.<br>

@param <E>
jctools-core/src/main/java/org/jctools/queues/atomic/unpadded/SpscGrowableAtomicUnpaddedArrayQueue.java