-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
functors.jl
211 lines (163 loc) · 7.11 KB
/
functors.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# This file is a part of Julia. License is MIT: http://julialang.org/license
###### Function Objects ("Functors") ######
# Note that function objects are merely used as internal machinery to
# enhance code reuse and improve performance of map/reduce.
# They are not exported.
# When function arguments can be inlined, the use of function objects
# can be removed.
abstract Func{N}
immutable IdFun <: Func{1} end
call(::IdFun, x) = x
immutable AbsFun <: Func{1} end
call(::AbsFun, x) = abs(x)
immutable Abs2Fun <: Func{1} end
call(::Abs2Fun, x) = abs2(x)
immutable ExpFun <: Func{1} end
call(::ExpFun, x) = exp(x)
immutable LogFun <: Func{1} end
call(::LogFun, x) = log(x)
immutable ConjFun <: Func{1} end
call(::ConjFun, x) = conj(x)
immutable AndFun <: Func{2} end
call(::AndFun, x, y) = x & y
immutable OrFun <: Func{2} end
call(::OrFun, x, y) = x | y
immutable XorFun <: Func{2} end
call(::XorFun, x, y) = x $ y
immutable AddFun <: Func{2} end
call(::AddFun, x, y) = x + y
immutable DotAddFun <: Func{2} end
call(::DotAddFun, x, y) = x .+ y
immutable SubFun <: Func{2} end
call(::SubFun, x, y) = x - y
immutable DotSubFun <: Func{2} end
call(::DotSubFun, x, y) = x .- y
immutable MulFun <: Func{2} end
call(::MulFun, x, y) = x * y
immutable DotMulFun <: Func{2} end
call(::DotMulFun, x, y) = x .* y
immutable RDivFun <: Func{2} end
call(::RDivFun, x, y) = x / y
immutable DotRDivFun <: Func{2} end
call(::DotRDivFun, x, y) = x ./ y
immutable LDivFun <: Func{2} end
call(::LDivFun, x, y) = x \ y
immutable IDivFun <: Func{2} end
call(::IDivFun, x, y) = div(x, y)
immutable ModFun <: Func{2} end
call(::ModFun, x, y) = mod(x, y)
immutable RemFun <: Func{2} end
call(::RemFun, x, y) = rem(x, y)
immutable DotRemFun <: Func{2} end
call(::RemFun, x, y) = x .% y
immutable PowFun <: Func{2} end
call(::PowFun, x, y) = x ^ y
immutable MaxFun <: Func{2} end
call(::MaxFun, x, y) = scalarmax(x,y)
immutable MinFun <: Func{2} end
call(::MinFun, x, y) = scalarmin(x, y)
immutable LessFun <: Func{2} end
call(::LessFun, x, y) = x < y
immutable MoreFun <: Func{2} end
call(::MoreFun, x, y) = x > y
immutable DotLSFun <: Func{2} end
call(::DotLSFun, x, y) = x .<< y
immutable DotRSFun <: Func{2} end
call(::DotRSFun, x, y) = x .>> y
# a fallback unspecialized function object that allows code using
# function objects to not care whether they were able to specialize on
# the function value or not
immutable UnspecializedFun{N} <: Func{N}
f::Function
end
call(f::UnspecializedFun{1}, x) = f.f(x)
call(f::UnspecializedFun{2}, x, y) = f.f(x,y)
# Special purpose functors
type Predicate{F} <: Func{1}
f::F
end
call(pred::Predicate, x) = pred.f(x)::Bool
immutable EqX{T} <: Func{1}
x::T
end
EqX{T}(x::T) = EqX{T}(x)
call(f::EqX, y) = f.x == y
#### Bitwise operators ####
# BitFunctors are functions that behave in the same bit-wise manner when applied
# to individual bits as well as integers, allowing them to be used in BitArrays
# Note that there are 16 possible pure two-argument logical functions,
# of which eight don't exist as a single function in Base (but six of those are trivial):
##############################################################################
## p = TTFF ## p = TTFF ##
## q = TFTF function bit-op ## q = TFTF function bit-op ##
## -------------------------------- ## --------------------------------- ##
## TTTT (true) p | ~p ## FFFF (false) p & ~p ##
## TTTF |, max p | q ## FFFT ??? ~(p | q) ##
## TTFT >=, ^ p | ~q ## FFTF < ~p & q ##
## TTFF (p) p ## FFTT (~p) ~p ##
## TFTT <= ~p | q ## FTFF > p & ~q ##
## TFTF (q) q ## FTFT (~q) ~q ##
## TFFT == ~(p $ q) ## FTTF $, != p $ q ##
## TFFF &, *, min p & q ## FTTT ??? ~(p & q) ##
##############################################################################
immutable BitFunctorUnary{T,F} <: Func{1} end
call(::BitFunctorUnary{true, true}, p) = p | ~p # Must work for bits and ints
call(::BitFunctorUnary{false, false}, p) = p & ~p # LLVM figures them out nicely
call(::BitFunctorUnary{true, false}, p) = p
call(::BitFunctorUnary{false, true}, p) = ~p
immutable BitFunctorBinary{TT,TF,FT,FF} <: Func{2} end
call(::BitFunctorBinary{true, true, true, true }, p, q) = p | ~p
call(::BitFunctorBinary{true, true, true, false}, p, q) = p | q
call(::BitFunctorBinary{true, true, false, true }, p, q) = p | ~q
call(::BitFunctorBinary{true, true, false, false}, p, q) = p
call(::BitFunctorBinary{true, false, true, true }, p, q) = ~p | q
call(::BitFunctorBinary{true, false, true, false}, p, q) = q
call(::BitFunctorBinary{true, false, false, true }, p, q) = ~(p $ q)
call(::BitFunctorBinary{true, false, false, false}, p, q) = p & q
call(::BitFunctorBinary{false, false, false, false}, p, q) = p & ~p
call(::BitFunctorBinary{false, false, false, true }, p, q) = ~(p | q)
call(::BitFunctorBinary{false, false, true, false}, p, q) = ~p & q
call(::BitFunctorBinary{false, false, true, true }, p, q) = ~p
call(::BitFunctorBinary{false, true, false, false}, p, q) = p & ~q
call(::BitFunctorBinary{false, true, false, true }, p, q) = ~q
call(::BitFunctorBinary{false, true, true, false}, p, q) = p $ q
call(::BitFunctorBinary{false, true, true, true }, p, q) = ~(p & q)
# Specializations by value
function specialized_unary(f::Function)
is(f, identity) ? IdFun() :
is(f, abs) ? AbsFun() :
is(f, abs2) ? Abs2Fun() :
is(f, exp) ? ExpFun() :
is(f, log) ? LogFun() :
UnspecializedFun{1}(f)
end
function specialized_binary(f::Function)
is(f, +) ? AddFun() :
is(f, -) ? SubFun() :
is(f, *) ? MulFun() :
is(f, /) ? RDivFun() :
is(f, \) ? LDivFun() :
is(f, ^) ? PowFun() :
is(f, &) ? AndFun() :
is(f, |) ? OrFun() :
is(f, div) ? IDivFun() :
UnspecializedFun{2}(f)
end
function specialized_bitwise_unary(f::Function)
is(f, identity) ? BitFunctorUnary{true, false}() :
is(f, !) | is(f, ~) ? BitFunctorUnary{false, true }() :
is(f, one) ? BitFunctorUnary{true, true }() :
is(f, zero) ? BitFunctorUnary{false, false}() :
UnspecializedFun{1}(f)
end
function specialized_bitwise_binary(f::Function)
is(f, &) | is(f, *) | is(f, min) ? BitFunctorBinary{true, false, false, false}() :
is(f, |) | is(f, max) ? BitFunctorBinary{true, true, true, false}() :
is(f, $) | is(f, !=) ? BitFunctorBinary{false, true, true, false}() :
is(f, >=) | is(f, ^) ? BitFunctorBinary{true, true, false, true }() :
is(f, <=) ? BitFunctorBinary{true, false, true, true }() :
is(f, ==) ? BitFunctorBinary{true, false, false, true }() :
is(f, <) ? BitFunctorBinary{false, false, true, false}() :
is(f, >) ? BitFunctorBinary{false, true, false, false}() :
UnspecializedFun{2}(f)
end