diff --git a/src/implementations/BigInt.jl b/src/implementations/BigInt.jl index feaec50..4bf0966 100644 --- a/src/implementations/BigInt.jl +++ b/src/implementations/BigInt.jl @@ -8,6 +8,7 @@ # Base.BigInt. mutability(::Type{BigInt}) = IsMutable() +mutability(::Type{BigInt}, ::typeof(copy), ::Vararg{Type}) = IsMutable() # Copied from `deepcopy_internal` implementation in Julia: # https://github.com/JuliaLang/julia/blob/7d41d1eb610cad490cbaece8887f9bbd2a775021/base/gmp.jl#L772 @@ -17,8 +18,21 @@ mutable_copy(x::BigInt) = Base.GMP.MPZ.set(x) promote_operation(::typeof(copy), ::Type{BigInt}) = BigInt -function operate_to!(out::BigInt, ::typeof(copy), in::BigInt) - Base.GMP.MPZ.set!(out, in) +function operate_to!( + out::BigInt, + ::typeof(copy), + in::Union{Bool,Int8,Int16,Int32,Clong,UInt8,UInt16,UInt32,Culong,BigInt}, +) + let f! + if in isa BigInt + f! = Base.GMP.MPZ.set! + elseif in isa Union{Bool,Unsigned} + f! = Base.GMP.MPZ.set_ui! + elseif in isa Signed + f! = Base.GMP.MPZ.set_si! + end + f!(out, in) + end return out end @@ -28,13 +42,13 @@ operate!(::typeof(copy), x::BigInt) = x promote_operation(::typeof(zero), ::Type{BigInt}) = BigInt -operate!(::typeof(zero), x::BigInt) = Base.GMP.MPZ.set_si!(x, 0) +operate!(::typeof(zero), x::BigInt) = operate_to!(x, copy, false) # one promote_operation(::typeof(one), ::Type{BigInt}) = BigInt -operate!(::typeof(one), x::BigInt) = Base.GMP.MPZ.set_si!(x, 1) +operate!(::typeof(one), x::BigInt) = operate_to!(x, copy, true) # + diff --git a/test/test_basics.jl b/test/test_basics.jl index 7bbf154..57efa6c 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -64,6 +64,49 @@ test_copy_Rational_Int() = _test_copy(Rational{Int}) test_copy_Rational_BigInt() = _test_copy(Rational{BigInt}) +function test_copy_BigInt_smallint() + function example_ints(t::Type{<:Integer}) + if t <: Signed + [ + typemin(t), + typemin(t) + t(1), + t(-2), + t(-1), + t(0), + t(1), + t(2), + typemax(t) - t(1), + typemax(t), + ] + elseif t <: Unsigned + [t(0), t(1), t(2), typemax(t) - t(1), typemax(t)] + elseif t == Bool + [false, true] + else + throw(ArgumentError("unknown type")) + end + end + @testset "`copy` small integer to `BigInt`" begin + for f! in (MA.operate_to!, MA.operate_to!!) + for typ in [Bool, Int8, Int16, Int32, UInt8, UInt16, UInt32] + for x in example_ints(typ) + @test let y = BigInt(3) + x == @inferred f!(y, copy, x) + end + @test let y = BigInt(3) + y === @inferred f!(y, copy, x) + end + let y = BigInt(3), x = typ(0), f! = f! + alloc_test(0) do + return f!(y, copy, x) + end + end + end + end + end + end +end + function _test_mutating_step_range(::Type{T}) where {T} r = MA.MutatingStepRange(T(2), T(3), T(9)) expected = MA.mutability(T) isa MA.IsMutable ? 8 * ones(T, 3) : T[2, 5, 8]