Skip to content
This repository has been archived by the owner on May 4, 2019. It is now read-only.

Allow operations mixing Nullable and scalar #85

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 75 additions & 9 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,40 @@ for f in (
end

# Implement the binary operators: +, -, *, /, %, &, |, ^, <<, and >>
# Prevent ambiguities with Base
@inline function Base.(:^){S1, S2<:Integer}(x::Nullable{S1}, y::S2)
if isbits(S1) & isbits(S2)
Nullable(^(x.value, y), x.isnull)
else
throw_error()
end
end

for f in (
:(Base.(:<<)),
:(Base.(:>>))
)
@eval begin
@inline function $(f){S1}(x::Nullable{S1}, y::Int)
if isbits(S1)
Nullable($(f)(x.value, y), x.isnull)
else
throw_error()
end
end
end

@eval begin
@inline function $(f){S1, T<:Integer}(x::Nullable{S1}, y::T)
if isbits(S1) && isbits(T)
Nullable($(f)(x.value, y), x.isnull)
else
throw_error()
end
end
end
end

for f in (
:(Base.(:+)),
:(Base.(:-)),
Expand All @@ -40,24 +74,38 @@ for f in (
end
end
end
end

# Implement the binary operators: == and !=
for f in (
:(Base.(:(==))),
:(Base.(:!=)),
)
@eval begin
function $(f){S1, S2}(x::Nullable{S1}, y::Nullable{S2})
@inline function $(f){S1, S2}(x::Nullable{S1}, y::S2)
if isbits(S1) & isbits(S2)
Nullable{Bool}($(f)(x.value, y.value), x.isnull | y.isnull)
Nullable($(f)(x.value, y), x.isnull)
else
error()
throw_error()
end
end
end
end

# Implement the binary operators: == and !=
# Prevent ambiguity with Base
Base.(:(==))(x::Nullable, y::WeakRef) = x == y.value

function Base.(:(==)){S1, S2}(x::Nullable{S1}, y::Nullable{S2})
if isbits(S1) & isbits(S2)
Nullable{Bool}(x.value == y.value, x.isnull | y.isnull)
else
error()
end
end

function Base.(:(==)){S1, S2}(x::Nullable{S1}, y::S2)
if isbits(S1) & isbits(S2)
Nullable{Bool}(x.value == y, x.isnull)
else
error()
end
end

# Implement the binary operators: <, >, <=, and >=
for f in (
:(Base.(:<)),
Expand All @@ -74,6 +122,16 @@ for f in (
end
end
end

@eval begin
function $(f){S1, S2}(x::Nullable{S1}, y::S2)
if isbits(S1) & isbits(S2)
Nullable{Bool}($(f)(x.value, y), x.isnull)
else
error()
end
end
end
end

# Miscellaneous lifted operators
Expand Down Expand Up @@ -112,6 +170,14 @@ function Base.call{S1, S2}(::Base.MinFun, x::Nullable{S1}, y::Nullable{S2})
end
end

function Base.call{S1, S2}(::Base.MinFun, x::Nullable{S1}, y::Nullable{S2})
if isbits(S1) & isbits(S2)
return Nullable(Base.scalarmin(x.value, y.value), x.isnull | y.isnull)
else
error()
end
end

function Base.call{S1, S2}(::Base.MaxFun, x::Nullable{S1}, y::Nullable{S2})
if isbits(S1) & isbits(S2)
return Nullable(Base.scalarmax(x.value, y.value), x.isnull | y.isnull)
Expand Down
9 changes: 9 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ module TestOperators
x = op(Nullable(v), Nullable(w))
@test_approx_eq x.value op(v, w)
@test !x.isnull
y = op(Nullable(v), w)
@test_approx_eq y.value op(v, w)
@test !y.isnull
@test_throws ErrorException op(Nullable(rand(1)), Nullable(rand(1)))
end

Expand All @@ -58,6 +61,9 @@ module TestOperators
x = op(Nullable(v), Nullable(w))
@test_approx_eq x.value op(v, w)
@test !x.isnull
y = op(Nullable(v), w)
@test_approx_eq y.value op(v, w)
@test !y.isnull
@test_throws ErrorException op(Nullable(rand(Bool, 1)), Nullable(rand(Bool, 1)))
end

Expand All @@ -70,6 +76,9 @@ module TestOperators
x = op(Nullable(v), Nullable(w))
@test_approx_eq x.value op(v, w)
@test !x.isnull
y = op(Nullable(v), w)
@test_approx_eq y.value op(v, w)
@test !y.isnull
@test_throws ErrorException op(Nullable(rand(Int, 1)), Nullable(rand(Int, 1)))
end
end