Skip to content

Commit

Permalink
Switch type parameters for AnchoredInterval
Browse files Browse the repository at this point in the history
  • Loading branch information
omus committed Mar 8, 2018
1 parent bcde3f7 commit 77a4944
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 149 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
This package defines:
* `AbstractInterval`, along with its subtypes:
* `Interval{T}`, which represents a non-iterable range between two endpoints of type `T`
* `AnchoredInterval{P, T}`, which represents a non-iterable range defined by a single
* `AnchoredInterval{T, P}`, which represents a non-iterable range defined by a single
value `anchor::T` and the value type `P` which represents the size of the range
* `HourEnding`, a type alias for `AnchoredInterval{Hour(-1)}`
* `HourBeginning`, a type alias for `AnchoredInterval{Hour(1)}`
* `HourEnding`, a type alias for `AnchoredInterval{T, Hour(-1)}`
* `HourBeginning`, a type alias for `AnchoredInterval{T, Hour(1)}`
* `HE` and `HB`, pseudoconstructors for `HourEnding` and `HourBeginning` that round the
anchor up (`HE`) or down (`HB`) to the nearest hour
* `Inclusivity`, which represents whether an `AbstractInterval` is open, half-open, or
Expand Down
6 changes: 3 additions & 3 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
This package defines:
* `AbstractInterval`, along with its subtypes:
* `Interval{T}`, which represents a non-iterable range between two endpoints of type `T`
* `AnchoredInterval{P, T}`, which represents a non-iterable range defined by a single
* `AnchoredInterval{T, P}`, which represents a non-iterable range defined by a single
value `anchor::T` and the value type `P` which represents the size of the range
* `HourEnding`, a type alias for `AnchoredInterval{Hour(-1), T}`
* `HourBeginning`, a type alias for `AnchoredInterval{Hour(1), T}`
* `HourEnding`, a type alias for `AnchoredInterval{T, Hour(-1)}`
* `HourBeginning`, a type alias for `AnchoredInterval{T, Hour(1)}`
* `HE` and `HB`, pseudoconstructors for `HourEnding` and `HourBeginning` that round the
anchor up (`HE`) or down (`HB`) to the nearest hour
* `Inclusivity`, which represents whether an `AbstractInterval` is open, half-open, or
Expand Down
91 changes: 49 additions & 42 deletions src/anchoredinterval.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Base.Dates: value, coarserperiod

"""
AnchoredInterval{P, T}(anchor::T, [inclusivity::Inclusivity]) where {P, T} -> AnchoredInterval{P, T}
AnchoredInterval{P, T}(anchor::T, [closed_left::Bool, closed_right::Bool]) where {P, T} -> AnchoredInterval{P, T}
AnchoredInterval{T, P}(anchor::T, [inclusivity::Inclusivity]) -> AnchoredInterval{T, P}
AnchoredInterval{T, P}(anchor::T, [closed_left::Bool, closed_right::Bool]) -> AnchoredInterval{T, P}
AnchoredInterval(anchor::T, P, [inclusivity::Inclusivity]) -> AnchoredInterval{T, P}
AnchoredInterval(anchor::T, P, [closed_left::Bool, closed_right::Bool]) -> AnchoredInterval{T, P}
`AnchoredInterval` is a subtype of `AbstractInterval` that represents a non-iterable range
or span of values defined not by two endpoints but instead by a single `anchor` point and
Expand All @@ -21,8 +24,8 @@ included for positive values of `P` and the greater endpoint included for negati
range of values. This happens most often with dates and times, where "HE15" is often used as
shorthand for (14:00..15:00].
To this end, `HourEnding` is a type alias for `AnchoredInterval{Hour(-1)}`. Similarly,
`HourBeginning` is a type alias for `AnchoredInterval{Hour(1)}`.
To this end, `HourEnding` is a type alias for `AnchoredInterval{T, Hour(-1)} where T`.
Similarly, `HourBeginning` is a type alias for `AnchoredInterval{T, Hour(1)} where T`.
### Rounding
Expand All @@ -48,44 +51,42 @@ HourBeginning{DateTime}(2016-08-11T02:00:00, Inclusivity(true, false))
### Example
```julia
julia> AnchoredInterval{Hour(-1)}(DateTime(2016, 8, 11, 12))
julia> AnchoredInterval(DateTime(2016, 8, 11, 12), Hour(-1))
HourEnding{DateTime}(2016-08-11T12:00:00, Inclusivity(false, true))
julia> AnchoredInterval{Day(1)}(DateTime(2016, 8, 11))
AnchoredInterval{1 day, DateTime}(2016-08-11T00:00:00, Inclusivity(true, false))
julia> AnchoredInterval(DateTime(2016, 8, 11), Day(1))
AnchoredInterval{DateTime, 1 day}(2016-08-11T00:00:00, Inclusivity(true, false))
julia> AnchoredInterval{Minute(5)}(DateTime(2016, 8, 11, 12, 30), true, true)
AnchoredInterval{5 minutes, DateTime}(2016-08-11T12:30:00, Inclusivity(true, true))
julia> AnchoredInterval(DateTime(2016, 8, 11, 12, 30), Minute(5), true, true)
AnchoredInterval{DateTime, 5 minutes}(2016-08-11T12:30:00, Inclusivity(true, true))
```
See also: [`Interval`](@ref), [`Inclusivity`](@ref), [`HE`](@ref), [`HB`](@ref)
"""
struct AnchoredInterval{P, T} <: AbstractInterval{T}
struct AnchoredInterval{T, P} <: AbstractInterval{T}
anchor::T
inclusivity::Inclusivity
end

# When an interval is anchored to the lesser endpoint, default to Inclusivity(false, true)
# When an interval is anchored to the greater endpoint, default to Inclusivity(true, false)
function AnchoredInterval{P, T}(i::T) where {P, T}
return AnchoredInterval{P, T}(i::T, Inclusivity(P zero(P), P zero(P)))
function AnchoredInterval{T, P}(i::T) where {T, P}
return AnchoredInterval{T, P}(i::T, Inclusivity(P zero(P), P zero(P)))
end

AnchoredInterval{P}(i::T, inc::Inclusivity) where {P, T} = AnchoredInterval{P, T}(i, inc)
AnchoredInterval{P}(i::T) where {P, T} = AnchoredInterval{P, T}(i)

function AnchoredInterval{P, T}(i::T, x::Bool, y::Bool) where {P, T}
return AnchoredInterval{P, T}(i, Inclusivity(x, y))
function AnchoredInterval{T, P}(i::T, x::Bool, y::Bool) where {T, P}
return AnchoredInterval{T, P}(i, Inclusivity(x, y))
end

function AnchoredInterval{P}(i::T, x::Bool, y::Bool) where {P, T}
return AnchoredInterval{P, T}(i, Inclusivity(x, y))
end
AnchoredInterval(i::T, span, inc::Inclusivity) where T = AnchoredInterval{T, span}(i, inc)
AnchoredInterval(i::T, span, x::Bool, y::Bool) where T = AnchoredInterval{T, span}(i, x, y)
AnchoredInterval(i::T, span) where T = AnchoredInterval{T, span}(i)


const HourEnding{T} = AnchoredInterval{Hour(-1), T} where T <: TimeType
const HourEnding{T} = AnchoredInterval{T, Hour(-1)} where T <: TimeType
HourEnding(a::T, args...) where T = HourEnding{T}(a, args...)

const HourBeginning{T} = AnchoredInterval{Hour(1), T} where T <: TimeType
const HourBeginning{T} = AnchoredInterval{T, Hour(1)} where T <: TimeType
HourBeginning(a::T, args...) where T = HourBeginning{T}(a, args...)

"""
Expand All @@ -104,32 +105,38 @@ nearest hour.
"""
HB(a, args...) = HourBeginning(floor(a, Hour), args...)

function Base.copy(x::AnchoredInterval{P, T}) where {P, T}
return AnchoredInterval{P, T}(anchor(x), inclusivity(x))
function Base.copy(x::AnchoredInterval{T, P}) where {T, P}
return AnchoredInterval{T, P}(anchor(x), inclusivity(x))
end

##### ACCESSORS #####

Base.first(interval::AnchoredInterval{P}) where P = min(interval.anchor, interval.anchor+P)
Base.last(interval::AnchoredInterval{P}) where P = max(interval.anchor, interval.anchor+P)
function Base.first(interval::AnchoredInterval{T, P}) where {T, P}
min(interval.anchor, interval.anchor + P)
end

function Base.last(interval::AnchoredInterval{T, P}) where {T, P}
max(interval.anchor, interval.anchor + P)
end

anchor(interval::AnchoredInterval) = interval.anchor
span(interval::AnchoredInterval{P}) where P = abs(P)
span(interval::AnchoredInterval{T, P}) where {T, P} = abs(P)

##### CONVERSION #####

function Base.convert(::Type{Interval}, interval::AnchoredInterval{P, T}) where {P, T}
function Base.convert(::Type{Interval}, interval::AnchoredInterval{T}) where T
return Interval{T}(first(interval), last(interval), inclusivity(interval))
end

function Base.convert(::Type{Interval{T}}, interval::AnchoredInterval{P, T}) where {P, T}
function Base.convert(::Type{Interval{T}}, interval::AnchoredInterval{T}) where T
return Interval{T}(first(interval), last(interval), inclusivity(interval))
end

Base.convert(::Type{T}, interval::AnchoredInterval{P, T}) where {P, T} = anchor(interval)
Base.convert(::Type{T}, interval::AnchoredInterval{T}) where T = anchor(interval)

# Date/DateTime attempt to convert to Int64 instead of falling back to convert(T, ...)
Base.Date(interval::AnchoredInterval{P, Date}) where P = convert(Date, interval)
Base.DateTime(interval::AnchoredInterval{P, DateTime}) where P = convert(DateTime, interval)
Base.Date(interval::AnchoredInterval{Date}) = convert(Date, interval)
Base.DateTime(interval::AnchoredInterval{DateTime}) = convert(DateTime, interval)

##### DISPLAY #####

Expand All @@ -139,8 +146,8 @@ Base.show(io::IO, ::Type{HourBeginning}) = print(io, "HourBeginning{T}")
Base.show(io::IO, ::Type{HourEnding{T}}) where T <: TimeType = print(io, "HourEnding{$T}")
Base.show(io::IO, ::Type{HourBeginning{T}}) where T <: TimeType = print(io, "HourBeginning{$T}")

function Base.show(io::IO, ::Type{AnchoredInterval{P, T}}) where {P, T}
print(io, "AnchoredInterval{$P, $T}")
function Base.show(io::IO, ::Type{AnchoredInterval{T, P}}) where {T, P}
print(io, "AnchoredInterval{$T, $P}")
end

function Base.show(io::IO, interval::T) where T <: AnchoredInterval
Expand All @@ -155,7 +162,7 @@ function Base.show(io::IO, interval::T) where T <: AnchoredInterval
end
end

function Base.print(io::IO, interval::AnchoredInterval{P, T}) where {P, T <: TimeType}
function Base.print(io::IO, interval::AnchoredInterval{<:TimeType})
# Print to io in order to keep properties like :limit and :compact
if get(io, :compact, false)
io = IOContext(io, :limit=>true)
Expand All @@ -174,11 +181,11 @@ Base.:-(a::AnchoredInterval, b) = a + -b
# Required for StepRange{<:AnchoredInterval}
Base.:-(a::AnchoredInterval, b::AnchoredInterval) = anchor(a) - anchor(b)

Base.:-(a::T, b::AnchoredInterval{P, T}) where {P, T <: Number} = a + -b
Base.:-(a::T, b::AnchoredInterval{T}) where {T <: Number} = a + -b

function Base.:-(a::AnchoredInterval{P, T}) where {P, T <: Number}
function Base.:-(a::AnchoredInterval{T, P}) where {T <: Number, P}
inc = inclusivity(a)
AnchoredInterval{-P, T}(-anchor(a), Inclusivity(last(inc), first(inc)))
AnchoredInterval{T, -P}(-anchor(a), Inclusivity(last(inc), first(inc)))
end

##### RANGE #####
Expand All @@ -189,7 +196,7 @@ function Base.steprem(a::T, b::T, c) where {T <: AnchoredInterval}
end

# Infer step for two-argument StepRange{<:AnchoredInterval}
function Base.colon(start::AnchoredInterval{P, T}, stop::AnchoredInterval{P, T}) where {P,T}
function Base.colon(start::AnchoredInterval{T, P}, stop::AnchoredInterval{T, P}) where {T,P}
return colon(start, abs(P), stop)
end

Expand All @@ -199,11 +206,11 @@ end

##### SET OPERATIONS #####

function Base.isempty(interval::AnchoredInterval{P, T}) where {P, T}
function Base.isempty(interval::AnchoredInterval{T, P}) where {T, P}
return P == zero(P) && !isclosed(interval)
end

function Base.intersect(a::AnchoredInterval{P, T}, b::AnchoredInterval{Q, T}) where {P,Q,T}
function Base.intersect(a::AnchoredInterval{T, P}, b::AnchoredInterval{T, Q}) where {T,P,Q}
interval = invoke(intersect, Tuple{AbstractInterval{T}, AbstractInterval{T}}, a, b)

sp = isa(P, Period) ? canonicalize(typeof(P), span(interval)) : span(interval)
Expand All @@ -215,7 +222,7 @@ function Base.intersect(a::AnchoredInterval{P, T}, b::AnchoredInterval{Q, T}) wh
new_P = sp
end

return AnchoredInterval{new_P, T}(anchor, inclusivity(interval))
return AnchoredInterval{T, new_P}(anchor, inclusivity(interval))
end

##### UTILITIES #####
Expand Down
8 changes: 5 additions & 3 deletions src/description.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using Base.Dates: value, coarserperiod

description(interval::AnchoredInterval{P}) where P = description(interval, P > zero(P) ? "B" : "E")
function description(interval::AnchoredInterval{T, P}) where {T, P}
description(interval, P > zero(P) ? "B" : "E")
end

function description(interval::AnchoredInterval{P, T}, s::String) where {P, T}
function description(interval::AnchoredInterval{T, P}, s::String) where {T, P}
return string(
first(inclusivity(interval)) ? '[' : '(',
description(anchor(interval), abs(P), s),
last(inclusivity(interval)) ? ']' : ')',
)
end

function description(interval::AnchoredInterval{P, ZonedDateTime}, s::String) where P
function description(interval::AnchoredInterval{ZonedDateTime, P}, s::String) where P
return string(
first(inclusivity(interval)) ? '[' : '(',
description(anchor(interval), abs(P), s),
Expand Down
Loading

0 comments on commit 77a4944

Please sign in to comment.