Skip to content

Commit c4008ff

Browse files
authored
WIP Add size to abstract StaticArray type (#134)
* Add size to abstract StaticArray type * Update SUnitRange + bufix
1 parent b643ff5 commit c4008ff

28 files changed

+279
-268
lines changed

README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,10 @@ an `MArray` might be preferable.
325325

326326
Sometimes it might be useful to imbue your own types, having multiple fields,
327327
with vector-like properties. *StaticArrays* can take care of this for you by
328-
allowing you to inherit from `FieldVector{T}`. For example, consider:
328+
allowing you to inherit from `FieldVector{N, T}`. For example, consider:
329329

330330
```julia
331-
immutable Point3D <: FieldVector{Float64}
331+
immutable Point3D <: FieldVector{3, Float64}
332332
x::Float64
333333
y::Float64
334334
z::Float64
@@ -337,21 +337,22 @@ end
337337

338338
With this type, users can easily access fields to `p = Point3D(x,y,z)` using
339339
`p.x`, `p.y` or `p.z`, or alternatively via `p[1]`, `p[2]`, or `p[3]`. You may
340-
even permute the coordinates with `p[(3,2,1)]`). Furthermore, `Point3D` is a
341-
complete `AbstractVector` implementation where you can add, subtract or scale
342-
vectors, multiply them by matrices (and return the same type), etc.
340+
even permute the coordinates with `p[SVector(3,2,1)]`). Furthermore, `Point3D`
341+
is a complete `AbstractVector` implementation where you can add, subtract or
342+
scale vectors, multiply them by matrices, etc.
343343

344344
It is also worth noting that `FieldVector`s may be mutable or immutable, and
345-
that `setindex!` is defined for use on mutable types. For mutable containers,
346-
you may want to define a default constructor (no inputs) that can be called by
347-
`similar`.
345+
that `setindex!` is defined for use on mutable types. For immutable containers,
346+
you may want to define a method for `similar_type` so that operations leave the
347+
type constant (otherwise they may fall back to `SVector`). For mutable
348+
containers, you may want to define a default constructor (no inputs) and an
349+
appropriate method for `similar`,
348350

349351
### Implementing your own types
350352

351-
You can easily create your own `StaticArray` type, by defining both `Size` (on the
352-
*type*, e.g. `StaticArrays.Size(::Type{Point3D}) = Size(3)`), and linear
353+
You can easily create your own `StaticArray` type, by defining linear
353354
`getindex` (and optionally `setindex!` for mutable types - see
354-
`setindex(::SVector, val, i)` in *MVector.jl* for an example of how to
355+
`setindex(::MArray, val, i)` in *MArray.jl* for an example of how to
355356
achieve this through pointer manipulation). Your type should define a constructor
356357
that takes a tuple of the data (and mutable containers may want to define a
357358
default constructor).

src/FieldVector.jl

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
"""
2-
abstract FieldVector{T} <: StaticVector{T}
2+
abstract FieldVector{N, T} <: StaticVector{N, T}
33
44
Inheriting from this type will make it easy to create your own vector types. A `FieldVector`
5-
will automatically determine its size from the number of fields, and define `getindex` and
6-
`setindex!` appropriately. An immutable `FieldVector` will be as performant as an `SVector`
7-
of similar length and element type, while a mutable `FieldVector` will behave similarly to
8-
an `MVector`.
5+
will automatically define `getindex` and `setindex!` appropriately. An immutable
6+
`FieldVector` will be as performant as an `SVector` of similar length and element type,
7+
while a mutable `FieldVector` will behave similarly to an `MVector`.
98
109
For example:
1110
12-
immutable/type Point3D <: FieldVector{Float64}
11+
immutable/type Point3D <: FieldVector{3, Float64}
1312
x::Float64
1413
y::Float64
1514
z::Float64
1615
end
1716
"""
18-
abstract type FieldVector{T} <: StaticVector{T} end
17+
abstract type FieldVector{N, T} <: StaticVector{N, T} end
1918

2019
# Is this a good idea?? Should people just define constructors that accept tuples?
21-
@inline (::Type{FV}){FV<:FieldVector}(x::Tuple) = FV(x...)
20+
@inline (::Type{FV})(x::Tuple) where {FV <: FieldVector} = FV(x...)
2221

23-
@pure Size{FV<:FieldVector}(::Type{FV}) = Size(nfields(FV))
24-
25-
@inline getindex(v::FieldVector, i::Int) = getfield(v, i)
26-
@inline setindex!(v::FieldVector, x, i::Int) = setfield!(v, i, x)
22+
@propagate_inbounds getindex(v::FieldVector, i::Int) = getfield(v, i)
23+
@propagate_inbounds setindex!(v::FieldVector, x, i::Int) = setfield!(v, i, x)
2724

2825
# See #53
2926
Base.cconvert{T}(::Type{Ptr{T}}, v::FieldVector) = Ref(v)

src/MArray.jl

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,81 @@
11
"""
2-
MArray{Size, T, L}()
3-
MArray{Size, T, L}(x::NTuple{L, T})
4-
MArray{Size, T, L}(x1, x2, x3, ...)
2+
MArray{S, T, L}()
3+
MArray{S, T, L}(x::NTuple{L, T})
4+
MArray{S, T, L}(x1, x2, x3, ...)
5+
56
67
Construct a statically-sized, mutable array `MArray`. The data may optionally be
7-
provided upon construction and can be mutated later. The `Size` parameter is a
8-
Tuple specifying the dimensions of the array. The `L` parameter is the `length`
9-
of the array and is always equal to `prod(S)`. Constructors may drop the `L` and
10-
`T` parameters if they are inferrable from the input (e.g. `L` is always
11-
inferrable from `Size`).
8+
provided upon construction and cannot be mutated later. The `S` parameter is a Tuple-type
9+
specifying the dimensions, or size, of the array - such as `Tuple{3,4,5}` for a 3×4×5-sized
10+
array. The `L` parameter is the `length` of the array and is always equal to `prod(S)`.
11+
Constructors may drop the `L` and `T` parameters if they are inferrable from the input
12+
(e.g. `L` is always inferrable from `S`).
1213
13-
MArray{Size}(a::Array)
14+
MArray{S}(a::Array)
1415
15-
Construct a statically-sized, mutable array of dimensions `Size` using the data from
16-
`a`. The `Size` parameter is mandatory since the size of `a` is unknown to the
17-
compiler (the element type may optionally also be specified).
16+
Construct a statically-sized, mutable array of dimensions `S` (expressed as a `Tuple{...}`)
17+
using the data from `a`. The `S` parameter is mandatory since the size of `a` is unknown to
18+
the compiler (the element type may optionally also be specified).
1819
"""
19-
type MArray{Size, T, N, L} <: StaticArray{T, N}
20+
type MArray{S <: Tuple, T, N, L} <: StaticArray{S, T, N}
2021
data::NTuple{L,T}
2122

22-
function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,T})
23-
check_array_parameters(Size, T, Val{N}, Val{L})
24-
new{Size,T,N,L}(x)
23+
function (::Type{MArray{S,T,N,L}}){S,T,N,L}(x::NTuple{L,T})
24+
check_array_parameters(S, T, Val{N}, Val{L})
25+
new{S,T,N,L}(x)
2526
end
2627

27-
function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,Any})
28-
check_array_parameters(Size, T, Val{N}, Val{L})
29-
new{Size,T,N,L}(convert_ntuple(T, x))
28+
function (::Type{MArray{S,T,N,L}}){S,T,N,L}(x::NTuple{L,Any})
29+
check_array_parameters(S, T, Val{N}, Val{L})
30+
new{S,T,N,L}(convert_ntuple(T, x))
3031
end
3132

32-
function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}()
33-
check_array_parameters(Size, T, Val{N}, Val{L})
34-
new{Size,T,N,L}()
33+
function (::Type{MArray{S,T,N,L}}){S,T,N,L}()
34+
check_array_parameters(S, T, Val{N}, Val{L})
35+
new{S,T,N,L}()
3536
end
3637
end
3738

38-
@generated function (::Type{MArray{Size,T,N}}){Size,T,N}(x::Tuple)
39+
@generated function (::Type{MArray{S,T,N}}){S,T,N}(x::Tuple)
3940
return quote
4041
$(Expr(:meta, :inline))
41-
MArray{Size,T,N,$(tuple_prod(Size))}(x)
42+
MArray{S,T,N,$(tuple_prod(S))}(x)
4243
end
4344
end
4445

45-
@generated function (::Type{MArray{Size,T}}){Size,T}(x::Tuple)
46+
@generated function (::Type{MArray{S,T}}){S,T}(x::Tuple)
4647
return quote
4748
$(Expr(:meta, :inline))
48-
MArray{Size,T,$(tuple_length(Size)),$(tuple_prod(Size))}(x)
49+
MArray{S,T,$(tuple_length(S)),$(tuple_prod(S))}(x)
4950
end
5051
end
5152

52-
@generated function (::Type{MArray{Size}}){Size, T <: Tuple}(x::T)
53+
@generated function (::Type{MArray{S}}){S, T <: Tuple}(x::T)
5354
return quote
5455
$(Expr(:meta, :inline))
55-
MArray{Size,$(promote_tuple_eltype(T)),$(tuple_length(Size)),$(tuple_prod(Size))}(x)
56+
MArray{S,$(promote_tuple_eltype(T)),$(tuple_length(S)),$(tuple_prod(S))}(x)
5657
end
5758
end
5859

59-
@generated function (::Type{MArray{Size,T,N}}){Size,T,N}()
60+
@generated function (::Type{MArray{S,T,N}}){S,T,N}()
6061
return quote
6162
$(Expr(:meta, :inline))
62-
MArray{Size, T, N, $(tuple_prod(Size))}()
63+
MArray{S, T, N, $(tuple_prod(S))}()
6364
end
6465
end
6566

66-
@generated function (::Type{MArray{Size,T}}){Size,T}()
67+
@generated function (::Type{MArray{S,T}}){S,T}()
6768
return quote
6869
$(Expr(:meta, :inline))
69-
MArray{Size, T, $(tuple_length(Size)), $(tuple_prod(Size))}()
70+
MArray{S, T, $(tuple_length(S)), $(tuple_prod(S))}()
7071
end
7172
end
7273

7374
@inline MArray(a::StaticArray) = MArray{size_tuple(typeof(a))}(Tuple(a))
7475

76+
# Simplified show for the type
77+
show(io::IO, ::Type{MArray{S, T, N}}) where {S, T, N} = print(io, "MArray{$S,$T,$N}")
78+
7579
# Some more advanced constructor-like functions
7680
@inline one(::Type{MArray{S}}) where {S} = one(MArray{S,Float64,tuple_length(S)})
7781
@inline eye(::Type{MArray{S}}) where {S} = eye(MArray{S,Float64,tuple_length(S)})
@@ -82,24 +86,19 @@ end
8286
## MArray methods ##
8387
####################
8488

85-
@pure Size{S}(::Type{MArray{S}}) = Size(S)
86-
@pure Size{S,T}(::Type{MArray{S,T}}) = Size(S)
87-
@pure Size{S,T,N}(::Type{MArray{S,T,N}}) = Size(S)
88-
@pure Size{S,T,N,L}(::Type{MArray{S,T,N,L}}) = Size(S)
89-
9089
function getindex(v::MArray, i::Int)
9190
Base.@_inline_meta
9291
v.data[i]
9392
end
9493

95-
@propagate_inbounds setindex!{S,T}(v::MArray{S,T}, val, i::Int) = setindex!(v, convert(T, val), i)
96-
@inline function setindex!{S,T}(v::MArray{S,T}, val::T, i::Int)
94+
@inline function setindex!(v::MArray, val, i::Int)
9795
@boundscheck if i < 1 || i > length(v)
9896
throw(BoundsError())
9997
end
10098

99+
T = eltype(v)
101100
if isbits(T)
102-
unsafe_store!(Base.unsafe_convert(Ptr{T}, Base.data_pointer_from_objref(v)), val, i)
101+
unsafe_store!(Base.unsafe_convert(Ptr{T}, Base.data_pointer_from_objref(v)), convert(T, val), i)
103102
else
104103
# This one is unsafe (#27)
105104
# unsafe_store!(Base.unsafe_convert(Ptr{Ptr{Void}}, Base.data_pointer_from_objref(v.data)), Base.data_pointer_from_objref(val), i)
@@ -111,7 +110,7 @@ end
111110

112111
@inline Tuple(v::MArray) = v.data
113112

114-
@inline function Base.unsafe_convert{Size,T}(::Type{Ptr{T}}, a::MArray{Size,T})
113+
@inline function Base.unsafe_convert{S,T}(::Type{Ptr{T}}, a::MArray{S,T})
115114
Base.unsafe_convert(Ptr{T}, Base.data_pointer_from_objref(a))
116115
end
117116

src/MMatrix.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,12 @@ end
5353
end
5454
end
5555

56-
@inline convert{S1,S2,T}(::Type{MMatrix{S1,S2}}, a::StaticArray{T}) = MMatrix{S1,S2,T}(Tuple(a))
56+
@inline convert{S1,S2,T}(::Type{MMatrix{S1,S2}}, a::StaticArray{<:Any, T}) = MMatrix{S1,S2,T}(Tuple(a))
5757
@inline MMatrix(a::StaticMatrix) = MMatrix{size(typeof(a),1),size(typeof(a),2)}(Tuple(a))
5858

59+
# Simplified show for the type
60+
show(io::IO, ::Type{MMatrix{N, M, T}}) where {N, M, T} = print(io, "MMatrix{$N,$M,$T}")
61+
5962
# Some more advanced constructor-like functions
6063
@inline one{N}(::Type{MMatrix{N}}) = one(MMatrix{N,N})
6164
@inline eye{N}(::Type{MMatrix{N}}) = eye(MMatrix{N,N})
@@ -64,10 +67,6 @@ end
6467
## MMatrix methods ##
6568
#####################
6669

67-
@pure Size{S1,S2}(::Type{MMatrix{S1,S2}}) = Size(S1, S2)
68-
@pure Size{S1,S2,T}(::Type{MMatrix{S1,S2,T}}) = Size(S1, S2)
69-
@pure Size{S1,S2,T,L}(::Type{MMatrix{S1,S2,T,L}}) = Size(S1, S2)
70-
7170
@propagate_inbounds function getindex{S1,S2,T}(m::MMatrix{S1,S2,T}, i::Int)
7271
#@boundscheck if i < 1 || i > length(m)
7372
# throw(BoundsError(m,i))

src/MVector.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ compiler (the element type may optionally also be specified).
1616
"""
1717
const MVector{S, T} = MArray{Tuple{S}, T, 1, S}
1818

19-
@inline (::Type{MVector}){S}(x::NTuple{S,Any}) = MVector{S}(x)
20-
@inline (::Type{MVector{S}}){S, T}(x::NTuple{S,T}) = MVector{S,T}(x)
21-
@inline (::Type{MVector{S}}){S, T <: Tuple}(x::T) = MVector{S,promote_tuple_eltype(T)}(x)
19+
@inline MVector(x::NTuple{S,Any}) where {S} = MVector{S}(x)
20+
@inline MVector{S}(x::NTuple{S,T}) where {S, T} = MVector{S, T}(x)
21+
@inline MVector{S}(x::NTuple{S,Any}) where {S} = MVector{S, promote_tuple_eltype(typeof(x))}(x)
22+
23+
# Simplified show for the type
24+
show(io::IO, ::Type{MVector{N, T}}) where {N, T} = print(io, "MVector{$N,$T}")
2225

2326
# Some more advanced constructor-like functions
2427
@inline zeros{N}(::Type{MVector{N}}) = zeros(MVector{N,Float64})
@@ -28,9 +31,6 @@ const MVector{S, T} = MArray{Tuple{S}, T, 1, S}
2831
## MVector methods ##
2932
#####################
3033

31-
@pure Size{S}(::Type{MVector{S}}) = Size(S)
32-
@pure Size{S,T}(::Type{MVector{S,T}}) = Size(S)
33-
3434
@propagate_inbounds function getindex(v::MVector, i::Int)
3535
v.data[i]
3636
end

src/SArray.jl

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,70 @@
11
"""
2-
SArray{Size, T, L}(x::NTuple{L, T})
3-
SArray{Size, T, L}(x1, x2, x3, ...)
2+
SArray{S, T, L}(x::NTuple{L, T})
3+
SArray{S, T, L}(x1, x2, x3, ...)
44
5-
Construct a statically-sized array `SArray`. Since this type is immutable,
6-
the data must be provided upon construction and cannot be mutated later. The
7-
`Size` parameter is a Tuple specifying the dimensions of the array. The
8-
`L` parameter is the `length` of the array and is always equal to `prod(S)`.
9-
Constructors may drop the `L` and `T` parameters if they are inferrable
10-
from the input (e.g. `L` is always inferrable from `Size`).
5+
Construct a statically-sized array `SArray`. Since this type is immutable, the data must be
6+
provided upon construction and cannot be mutated later. The `S` parameter is a Tuple-type
7+
specifying the dimensions, or size, of the array - such as `Tuple{3,4,5}` for a 3×4×5-sized
8+
array. The `L` parameter is the `length` of the array and is always equal to `prod(S)`.
9+
Constructors may drop the `L` and `T` parameters if they are inferrable from the input
10+
(e.g. `L` is always inferrable from `S`).
1111
12-
SArray{Size}(a::Array)
12+
SArray{S}(a::Array)
1313
14-
Construct a statically-sized array of dimensions `Size` using the data from
15-
`a`. The `Size` parameter is mandatory since the size of `a` is unknown to the
14+
Construct a statically-sized array of dimensions `S` (expressed as a `Tuple{...}`) using
15+
the data from `a`. The `S` parameter is mandatory since the size of `a` is unknown to the
1616
compiler (the element type may optionally also be specified).
1717
"""
18-
immutable SArray{Size, T, N, L} <: StaticArray{T, N}
18+
immutable SArray{S <: Tuple, T, N, L} <: StaticArray{S, T, N}
1919
data::NTuple{L,T}
2020

21-
function (::Type{SArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,T})
22-
check_array_parameters(Size, T, Val{N}, Val{L})
23-
new{Size,T,N,L}(x)
21+
function (::Type{SArray{S, T, N, L}}){S, T, N, L}(x::NTuple{L,T})
22+
check_array_parameters(S, T, Val{N}, Val{L})
23+
new{S, T, N, L}(x)
2424
end
2525

26-
function (::Type{SArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,Any})
27-
check_array_parameters(Size, T, Val{N}, Val{L})
28-
new{Size,T,N,L}(convert_ntuple(T, x))
26+
function (::Type{SArray{S, T, N, L}}){S, T, N, L}(x::NTuple{L,Any})
27+
check_array_parameters(S, T, Val{N}, Val{L})
28+
new{S, T, N, L}(convert_ntuple(T, x))
2929
end
3030
end
3131

32-
@generated function (::Type{SArray{Size,T,N}}){Size <: Tuple,T,N}(x::Tuple)
32+
@generated function (::Type{SArray{S, T, N}}){S <: Tuple, T, N}(x::Tuple)
3333
return quote
34-
$(Expr(:meta, :inline))
35-
SArray{Size,T,N,$(tuple_prod(Size))}(x)
34+
@_inline_meta
35+
SArray{S, T, N, $(tuple_prod(S))}(x)
3636
end
3737
end
3838

39-
@generated function (::Type{SArray{Size,T}}){Size <: Tuple,T}(x::Tuple)
39+
@generated function (::Type{SArray{S, T}}){S <: Tuple, T}(x::Tuple)
4040
return quote
41-
$(Expr(:meta, :inline))
42-
SArray{Size,T,$(tuple_length(Size)),$(tuple_prod(Size))}(x)
41+
@_inline_meta
42+
SArray{S, T, $(tuple_length(S)), $(tuple_prod(S))}(x)
4343
end
4444
end
4545

46-
@generated function (::Type{SArray{Size}}){Size <: Tuple, T <: Tuple}(x::T)
46+
@generated function (::Type{SArray{S}}){S <: Tuple, T <: Tuple}(x::T)
4747
return quote
48-
$(Expr(:meta, :inline))
49-
SArray{Size,$(promote_tuple_eltype(T)),$(tuple_length(Size)),$(tuple_prod(Size))}(x)
48+
@_inline_meta
49+
SArray{S, $(promote_tuple_eltype(T)), $(tuple_length(S)), $(tuple_prod(S))}(x)
5050
end
5151
end
5252

53-
@inline SArray(a::StaticArray) = SArray{size_tuple(a)}(Tuple(a))
53+
@inline SArray(a::StaticArray) = SArray{size_tuple(a)}(Tuple(a)) # TODO fixme
54+
55+
# Simplified show for the type
56+
show(io::IO, ::Type{SArray{S, T, N}}) where {S, T, N} = print(io, "SArray{$S,$T,$N}")
5457

5558
# Some more advanced constructor-like functions
56-
@inline one(::Type{SArray{S}}) where {S} = one(SArray{S,Float64,tuple_length(S)})
57-
@inline eye(::Type{SArray{S}}) where {S} = eye(SArray{S,Float64,tuple_length(S)})
58-
@inline one(::Type{SArray{S,T}}) where {S,T} = one(SArray{S,T,tuple_length(S)})
59-
@inline eye(::Type{SArray{S,T}}) where {S,T} = eye(SArray{S,T,tuple_length(S)})
59+
@inline one(::Type{SArray{S}}) where {S} = one(SArray{S, Float64, tuple_length(S)})
60+
@inline eye(::Type{SArray{S}}) where {S} = eye(SArray{S, Float64, tuple_length(S)})
61+
@inline one(::Type{SArray{S, T}}) where {S, T} = one(SArray{S, T, tuple_length(S)})
62+
@inline eye(::Type{SArray{S, T}}) where {S, T} = eye(SArray{S, T, tuple_length(S)})
6063

6164
####################
6265
## SArray methods ##
6366
####################
6467

65-
@pure Size{S}(::Type{SArray{S}}) = Size(S)
66-
@pure Size{S,T}(::Type{SArray{S,T}}) = Size(S)
67-
@pure Size{S,T,N}(::Type{SArray{S,T,N}}) = Size(S)
68-
@pure Size{S,T,N,L}(::Type{SArray{S,T,N,L}}) = Size(S)
69-
7068
function getindex(v::SArray, i::Int)
7169
Base.@_inline_meta
7270
v.data[i]

0 commit comments

Comments
 (0)