From 8f6a8a137534fde1d60e298a242d8f54678b42cc Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Mon, 12 Oct 2015 18:52:41 +0200 Subject: [PATCH] Allow operations mixing Nullable and scalar Makes op(x::Nullable, y) equivalent to op(x, Nullable(y)), but more efficient. --- src/operators.jl | 84 ++++++++++++++++++++++++++++++++++++++++++----- test/operators.jl | 9 +++++ 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index d8f0ec9..f4cf299 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -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.(:-)), @@ -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.(:<)), @@ -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 @@ -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) diff --git a/test/operators.jl b/test/operators.jl index 127fa1b..bd96edd 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -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 @@ -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 @@ -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