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).