(feat): add reshape! — zero-allocation array reshaping via pool wrapper cache#21
Merged
(feat): add reshape! — zero-allocation array reshaping via pool wrapper cache#21
reshape! — zero-allocation array reshaping via pool wrapper cache#21Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add
reshape!(pool, A, dims...)that reshapes arrays using the pool's N-D wrapper cache. On Julia 1.11+, cross-dimensional reshapes are zero-allocation after warmup viasetfield!-based wrapper reuse. The result shares memory with the source array.Motivation
Base.reshapeallocates a new wrapper object on every call (~40-80 bytes). In hot loops that repeatedly reshape pooled arrays (e.g., treating a flat vector as a matrix for BLAS), these wrapper allocations accumulate.reshape!eliminates this by reusing cached wrappers from the pool's existingnd_wrappersinfrastructure.Changes
_claim_slot!(wrapper-only slot reservation) and_reshape_impl!forAdaptiveArrayPoolusingsetfield!(:ref, :size)reshape!API with_record_type_touch!,DisabledPoolfallbacks, and_impl!delegatorsreshape!→_reshape_impl!inside@with_pool/@maybe_with_pool; extracteltype(A)for typed-lazy modeDesign
setfield!(A, :size, dims)in-place — no pool interaction, effectively free_claim_slot!reserves a pool slot without backing memory, then reuses a cachedArray{T,N}wrapper viasetfield!(:ref, :size)pointing toA'sMemoryRefDimensionMismatchthrown before slot reservation ifprod(dims) != length(A)_reshape_impl!delegates toBase.reshape