Skip to content

Commit b20ebda

Browse files
committed
implement operate_to!!(::BigInt, ::typeof(copy), ::T) for small int T
GMP natively supports integer types no wider than `Clong` or `Culong`, so make use of that. A followup PR may add support for generic subtypes of `Integer`, too. Fixes #354
1 parent c271f3f commit b20ebda

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

src/implementations/BigInt.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
# Base.BigInt.
99

1010
mutability(::Type{BigInt}) = IsMutable()
11+
mutability(::Type{BigInt}, ::Any, ::Vararg{Type}) = IsMutable()
1112

1213
# Copied from `deepcopy_internal` implementation in Julia:
1314
# https://github.com/JuliaLang/julia/blob/7d41d1eb610cad490cbaece8887f9bbd2a775021/base/gmp.jl#L772
@@ -17,8 +18,21 @@ mutable_copy(x::BigInt) = Base.GMP.MPZ.set(x)
1718

1819
promote_operation(::typeof(copy), ::Type{BigInt}) = BigInt
1920

20-
function operate_to!(out::BigInt, ::typeof(copy), in::BigInt)
21-
Base.GMP.MPZ.set!(out, in)
21+
function operate_to!(
22+
out::BigInt,
23+
::typeof(copy),
24+
in::Union{Bool,Int8,Int16,Int32,Clong,UInt8,UInt16,UInt32,Culong,BigInt},
25+
)
26+
let f!
27+
if in isa BigInt
28+
f! = Base.GMP.MPZ.set!
29+
elseif in isa Union{Bool,Unsigned}
30+
f! = Base.GMP.MPZ.set_ui!
31+
elseif in isa Signed
32+
f! = Base.GMP.MPZ.set_si!
33+
end
34+
f!(out, in)
35+
end
2236
return out
2337
end
2438

@@ -28,13 +42,13 @@ operate!(::typeof(copy), x::BigInt) = x
2842

2943
promote_operation(::typeof(zero), ::Type{BigInt}) = BigInt
3044

31-
operate!(::typeof(zero), x::BigInt) = Base.GMP.MPZ.set_si!(x, 0)
45+
operate!(::typeof(zero), x::BigInt) = operate_to!(x, copy, false)
3246

3347
# one
3448

3549
promote_operation(::typeof(one), ::Type{BigInt}) = BigInt
3650

37-
operate!(::typeof(one), x::BigInt) = Base.GMP.MPZ.set_si!(x, 1)
51+
operate!(::typeof(one), x::BigInt) = operate_to!(x, copy, true)
3852

3953
# +
4054

test/test_basics.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,49 @@ test_copy_Rational_Int() = _test_copy(Rational{Int})
6464

6565
test_copy_Rational_BigInt() = _test_copy(Rational{BigInt})
6666

67+
function test_copy_BigInt_smallint()
68+
function example_ints(t::Type{<:Integer})
69+
if t <: Signed
70+
[
71+
typemin(t),
72+
typemin(t) + t(1),
73+
t(-2),
74+
t(-1),
75+
t(0),
76+
t(1),
77+
t(2),
78+
typemax(t) - t(1),
79+
typemax(t),
80+
]
81+
elseif t <: Unsigned
82+
[t(0), t(1), t(2), typemax(t) - t(1), typemax(t)]
83+
elseif t == Bool
84+
[false, true]
85+
else
86+
throw(ArgumentError("unknown type"))
87+
end
88+
end
89+
@testset "`copy` small integer to `BigInt`" begin
90+
for f! in (MA.operate_to!, MA.operate_to!!)
91+
for typ in [Bool, Int8, Int16, Int32, UInt8, UInt16, UInt32]
92+
for x in example_ints(typ)
93+
@test let y = BigInt(3)
94+
x == @inferred f!(y, copy, x)
95+
end
96+
@test let y = BigInt(3)
97+
y === @inferred f!(y, copy, x)
98+
end
99+
let y = BigInt(3), x = typ(0), f! = f!
100+
alloc_test(0) do
101+
return f!(y, copy, x)
102+
end
103+
end
104+
end
105+
end
106+
end
107+
end
108+
end
109+
67110
function _test_mutating_step_range(::Type{T}) where {T}
68111
r = MA.MutatingStepRange(T(2), T(3), T(9))
69112
expected = MA.mutability(T) isa MA.IsMutable ? 8 * ones(T, 3) : T[2, 5, 8]

0 commit comments

Comments
 (0)