Skip to content

Commit

Permalink
Merge pull request #11740 from JuliaLang/dcjones/bitvector-reverse
Browse files Browse the repository at this point in the history
Faster reverse!(::BitVector)
  • Loading branch information
StefanKarpinski committed Jun 18, 2015
2 parents e2d9150 + 7431253 commit 2533771
Showing 1 changed file with 45 additions and 19 deletions.
64 changes: 45 additions & 19 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1146,31 +1146,57 @@ function reverse_bits(src::UInt64)
end

function reverse!(B::BitVector)
# Basic idea: each chunk is divided into two blocks of size k = n % 64, and
# h = 64 - k. Walk from either end (with indexes i and j) reversing chunks
# and seperately ORing their two blocks into place.
#
# chunk 3 chunk 2 chunk 1
# ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
# │000000000000000│ E ││ D │ C ││ B │ A │
# └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
# k h k h k
# yielding;
# ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
# │000000000000000│ A' ││ B' │ C' ││ D' │ E' │
# └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘

n = length(B)
n == 0 && return B
if n == 0
return B
end

pnc = length(B.chunks) & 1
hnc = (length(B.chunks) >>> 1)
k = _mod64(n+63) + 1
h = 64 - k

aux_chunks = Array(UInt64, 1)
i, j = 0, length(B.chunks)
u = UInt64(0)
v = reverse_bits(B.chunks[j])
B.chunks[j] = 0
@inbounds while true
i += 1
if i == j
break
end
u = reverse_bits(B.chunks[i])
B.chunks[i] = 0
B.chunks[j] |= u >>> h
B.chunks[i] |= v >>> h

for i = 1:hnc
j = ((i - 1) << 6)
aux_chunks[1] = reverse_bits(B.chunks[i])
copy_chunks!(B.chunks, j+1, B.chunks, n-63-j, 64)
B.chunks[i] = reverse_bits(B.chunks[i])
copy_chunks!(B.chunks, n-63-j, aux_chunks, 1, 64)
j -= 1
if i == j
break
end
v = reverse_bits(B.chunks[j])
B.chunks[j] = 0
B.chunks[i] |= v << k
B.chunks[j] |= u << k
end

pnc == 0 && return B

i = hnc + 1
j = hnc << 6
l = _mod64(n+63) + 1

aux_chunks[1] = reverse_bits(B.chunks[i] & _msk_end(l))
aux_chunks[1] >>>= (64 - l)
copy_chunks!(B.chunks, j+1, aux_chunks, 1, l)
if isodd(length(B.chunks))
B.chunks[i] |= v >>> h
else
B.chunks[i] |= u << k
end

return B
end
Expand Down

0 comments on commit 2533771

Please sign in to comment.