Skip to content

Fixed-size multidimensional arrays. An Array-like type with less indirection at the cost of resizing capability.

License

Notifications You must be signed in to change notification settings

JuliaArrays/FixedSizeArrays.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FixedSizeArrays.jl

Aqua QA Build Status Coverage PkgEval

FixedSizeArrays.jl is a proof-of-concept package for the Julia programming language which implements mutable fixed-size arrays, which means the length of the array is constant and is amenable to be constant-propagated at compile-time when possible. This is an alternative implementation to MArray from StaticArrays.jl.

Main differences between FixedSizeArray and MArray are:

  • FixedSizeArray is based on the Memory type introduced in Julia v1.11, MArray is backed by tuples;
  • the size of the array is part of the type parameters of MArray, this isn't the case for FixedSizeArray, where the size is only a constant field of the data structure.

FixedSizeArrays supports the usual array interfaces, so things like broadcasting, matrix multiplication, other linear algebra operations, similar, copyto! or map should just work.

Use the constructors to convert from other array types. Use collect_as to convert from arbitrary iterators.

julia> arr = [10 20; 30 14]
2×2 Matrix{Int64}:
 10  20
 30  14

julia> iter = (i for i ∈ 7:9 if i≠8);

julia> using FixedSizeArrays

julia> FixedSizeArray(arr)  # construct from an `AbstractArray` value
2×2 FixedSizeMatrix{Int64}:
 10  20
 30  14

julia> FixedSizeArray{Float64}(arr)  # construct from an `AbstractArray` value while converting element type
2×2 FixedSizeMatrix{Float64}:
 10.0  20.0
 30.0  14.0

julia> const ca = FixedSizeArrays.collect_as
collect_as (generic function with 1 method)

julia> ca(FixedSizeArray, iter)  # construct from an arbitrary iterator
2-element FixedSizeVector{Int64}:
 7
 9

julia> ca(FixedSizeArray{Float64}, iter)  # construct from an arbitrary iterator while converting element type
2-element FixedSizeVector{Float64}:
 7.0
 9.0

Note: FixedSizeArrays are not guaranteed to be stack-allocated, in fact they will more likely not be stack-allocated. However, in some extremely simple cases the compiler may be able to completely elide their allocations:

julia> using FixedSizeArrays

julia> @noinline f(A::AbstractArray) = length(A)
f (generic function with 1 method)

julia> g() = f(FixedSizeVector{Float64}(undef, 3))
g (generic function with 1 method)

julia> h() = f(Vector{Float64}(undef, 3))
h (generic function with 1 method)

julia> code_llvm(g)
; Function Signature: g()
;  @ REPL[3]:1 within `g`
define i64 @julia_g_511() #0 {
top:
  ret i64 3
}
julia> code_llvm(h)
; Function Signature: h()
;  @ REPL[4]:1 within `h`
define i64 @julia_h_693() #0 {
top:
  %gcframe1 = alloca [3 x ptr], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %gcframe1, i8 0, i64 24, i1 true)
  %pgcstack = call ptr inttoptr (i64 7452881148 to ptr)(i64 262) #10
  store i64 4, ptr %gcframe1, align 16
  %task.gcstack = load ptr, ptr %pgcstack, align 8
  %frame.prev = getelementptr inbounds ptr, ptr %gcframe1, i64 1
  store ptr %task.gcstack, ptr %frame.prev, align 8
  store ptr %gcframe1, ptr %pgcstack, align 8
; ┌ @ boot.jl:576 within `Array`
; │┌ @ boot.jl:514 within `GenericMemory`
    %"Memory{Float64}[]" = call ptr @jl_alloc_genericmemory(ptr nonnull @"+Core.GenericMemory#695.jit", i64 3)
; │└
; │ @ boot.jl:577 within `Array`
   %.data_ptr = getelementptr inbounds { i64, ptr }, ptr %"Memory{Float64}[]", i64 0, i32 1
   %0 = load ptr, ptr %.data_ptr, align 8
   %gc_slot_addr_0 = getelementptr inbounds ptr, ptr %gcframe1, i64 2
   store ptr %"Memory{Float64}[]", ptr %gc_slot_addr_0, align 16
   %ptls_field = getelementptr inbounds ptr, ptr %pgcstack, i64 2
   %ptls_load = load ptr, ptr %ptls_field, align 8
   %"new::Array" = call noalias nonnull align 8 dereferenceable(32) ptr @ijl_gc_pool_alloc_instrumented(ptr %ptls_load, i32 800, i32 32, i64 4645053728) #8
   %"new::Array.tag_addr" = getelementptr inbounds i64, ptr %"new::Array", i64 -1
   store atomic i64 4645053728, ptr %"new::Array.tag_addr" unordered, align 8
   %1 = getelementptr inbounds ptr, ptr %"new::Array", i64 1
   store ptr %0, ptr %"new::Array", align 8
   store ptr %"Memory{Float64}[]", ptr %1, align 8
   %"new::Array.size_ptr" = getelementptr inbounds i8, ptr %"new::Array", i64 16
   store i64 3, ptr %"new::Array.size_ptr", align 8
   store ptr %"new::Array", ptr %gc_slot_addr_0, align 16
; └
  %2 = call i64 @j_f_699(ptr nonnull %"new::Array")
  %frame.prev10 = load ptr, ptr %frame.prev, align 8
  store ptr %frame.prev10, ptr %pgcstack, align 8
  ret i64 %2
}

Warning

This package should currently be used only to experiment with the idea of Memory-backed fixed-size arrays, it's highly non-optimised, absolutely don't use it for production.

About

Fixed-size multidimensional arrays. An Array-like type with less indirection at the cost of resizing capability.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Languages