-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathbeginend.jl
104 lines (88 loc) · 4.42 KB
/
beginend.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
struct LazyMath{T,F}
f::F
end
LazyMath{T}(f::F) where {T,F} = LazyMath{T,F}(f)
Base.show(io::IO, l::LazyMath{T}) where T = print(io, _print_f(T, l.f))
const BeginEndRangeVals = Union{Begin,End,LazyMath,Int}
# Ranges
abstract type AbstractBeginEndRange <: Function end
struct BeginEndRange{A<:BeginEndRangeVals,B<:BeginEndRangeVals} <: AbstractBeginEndRange
start::A
stop::B
end
struct BeginEndStepRange{A<:BeginEndRangeVals,B<:BeginEndRangeVals} <: AbstractBeginEndRange
start::A
step::Int
stop::B
end
Base.first(r::AbstractBeginEndRange) = r.start
Base.last(r::AbstractBeginEndRange) = r.stop
Base.step(r::BeginEndStepRange) = r.step
(::Colon)(a::Int, b::Union{Begin,End,Type{Begin},Type{End},LazyMath}) = BeginEndRange(a, _x(b))
(::Colon)(a::Union{Begin,End,Type{Begin},Type{End},LazyMath}, b::Int) = BeginEndRange(_x(a), b)
(::Colon)(a::Union{Begin,End,Type{Begin},Type{End},LazyMath}, b::Union{Begin,End,Type{Begin},Type{End},LazyMath}) =
BeginEndRange(_x(a), _x(b))
(::Colon)(a::Union{Int,LazyMath}, step::Int, b::Union{Type{Begin},Type{End}}) = BeginEndStepRange(a, step, _x(b))
(::Colon)(a::Union{Type{Begin},Type{End}}, step::Int, b::Union{Int,LazyMath}) = BeginEndStepRange(_x(a), step, b)
(::Colon)(a::Union{Type{Begin},Type{End}}, step::Int, b::Union{Type{Begin},Type{End}}) =
BeginEndStepRange(_x(a), step, _x(b))
_x(T::Type) = T()
_x(x) = x
Base.to_indices(A, inds, (r, args...)::Tuple{BeginEndRange,Vararg}) =
(_to_index(inds[1], r.start):_to_index(inds[1], r.stop), to_indices(A, Base.tail(inds), args)...)
Base.to_indices(A, inds, (r, args...)::Tuple{BeginEndStepRange,Vararg}) =
(_to_index(inds[1], r.start):r.step:_to_index(inds[1], r.stop), to_indices(A, Base.tail(inds), args)...)
Base.to_indices(A, inds, (r, args...)::Tuple{<:Union{Begin,End,<:LazyMath},Vararg}) =
(_to_index(inds[1], r), to_indices(A, Base.tail(inds), args)...)
_to_index(inds, a::Int) = a
_to_index(inds, ::Begin) = first(inds)
_to_index(inds, ::End) = last(inds)
_to_index(inds, ::Type{Begin}) = first(inds)
_to_index(inds, ::Type{End}) = last(inds)
_to_index(inds, l::LazyMath{End}) = l.f(last(inds))
_to_index(inds, l::LazyMath{Begin}) = l.f(first(inds))
Base.checkindex(::Type{Bool}, inds::AbstractUnitRange, ber::AbstractBeginEndRange) =
Base.checkindex(Bool, inds, _to_index(inds, first(ber)):_to_index(inds, last(ber)))
for f in (:+, :-, :*, :÷, :|, :&)
@eval Base.$f(::Type{T}, i::Int) where T <: Union{Begin,End} = LazyMath{T}(Base.Fix2($f, i))
@eval Base.$f(i::Int, ::Type{T}) where T <: Union{Begin,End} = LazyMath{T}(Base.Fix1($f, i))
@eval Base.$f(::T, i::Int) where T <: Union{Begin,End} = LazyMath{T}(Base.Fix2($f, i))
@eval Base.$f(i::Int, ::T) where T <: Union{Begin,End} = LazyMath{T}(Base.Fix1($f, i))
@eval Base.$f(x::LazyMath{T}, i::Int) where T = LazyMath{T}(Base.Fix2(x.f ∘ $f, i))
@eval Base.$f(i::Int, x::LazyMath{T}) where T = LazyMath{T}(Base.Fix1(x.f ∘ $f, i))
end
Base.show(io::IO, ::MIME"text/plain", r::AbstractBeginEndRange) = show(io, r)
function Base.show(io::IO, r::BeginEndRange)
_show(io, first(r))
print(io, ':')
_show(io, last(r))
end
function Base.show(io::IO, r::BeginEndStepRange)
_show(io, first(r))
print(io, ':')
show(io, step(r))
print(io, ':')
_show(io, last(r))
end
_show(io, x::Union{Begin,End}) = show(io, typeof(x))
_show(io, x) = show(io, x)
# Here we recursively print `Fix1` and `Fix2` either left or right
# to recreate the function
_print_f(T, f) = string(T, _pf(f))
_print_f(T, f::Base.ComposedFunction) = string('(', _print_f(T, f.outer), ')', _print_f("", f.inner))
_print_f(T, f::Base.Fix1) = string(f.x, _print_f(T, f.f))
_print_f(T, f::Base.Fix2) = string(_print_f(T, f.f), f.x)
_pf(::typeof(div)) = "÷"
_pf(f) = string(f)
for T in (UnitRange, AbstractUnitRange, StepRange, StepRangeLen, LinRange, Lookup)
for f in (:getindex, :view, :dotview)
@eval Base.$f(A::$T, i::AbstractBeginEndRange) = Base.$f(A, to_indices(A, (i,))...)
@eval Base.$f(A::$T, i::Union{Type{Begin},Type{End},Begin,End,LazyMath}) =
Base.$f(A, to_indices(A, _construct_types(i))...)
end
end
# These methods let us use Begin End end as types without constructing them.
@inline _construct_types(::Type{Begin}, I...) = (Begin(), _construct_types(I...)...)
@inline _construct_types(::Type{End}, I...) = (End(), _construct_types(I...)...)
@inline _construct_types(i, I...) = (i, _construct_types(I...)...)
@inline _construct_types() = ()