Skip to content

(feat): add reshape! — zero-allocation array reshaping via pool wrapper cache#21

Merged
mgyoo86 merged 5 commits intomasterfrom
feat/reshape!
Mar 6, 2026
Merged

(feat): add reshape! — zero-allocation array reshaping via pool wrapper cache#21
mgyoo86 merged 5 commits intomasterfrom
feat/reshape!

Conversation

@mgyoo86
Copy link
Collaborator

@mgyoo86 mgyoo86 commented Mar 6, 2026

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 via setfield!-based wrapper reuse. The result shares memory with the source array.

Motivation

Base.reshape allocates 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 existing nd_wrappers infrastructure.

Changes

File Change
src/acquire.jl Add _claim_slot! (wrapper-only slot reservation) and _reshape_impl! for AdaptiveArrayPool using setfield!(:ref, :size)
src/convenience.jl Add public reshape! API with _record_type_touch!, DisabledPool fallbacks, and _impl! delegators
src/macros.jl Transform reshape!_reshape_impl! inside @with_pool/@maybe_with_pool; extract eltype(A) for typed-lazy mode
docs/ API docs, quick-start example, and reference table entry
test/test_reshape.jl 427-line test suite (see below)

Design

  • Same dimensionality (M == N): setfield!(A, :size, dims) in-place — no pool interaction, effectively free
  • Cross dimensionality (M != N): _claim_slot! reserves a pool slot without backing memory, then reuses a cached Array{T,N} wrapper via setfield!(:ref, :size) pointing to A's MemoryRef
  • Memory sharing: Reshaped array shares memory with original — mutations visible in both directions
  • Validation: DimensionMismatch thrown before slot reservation if prod(dims) != length(A)
  • Julia 1.10 fallback: Base _reshape_impl! delegates to Base.reshape

mgyoo86 added 4 commits March 5, 2026 21:21
…ape!

- @with_pool function with mixed acquire!/reshape!/zeros! scenarios
- Zero-allocation test for the combined function pattern (v1.11+)
- @maybe_with_pool pooling vs no-pooling allocation comparison
  proving pool is the source of zero-alloc (alloc==0 vs alloc>0)
… cache

- Export reshape!(pool, A, dims...) public API with type touch recording
- _reshape_impl! with setfield!-based wrapper reuse (Julia 1.11+):
  same-dim updates size in-place, cross-dim claims slot + reuses cached wrapper
- _claim_slot! for wrapper-only slot reservation (no backing memory)
- Macro integration: type extraction, _RESHAPE_IMPL_REF call transformation
- DisabledPool{:cpu} fallback delegates to Base.reshape
- Include test_reshape.jl in both v1.11+ and legacy test paths
- README, api.md, api-essentials.md, quick-start.md: add reshape! entries
- api-essentials.md: new "Reshaping with reshape!" section with example
- test_reshape.jl: assert external data unchanged after @with_pool call
@codecov
Copy link

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 90.76923% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.21%. Comparing base (2adde8d) to head (0a8ae4d).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/acquire.jl 92.85% 3 Missing ⚠️
src/convenience.jl 87.50% 2 Missing ⚠️
src/macros.jl 85.71% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #21      +/-   ##
==========================================
- Coverage   95.38%   95.21%   -0.18%     
==========================================
  Files          13       13              
  Lines        1756     1818      +62     
==========================================
+ Hits         1675     1731      +56     
- Misses         81       87       +6     
Files with missing lines Coverage Δ
src/AdaptiveArrayPools.jl 100.00% <ø> (ø)
src/macros.jl 92.65% <85.71%> (-0.13%) ⬇️
src/convenience.jl 99.20% <87.50%> (-0.80%) ⬇️
src/acquire.jl 91.00% <92.85%> (+0.33%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new reshape!(pool, A, dims...) convenience API that uses the pool’s cached N-D wrappers to avoid repeated reshape-wrapper allocations (notably enabling zero-allocation cross-dimensional reshapes on Julia ≥ 1.11 after warmup).

Changes:

  • Introduces _claim_slot! and an AdaptiveArrayPool-specialized _reshape_impl! that reuses cached Array{T,N} wrappers via setfield!.
  • Adds the public reshape! API (with macro integration via _reshape_impl! rewriting) and DisabledPool fallbacks.
  • Adds extensive tests and updates user docs/README/API reference to include reshape!.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/acquire.jl Adds wrapper-only slot claiming and the Julia ≥ 1.11 zero-allocation reshape implementation using cached wrappers.
src/convenience.jl Introduces the public reshape! API + fallback _reshape_impl! and DisabledPool support.
src/macros.jl Extends type-extraction and call-rewriting so reshape! participates in typed/lazy macro optimizations.
src/AdaptiveArrayPools.jl Exports reshape! as part of the public API.
test/test_reshape.jl New test suite covering correctness, error cases, macro integration, and allocation behavior (version-gated).
test/runtests.jl Includes test_reshape.jl in the test run.
docs/src/reference/api.md Adds reshape! to the API reference table.
docs/src/basics/quick-start.md Adds reshape! to the quick-start convenience table.
docs/src/basics/api-essentials.md Adds a reshape! section and a quick-reference table entry.
README.md Documents reshape! in the top-level convenience-function table.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ocs and edge cases

- Extract `_warn_pool_growing`/@noinline + `_check_pool_growth` helper to
  deduplicate pool growth warning logic and reduce hot-path code size
- Add growth warning to `_claim_slot!` (mirrors `get_view!` behavior)
- Use zero-length dims for cache-miss wrapper to avoid orphaned 1-element buffer
- Add negative-dim guard to fallback `_reshape_impl!` (Julia 1.10 parity)
- Update `reshape!` docstring with in-place mutation and scope-escape caveats
- Fix API docs table return type from `Array{T,N}` to generic description
@mgyoo86 mgyoo86 merged commit fd06416 into master Mar 6, 2026
9 of 10 checks passed
@mgyoo86 mgyoo86 deleted the feat/reshape! branch March 6, 2026 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants