Reuse & Selection

Double Buffers & Storage Utilities

Reuse state instead of rebuilding it. Double buffers keep the last pass readable while the next one is written, and the array helpers grow, resize, refill and compare arrays you already own.

Updated Publisher Alien_AlgorithmsPine Script v6

Double buffers

IntDoubleBuffer and FloatDoubleBuffer keep two arrays, current and previous. swap() exchanges their references in O(1), keeps the completed pass as previous, and clears the new current for reuse. Nothing is copied and no new array is created; the clear still costs O(N).

This is useful when one pass must stay readable while the next is built: graph searches, flood fills, iterative clustering and simulations.

Example: a search frontier

In this small search, node n has children 2n and 2n + 1. Each pass reads the active level and writes the next one:

Three levels, no copiespine
var op.IntDoubleBuffer searchFrontier = op.intDoubleBuffer()

if barstate.isfirst
    searchFrontier.current.push(1)

    for depth = 1 to 3
        [nextFrontier, activeFrontier] = searchFrontier.swap()

        for nodeId in activeFrontier
            nextFrontier.push(nodeId * 2)
            nextFrontier.push(nodeId * 2 + 1)

// Output: current contains [8, 9, 10, 11, 12, 13, 14, 15].
//         previous contains [4, 5, 6, 7].

swap() returns [current, previous]: the other retained array, already empty, as nextFrontier, and the completed level as activeFrontier.

Swap rules

  • swapSized(size, fillValue) swaps and then sizes the new current array to exactly size, every element set to fillValue. Use it when every pass writes a fixed-size output by index.
  • clear() empties both arrays and keeps their allocations.
  • Both arrays belong to the buffer and may be written freely between swaps.
Re-read after every swap
A reference to current taken before a swap now points at previous. Use the arrays swap() returns, or read the fields again.

Reusing arrays

A var array that is resized and refilled in place costs no allocation. Four helper families do this for arrays you own, with one version per type: Int, Float, Bool, Color and String.

HelperWhat it does
op.ensureSizeFloat(values, minimumSize, fillValue)Grows the array to at least minimumSize by appending fillValue. Never shrinks, never touches existing elements.
op.resizeFloat(values, size, fillValue)Makes the array exactly size long, appending fillValue or removing from the end.
op.refillFloat(values, size, fillValue)Makes the array exactly size long with every element set to fillValue.
op.sameExactFloat(left, right)True when both arrays hold exactly the same elements in order.

The size helpers return the resulting size, raise when the array is na, and raise when the size would exceed 100,000 elements. The fill value defaults to 0, false or na, depending on the type. ensureSize*() pairs naturally with a StablePool: grow each payload array when acquire() reports a new key.

Grow a payload array for a new slotpine
[slot, created] = zonePool.acquire(zoneId)
if created
    op.ensureSizeFloat(zonePrices, slot + 1, na)
zonePrices.set(slot, zonePrice)

Exact comparison

sameExact*() compares two arrays element by element, without the rounding Pine applies to float comparisons, so a tiny real difference counts. na equals na, and an na array counts as empty. It compares the way a Watch does; call it directly when you hold both arrays yourself.

Flat arrays and matrices

Row rings and ring helpers return flat arrays, row by row. These helpers move that data to and from Pine's matrix type:

  • op.matrixFromFlat(source, rows, columns, startIndex = 0) builds a new float matrix from a contiguous range of a flat array. When the range is not fully present, it returns a zero-filled matrix of the requested shape. op.intMatrixFromFlat() is the int version.
  • op.flatFromFloatMatrix(source, output = na) and op.flatFromIntMatrix() copy a matrix into a flat array, row by row.
  • op.transposeFlatFloat(source, rows, columns, output = na) and op.transposeFlatInt() transpose a flat matrix without building a matrix object. The output must not be the source.
A ring's history as a matrixpine
var op.FloatRowRing history = op.floatRowRing(200, 3)
var array<float> flatHistory = array.new<float>()

// Every retained row, oldest first, then one matrix with a row per bar.
history.chronological(flatHistory)
matrix<float> features = op.matrixFromFlat(flatHistory, history.rowCount(), 3)

Constants

ConstantValue
op.MAX_ARRAY_ELEMENTS100,000. The most elements one Pine array or matrix can hold.
op.MAX_MAP_PAIRS50,000. The most pairs one Pine map can hold.
op.MAX_GENERATION2,000,000,000. The highest generation or revision value before a structure starts again from 0.

Calls

CallWhat it does
op.intDoubleBuffer(), op.floatDoubleBuffer()Create a double buffer with two empty arrays.
buffer.current, buffer.previousThe two arrays, as fields.
buffer.swap()Swaps, clears the new current array, and returns [current, previous].
buffer.swapSized(size, fillValue)Swaps and refills the new current array to a fixed size.
buffer.clear()Empties both arrays.
op.ensureSize*(), op.resize*(), op.refill*(), op.sameExact*()Array helpers for Int, Float, Bool, Color and String.
op.matrixFromFlat(), op.intMatrixFromFlat(), op.flatFromFloatMatrix(), op.flatFromIntMatrix()Convert between flat arrays and matrices.
op.transposeFlatFloat(), op.transposeFlatInt()Transpose a flat matrix.

Every signature is in the API Reference. Next: Weighted Sampling.

OptiPine is a performance library for Pine Script. TradingView's memory, execution and collection limits still apply. © Alien_Algorithms.