-
Notifications
You must be signed in to change notification settings - Fork 148
/
MVector.jl
136 lines (117 loc) · 4.78 KB
/
MVector.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
type MVector{S, T} <: StaticVector{T}
data::NTuple{S, T}
function MVector(in::NTuple{S, T})
new(in)
end
function MVector(in::NTuple{S})
new(convert_ntuple(T,in))
end
function MVector(in::T)
new((in,))
end
function MVector()
new()
end
end
@inline (::Type{MVector}){S}(x::NTuple{S}) = MVector{S}(x)
@inline (::Type{MVector{S}}){S, T}(x::NTuple{S,T}) = MVector{S,T}(x)
@inline (::Type{MVector{S}}){S, T <: Tuple}(x::T) = MVector{S,promote_tuple_eltype(T)}(x)
# Some more advanced constructor-like functions
@inline zeros{N}(::Type{MVector{N}}) = zeros(MVector{N,Float64})
@inline ones{N}(::Type{MVector{N}}) = ones(MVector{N,Float64})
#####################
## MVector methods ##
#####################
@pure size{S}(::Union{MVector{S},Type{MVector{S}}}) = (S, )
@pure size{S,T}(::Type{MVector{S,T}}) = (S,)
@propagate_inbounds function getindex(v::MVector, i::Integer)
v.data[i]
end
# Mutating setindex!
@propagate_inbounds setindex!{S,T}(v::MVector{S,T}, val, i::Integer) = setindex!(v, convert(T, val), i)
@inline function setindex!{S,T}(v::MVector{S,T}, val::T, i::Integer)
@boundscheck if i < 1 || i > length(v)
throw(BoundsError())
end
if isbits(T)
unsafe_store!(Base.unsafe_convert(Ptr{T}, Base.data_pointer_from_objref(v)), val, i)
else # TODO check that this isn't crazy. Also, check it doesn't cause problems with GC...
unsafe_store!(Base.unsafe_convert(Ptr{Ptr{Void}}, Base.data_pointer_from_objref(v.data)), Base.data_pointer_from_objref(val), i)
end
return val
end
@inline Tuple(v::MVector) = v.data
@inline function Base.unsafe_convert{N,T}(::Type{Ptr{T}}, v::MVector{N,T})
Base.unsafe_convert(Ptr{T}, Base.data_pointer_from_objref(v))
end
macro MVector(ex)
if isa(ex, Expr) && ex.head == :vect
return esc(Expr(:call, MVector{length(ex.args)}, Expr(:tuple, ex.args...)))
elseif isa(ex, Expr) && ex.head == :ref
return esc(Expr(:call, Expr(:curly, :MVector, length(ex.args[2:end]), ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
elseif isa(ex, Expr) && ex.head == :comprehension
if length(ex.args) != 1 || !isa(ex.args[1], Expr) || ex.args[1].head != :generator
error("Expected generator in comprehension, e.g. [f(i) for i = 1:3]")
end
ex = ex.args[1]
if length(ex.args) != 2
error("Use a one-dimensional comprehension for @MVector")
end
rng = eval(current_module(), ex.args[2].args[2])
f = gensym()
f_expr = :($f = ($(ex.args[2].args[1]) -> $(ex.args[1])))
exprs = [:($f($j)) for j in rng]
return quote
$(Expr(:meta, :inline))
$(esc(f_expr))
$(esc(Expr(:call, Expr(:curly, :MVector, length(rng)), Expr(:tuple, exprs...))))
end
elseif isa(ex, Expr) && ex.head == :typed_comprehension
if length(ex.args) != 2 || !isa(ex.args[2], Expr) !! ex.args[2].head != :generator
error("Expected generator in typed comprehension, e.g. Float64[f(i) for i = 1:3]")
end
T = ex.args[1]
ex = ex.args[2]
if length(ex.args) != 2
error("Use a one-dimensional comprehension for @MVector")
end
rng = eval(current_module(), ex.args[2].args[2])
f = gensym()
f_expr = :($f = ($(ex.args[2].args[1]) -> $(ex.args[1])))
exprs = [:($f($j)) for j in rng]
return quote
$(Expr(:meta, :inline))
$(esc(f_expr))
$(esc(Expr(:call, Expr(:curly, :MVector, length(rng), T), Expr(:tuple, exprs...))))
end
elseif isa(ex, Expr) && ex.head == :call
if ex.args[1] == :zeros || ex.args[1] == :ones || ex.args[1] == :rand ||ex.args[1] == :randn
if length(ex.args) == 2
return quote
$(Expr(:meta, :inline))
$(esc(ex.args[1]))(MVector{$(esc(ex.args[2]))})
end
elseif length(ex.args) == 3
return quote
$(Expr(:meta, :inline))
$(esc(ex.args[1]))(MVector{$(esc(ex.args[3])), $(esc(ex.args[2]))})
end
else
error("@MVector expected a 1-dimensional array expression")
end
elseif ex.args[1] == :fill
if length(ex.args) == 3
return quote
$(Expr(:meta, :inline))
$(esc(ex.args[1]))($(esc(ex.args[2])), MVector{$(esc(ex.args[3]))})
end
else
error("@MVector expected a 1-dimensional array expression")
end
else
error("@MVector only supports the zeros(), ones(), fill(), rand() and randn() functions.")
end
else
error("Use @MVector [a,b,c] or @MVector([a,b,c])")
end
end