I have a function that needs a Vector{Int}
for buffering, which I would like to reuse when I call that function over and over again in a loop. My idea was to create that vector outside and clearing it before every use. I had hoped that empty!
doesn’t change the vector’s capacity (similar to C++) and would have constant complexity (omit calling Int
destructors) without allocations (simply overwriting some length attribute).
However, empty!
isn’t “free”:
julia> tmp = Int[];
julia> @time empty!(tmp);
0.000036 seconds (4 allocations: 160 bytes)
How do I prevent allocation when clearing buffers?
What is the proper way to reuse those buffers?
A more elaborate example: consider computing the prime factorization of an integer
function factorize(n,
primes = Primes(2_000_000),
factors = Int[],
exponents = Int[])
n >= 4 || return [n], [1]
limit = floor(Int, sqrt(n))
for p in primes
p <= limit || break
n % p == 0 || continue
push!(factors, p)
push!(exponents, 0)
while n % p == 0
exponents[end] += 1
n ÷= p
n % p == 0 || break
exponents[end] += 1
n ÷= p
limit ÷= p
end
n != 1 || break
end
if n != 1
push!(factors, n)
push!(exponents, 1)
end
return factors, exponents
end
which is called very often when looking for the first number x = bar(n)
having at least 500 divisors:
function foo()
primes = Primes(2_000_000)
# buffers
f = Array{Int}(undef, length(primes)÷2)
e = similar(f)
n = 1
x = bar(n)
_, e = factorize(x, f, e)
while numdivisors(e) < 500
empty!(f)
empty!(e)
n += 1
x = bar(n)
_, e = factorize(t, primes, f, e)
end
x
end
An alternative would be to rewrite factorize
to be used like for (f, e) in primefactors(n, primes)
but that would be a rather big undertaking. Another way would be to replace all the push!
es and do all the index operations manually (plus returning the length in some form as resize!
isn’t free either).