Skip to content

Commit 56a2be4

Browse files
committed
fix #56 and #65
1 parent 2b4ca7c commit 56a2be4

File tree

4 files changed

+198
-109
lines changed

4 files changed

+198
-109
lines changed

src/FixedSizeArrays.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ end
1717
immutable Mat{Row, Column, T} <: FixedMatrix{Row, Column, T}
1818
_::NTuple{Column, NTuple{Row, T}}
1919
end
20+
function similar{FSA <: Mat, T}(::Type{FSA}, ::Type{T}, SZ::NTuple{2, Int})
21+
Mat{SZ[1], SZ[2], T}
22+
end
2023

2124
# most common FSA types
2225
immutable Vec{N, T} <: FixedVector{N, T}

src/constructors.jl

Lines changed: 83 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,16 @@ _fill_tuples{N}(inner, originalSZ, SZ::NTuple{N, Int}, inds::Int...) =
1212
ntuple(i->_fill_tuples(inner, originalSZ, SZ[1:end-1], i, inds...), Val{SZ[end]})
1313
fill_tuples{N}(inner, SZ::NTuple{N, Int}) = _fill_tuples(inner, SZ, SZ)
1414

15-
@generated function call{FSA <: FixedArray, T1 <: FixedArray}(::Type{FSA}, a::T1, b...)
16-
SZ = size_or(FSA, nothing)
17-
ElType = eltype_or(FSA, eltype(T1))
18-
a_expr = :( a )
19-
if SZ != nothing
20-
if (prod(SZ) > (length(T1) + length(b)))
21-
throw(DimensionMismatch("$FSA is too small, can not be constructed from array $a and $b arguments"))
22-
elseif prod(SZ) < length(T1) && isempty(b) #shrinking constructor, e.g. Vec3(Vec4(...))
23-
a_expr = :( a[1:$(prod(SZ))] )
24-
end
25-
end
26-
if isempty(b)
27-
if ElType != eltype(T1) && FSA <: T1
28-
return :( map($ElType, $a_expr) )
29-
elseif ElType == eltype(T1) && !(FSA <: T1)
30-
return :( $FSA($a_expr...) )
31-
else
32-
return :( $FSA($a_expr...) )
33-
end
34-
else
35-
return :( $FSA(a..., b...) )
36-
end
37-
end
15+
16+
#=
17+
Constructors for homogenous non tuple arguments
18+
Is unrolled for the first 4, since a::T... leads to slow performance
19+
=#
20+
call{FSA <: FixedArray, T}(::Type{FSA}, a::T) = FSA(NTuple{1,T}((a,)))
21+
call{FSA <: FixedArray, T}(::Type{FSA}, a::T, b::T) = FSA(NTuple{2,T}((a,b)))
22+
call{FSA <: FixedArray, T}(::Type{FSA}, a::T, b::T, c::T) = FSA(NTuple{3,T}((a,b,c)))
23+
call{FSA <: FixedArray, T}(::Type{FSA}, a::T, b::T, c::T, d::T) = FSA(NTuple{4,T}((a,b,c,d)))
24+
call{FSA <: FixedArray, T}(::Type{FSA}, a::T...) = FSA(a)
3825

3926
immutable ParseFunctor{T, S <: AbstractString} <: Func{1}
4027
t::Type{T}
@@ -43,6 +30,10 @@ end
4330
call{T}(pf::ParseFunctor{T}, i::Int) = parse(T, pf.a[i])
4431
call(pf::ParseFunctor{Void}, i::Int) = parse(pf.a[i])
4532

33+
34+
"""
35+
Constructs a fixedsize array from a Base.Array
36+
"""
4637
@generated function call{FSA <: FixedArray, T <: Array}(::Type{FSA}, a::T)
4738
if eltype(a) <: AbstractString
4839
ElType = eltype_or(FSA, Void)
@@ -56,48 +47,91 @@ call(pf::ParseFunctor{Void}, i::Int) = parse(pf.a[i])
5647
tupexpr = fill_tuples_expr((i,inds...) -> :($ElType(a[$i, $(inds...)])), SZ)
5748
expr = :($FSA($tupexpr))
5849
end
59-
if FSA <: FixedVectorNoTuple
60-
expr = :($FSA(a...))
61-
end
6250
quote
6351
$SZ != size(a) && throw(DimensionMismatch("size of $FSA is not fitting array $(typeof(a)), with size: $(size(a))"))
6452
$expr
6553
end
6654
end
6755

68-
call{FSA <: FixedVectorNoTuple}(::Type{FSA}, a::Tuple, b::Tuple...) = throw(DimensionMismatch("$FSA can't be constructed from $a"))
69-
call{FSA <: FixedVectorNoTuple}(::Type{FSA}, a::Tuple) = FSA(a...)
70-
call{FSA <: FixedArray, T}(::Type{FSA}, a::T...) = FSA(a)
71-
72-
7356

57+
"""
58+
Constructor for singular arguments.
59+
Can be a tuple, is not declared as that, because it will generate ambigouities
60+
and overwrites the default constructor.
61+
"""
7462
@generated function call{FSA <: FixedArray, X}(::Type{FSA}, a::X)
75-
SZ = size_or(FSA, (1,))
76-
ElType = eltype_or(FSA, a)
77-
Len = prod(SZ)
78-
T_N = FSA
79-
if FSA <: FixedVectorNoTuple
80-
return :($T_N($(ntuple(i-> :($ElType(a)), Len)...)))
63+
ND = ndims(FSA)
64+
if X <: Tuple
65+
types_svec = a.parameters
66+
if all(x-> x <: Tuple, types_svec) && ND == 1
67+
return :(throw(
68+
DimensionMismatch("tried to construct $FSA from $a. I can't allow that!")
69+
))
70+
end
71+
orlen = length(types_svec)
72+
ortyp = promote_type(types_svec...)
73+
else
74+
orlen = 1
75+
ortyp = a
76+
end
77+
SZ = size_or(FSA, (orlen, ntuple(x->1, ND-1)...))
78+
T = eltype_or(FSA, ortyp)
79+
FSAT = similar(FSA, T, SZ)
80+
if X <: Tuple
81+
expr = fill_tuples_expr((inds...)->:($T(a[$(inds[1])])), SZ)
8182
else
82-
expr = fill_tuples_expr((inds...)->:($ElType(a[1])), SZ)
83-
return :($T_N($expr))
83+
expr = fill_tuples_expr((inds...)->:($T(a)), SZ)
8484
end
85+
return :($FSAT($expr))
8586
end
86-
87+
"""
88+
Constructors for heterogenous multiple arguments.
89+
E.g. 1, 2f0, 4.0
90+
"""
8791
@generated function call{FSA <: FixedArray}(::Type{FSA}, a...)
8892
SZ = size_or(FSA, (length(a),))
8993
ElType = eltype_or(FSA, promote_type(a...))
90-
if FSA <: FixedVectorNoTuple
91-
length(a) != prod(SZ) && throw(DimensionMismatch("can't construct $FSA with $(length(a)) arguments. Args: $a"))
92-
return :($FSA(map($ElType, a)...))
93-
else
94-
all(x-> x <: Tuple, a) && return :( $FSA(a) ) # TODO be smarter about this
95-
any(x-> x != ElType, a) && return :($FSA(map($ElType, a)))
96-
return :($FSA(a))
97-
end
94+
all(x-> x <: Tuple, a) && return :( $FSA(a) ) # TODO be smarter about this
95+
any(x-> x != ElType, a) && return :($FSA(map($ElType, a)))
96+
return :($FSA(a))
9897
end
9998

100-
99+
"""
100+
Construction from other FixedSizeArrays + X arguments
101+
E.g. Vec4f0(Vec3f0(1), 0)
102+
"""
103+
@generated function call{FSA <: FixedArray, T1 <: FixedArray}(::Type{FSA}, a::T1, b...)
104+
if isempty(b) # this is the conversion constructor for 2 FSA's
105+
#easiest way is to just construct from the tuple
106+
expr = :(FSA(get_tuple(a)))
107+
if size_or(FSA, nothing) == nothing # no concrete size
108+
return expr
109+
else #has a size
110+
len1 = size(FSA, 1)
111+
len2 = size(T1, 1)
112+
if len1 < len2 # we need to shrink
113+
return :(FSA(get_tuple(a)[1:$len1]))
114+
elseif len1==len2
115+
return expr
116+
else
117+
return :(throw(DimensionMismatch(
118+
"tried to create $FSA from $T1. The latter has too many elements"
119+
)))
120+
end
121+
end
122+
end
123+
SZ = size_or(FSA, nothing)
124+
ElType = eltype_or(FSA, eltype(T1))
125+
a_expr = :( a )
126+
if SZ != nothing
127+
if (prod(SZ) > (length(T1) + length(b)))
128+
throw(DimensionMismatch("$FSA is too small, can not be constructed from array $a and $b arguments"))
129+
elseif prod(SZ) < length(T1) && isempty(b) #shrinking constructor, e.g. Vec3(Vec4(...))
130+
a_expr = :( a[1:$(prod(SZ))] )
131+
end
132+
end
133+
return :( $FSA(a..., b...) )
134+
end
101135

102136
@inline zero{FSA <: FixedArray}(::Type{FSA}) = map(ConstFunctor(zero(eltype(FSA))), FSA)
103137
zero(fsa::FixedArray) = zero(typeof(fsa))

src/core.jl

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,19 @@ eltype{T <: FixedArray}(A::Type{T}) = eltype_or(T, Any)
2323
eltype{T <: FixedArray,N,SZ}(A::FixedArray{T,N,SZ}) = T
2424

2525

26-
length{T,N,SZ}(A::Type{FixedArray{T,N,SZ}}) = _length(SZ)
27-
length{T,N,SZ}(::FixedArray{T,N,SZ}) = _length(SZ)
28-
length{T <: FixedArray}(A::Type{T}) = length(supertype(T))
26+
function length{T <: FixedArray}(A::Type{T})
27+
prod(size(T))
28+
end
29+
length{T <: FixedArray}(A::T) = length(T)
2930

30-
endof{T,N,SZ}(A::FixedArray{T,N,SZ}) = length(A)
31+
endof{T <: FixedArray}(A::Type{T}) = length(T)
32+
endof{T <: FixedArray}(A::T) = length(T)
3133

3234

33-
ndims{T,N,SZ}(A::Type{FixedArray{T,N,SZ}}) = N
34-
ndims{T <: FixedArray}(A::Type{T}) = ndims(supertype(T))
35-
ndims{T <: FixedArray}(A::T) = ndims(T)
35+
@generated function ndims{T <: FixedArray}(A::Type{T})
36+
:($(fsa_abstract(T).parameters[2]))
37+
end
38+
ndims{T <: FixedArray}(A::T) = ndims(T)
3639

3740

3841
size{T,N,SZ}(A::Type{FixedArray{T,N,SZ}}) = _size(SZ)
@@ -70,23 +73,35 @@ end
7073
end
7174

7275
# Iterator
73-
start(A::FixedArray) = 1
76+
start(A::FixedArray) = 1
7477
function next(A::FixedArray, state::Integer)
7578
@inbounds x = A[state]
7679
(x, state+1)
7780
end
78-
done(A::FixedArray, state::Integer) = length(A) < state
81+
done(A::FixedArray, state::Integer) = length(A) < state
7982

8083

81-
@generated function similar{FSA <: FixedVector}(::Type{FSA}, typ::DataType, n::Int)
84+
similar{FSA <: FixedVector, T}(::Type{FSA}, ::Type{T}, n::Tuple) = similar(FSA, T, n...)
85+
@generated function similar{FSA <: FixedVector, T}(::Type{FSA}, ::Type{T}, n::Int)
86+
name = parse(string("Main.", FSA.name))
87+
:($name{n, T, $(FSA.parameters[3:end]...)})
88+
end
89+
@generated function similar{FSA <: FixedVector, T}(::Type{FSA}, ::Type{T})
8290
name = parse(string("Main.", FSA.name))
83-
:($name{n, typ, $(FSA.parameters[3:end]...)})
91+
:($name{$(FSA.parameters[1]), T, $(FSA.parameters[3:end]...)})
8492
end
85-
@generated function similar{FSA <: FixedVector}(::Type{FSA}, typ::DataType)
93+
@generated function similar{FSA <: FixedVectorNoTuple, T}(::Type{FSA}, ::Type{T})
8694
name = parse(string("Main.", FSA.name))
87-
:($name{$(FSA.parameters[1]), typ, $(FSA.parameters[3:end]...)})
95+
:($name{T, $(FSA.parameters[3:end]...)})
8896
end
89-
@generated function similar{FSA <: FixedVectorNoTuple}(::Type{FSA}, typ::DataType)
97+
@generated function similar{FSA <: FixedVectorNoTuple, T}(::Type{FSA}, ::Type{T}, n::Int)
9098
name = parse(string("Main.", FSA.name))
91-
:($name{typ, $(FSA.parameters[3:end]...)})
99+
:($name{T, $(FSA.parameters[3:end]...)})
100+
end
101+
102+
@generated function get_tuple{N, T}(f::FixedVectorNoTuple{N, T})
103+
:(tuple($(ntuple(i->:(f[$i]), N)...)))
104+
end
105+
function get_tuple(f::FixedArray)
106+
f.(1) # a little wonky, but there really no much sense if isn't the only field
92107
end

0 commit comments

Comments
 (0)