Skip to content

Commit 9a4d3ea

Browse files
authored
Merge pull request #3 from JuliaMath/teh/axisarrays
Add features for supporting AxisArrays
2 parents 5da8cf9 + 024f3f5 commit 9a4d3ea

File tree

3 files changed

+61
-9
lines changed

3 files changed

+61
-9
lines changed

src/IntervalSets.jl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,29 @@ module IntervalSets
44

55
# package code goes here
66

7-
import Base: show, in, length, isempty, isequal, issubset, ==, union, intersect
7+
using Base: @pure
8+
import Base: eltype, convert, show, in, length, isempty, isequal, issubset, ==, hash, union, intersect, minimum, maximum
89

9-
export ClosedInterval, , .., ±, ordered
10+
export AbstractInterval, ClosedInterval, , .., ±, ordered
11+
12+
abstract AbstractInterval{T}
1013

1114
include("closed.jl")
1215

16+
eltype{T}(::Type{AbstractInterval{T}}) = T
17+
@pure eltype{I<:AbstractInterval}(::Type{I}) = eltype(supertype(I))
18+
19+
convert{I<:AbstractInterval}(::Type{I}, i::I) = i
20+
function convert{I<:AbstractInterval}(::Type{I}, i::AbstractInterval)
21+
T = eltype(I)
22+
I(convert(T, i.left), convert(T, i.right))
23+
end
24+
1325
ordered{T}(a::T, b::T) = ifelse(a < b, (a, b), (b, a))
1426
ordered(a, b) = ordered(promote(a, b)...)
1527

28+
checked_conversion{T}(::Type{T}, a, b) = _checked_conversion(T, convert(T, a), convert(T, b))
29+
_checked_conversion{T}(::Type{T}, a::T, b::T) = a, b
30+
_checked_conversion{T}(::Type{T}, a, b) = throw(ArgumentError("$a and $b are not both of type $T"))
31+
1632
end # module

src/closed.jl

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
"""
2-
A `ClosedInterval(left, right)` is an interval set that includes both its upper and lower bounds. In
2+
A `ClosedInterval(left, right)` is an interval set that includes both its upper and lower bounds. In
33
mathematical notation, the constructed range is `[left, right]`.
44
"""
5-
immutable ClosedInterval{T}
5+
immutable ClosedInterval{T} <: AbstractInterval{T}
66
left::T
77
right::T
8+
9+
ClosedInterval(l::T, r::T) = new(l, r)
10+
end
11+
12+
ClosedInterval{T}(left::T, right::T) = ClosedInterval{T}(left, right)
13+
(::Type{ClosedInterval{T}}){T}(left, right) =
14+
ClosedInterval{T}(checked_conversion(T, left, right)...)
15+
16+
function ClosedInterval(left, right)
17+
# Defining this as ClosedInterval(promote(left, right)...) has one problem:
18+
# if left and right do not promote to a common type, it triggers a StackOverflow.
19+
T = promote_type(typeof(left), typeof(right))
20+
ClosedInterval{T}(checked_conversion(T, left, right)...)
821
end
922

10-
ClosedInterval(left, right) = ClosedInterval(promote(left, right)...)
23+
ClosedInterval(i::AbstractInterval) = convert(ClosedInterval{eltype(i)}, i)
24+
(::Type{ClosedInterval{T}}){T}(i::AbstractInterval) = convert(ClosedInterval{T}, i)
1125

1226
..(x, y) = ClosedInterval(x, y)
1327

@@ -17,13 +31,21 @@ ClosedInterval(left, right) = ClosedInterval(promote(left, right)...)
1731
show(io::IO, I::ClosedInterval) = print(io, I.left, "..", I.right)
1832

1933
in(v, I::ClosedInterval) = I.left <= v <= I.right
34+
in(a::ClosedInterval, b::ClosedInterval) = (b.left <= a.left) & (a.right <= b.right)
2035

2136
isempty(A::ClosedInterval) = A.left > A.right
2237

2338
isequal(A::ClosedInterval, B::ClosedInterval) = (isequal(A.left, B.left) & isequal(A.right, B.right)) | (isempty(A) & isempty(B))
2439

2540
==(A::ClosedInterval, B::ClosedInterval) = (A.left == B.left && A.right == B.right) || (isempty(A) && isempty(B))
2641

42+
const _closed_interval_hash = UInt == UInt64 ? 0x1588c274e0a33ad4 : 0x1e3f7252
43+
44+
hash(I::ClosedInterval, h::UInt) = hash(I.left, hash(I.right, hash(_closed_interval_hash, h)))
45+
46+
minimum(I::ClosedInterval) = I.left
47+
maximum(I::ClosedInterval) = I.right
48+
2749
function intersect(A::ClosedInterval, B::ClosedInterval)
2850
left = max(A.left, B.left)
2951
right = min(A.right, B.right)

test/runtests.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,28 @@ using Base.Test
88
@test ordered(Float16(1), 2) == (1, 2)
99

1010
@testset "Closed Sets" begin
11+
@test_throws ArgumentError :a .. "b"
1112
I = 0..3
1213
print(io, I)
13-
@test String(io) == "0..3"
14+
@test takebuf_string(io) == "0..3"
1415
J = 3..2
1516
K = 5..4
1617
L = 3 ± 2
1718
M = ClosedInterval(2, 5.0)
18-
takebuf_array(io)
1919
print(io, M)
20-
@test String(io) == "2.0..5.0"
20+
@test takebuf_string(io) == "2.0..5.0"
2121
N = ClosedInterval(UInt8(255), 300)
2222
O = CartesianIndex(1, 2, 3, 4) ± 2
2323
@test O == (-1..3, 0..4, 1..5, 2..6)
2424

25+
@test eltype(I) == Int
26+
@test eltype(M) == Float64
27+
@test convert(ClosedInterval{Float64}, I) === 0.0..3.0
28+
@test !(convert(ClosedInterval{Float64}, I) === 0..3)
29+
@test ClosedInterval{Float64}(1,3) === 1.0..3.0
30+
@test ClosedInterval(0.5..2.5) === 0.5..2.5
31+
@test ClosedInterval{Int}(1.0..3.0) === 1..3
32+
2533
@test !isempty(I)
2634
@test isempty(J)
2735
@test J == K
@@ -33,9 +41,13 @@ using Base.Test
3341
@test isequal(J, K)
3442

3543
@test typeof(M.left) == typeof(M.right) && typeof(M.left) == Float64
36-
@test typeof(N.left) == typeof(N.right) && typeof(N.left) == Int
44+
@test typeof(N.left) == typeof(N.right) && typeof(N.left) == Int
45+
46+
@test maximum(I) === 3
47+
@test minimum(I) === 0
3748

3849
@test 2 in I
50+
@test 1..2 in 0.5..2.5
3951

4052
@test I L == ClosedInterval(0, 5)
4153
@test I L == ClosedInterval(1, 3)
@@ -59,5 +71,7 @@ using Base.Test
5971
@test (ClosedInterval(7, 9) I) == false
6072
@test I I
6173
@test I ClosedInterval(1, 2)
74+
75+
@test hash(1..3) == hash(1.0..3.0)
6276
end
6377
end

0 commit comments

Comments
 (0)