Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
232
julia-0.6.2/share/julia/base/intset.jl
Normal file
232
julia-0.6.2/share/julia/base/intset.jl
Normal file
@@ -0,0 +1,232 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
struct IntSet <: AbstractSet{Int}
|
||||
bits::BitVector
|
||||
IntSet() = new(falses(256))
|
||||
end
|
||||
IntSet(itr) = union!(IntSet(), itr)
|
||||
|
||||
eltype(::Type{IntSet}) = Int
|
||||
similar(s::IntSet) = IntSet()
|
||||
copy(s1::IntSet) = copy!(IntSet(), s1)
|
||||
function copy!(dest::IntSet, src::IntSet)
|
||||
resize!(dest.bits, length(src.bits))
|
||||
copy!(dest.bits, src.bits)
|
||||
dest
|
||||
end
|
||||
eltype(s::IntSet) = Int
|
||||
sizehint!(s::IntSet, n::Integer) = (_resize0!(s.bits, max(n, length(s.bits))); s)
|
||||
|
||||
# An internal function for setting the inclusion bit for a given integer n >= 0
|
||||
@inline function _setint!(s::IntSet, idx::Integer, b::Bool)
|
||||
if idx > length(s.bits)
|
||||
b || return s # setting a bit to zero outside the set's bits is a no-op
|
||||
newlen = Int(idx) + Int(idx)>>1 # This operation may overflow; we want saturation
|
||||
_resize0!(s.bits, ifelse(newlen<0, typemax(Int), newlen))
|
||||
end
|
||||
@inbounds s.bits[idx] = b
|
||||
s
|
||||
end
|
||||
|
||||
# An internal function to resize a bitarray and ensure the newly allocated
|
||||
# elements are zeroed (will become unnecessary if this behavior changes)
|
||||
@inline function _resize0!(b::BitVector, newlen::Integer)
|
||||
len = length(b)
|
||||
resize!(b, newlen)
|
||||
len < newlen && @inbounds b[len+1:newlen] = false # resize! gives dirty memory
|
||||
b
|
||||
end
|
||||
|
||||
# An internal function that takes a pure function `f` and maps across two BitArrays
|
||||
# allowing the lengths to be different and altering b1 with the result
|
||||
function _matched_map!(f, b1::BitArray, b2::BitArray)
|
||||
l1, l2 = length(b1), length(b2)
|
||||
if l1 == l2
|
||||
map!(f, b1, b1, b2)
|
||||
elseif l1 < l2
|
||||
_resize0!(b1, l2)
|
||||
map!(f, b1, b1, b2)
|
||||
elseif l1 > l2
|
||||
if f(false, false) == f(true, false) == false
|
||||
# We don't need to worry about the trailing bits — they're all false
|
||||
resize!(b1, l2)
|
||||
map!(f, b1, b1, b2)
|
||||
else
|
||||
# We transiently extend b2 — as IntSet internal storage this is unobservable
|
||||
_resize0!(b2, l1)
|
||||
map!(f, b1, b1, b2)
|
||||
resize!(b2, l2)
|
||||
end
|
||||
end
|
||||
b1
|
||||
end
|
||||
|
||||
@noinline _throw_intset_bounds_err() = throw(ArgumentError("elements of IntSet must be between 1 and typemax(Int)"))
|
||||
@noinline _throw_keyerror(n) = throw(KeyError(n))
|
||||
|
||||
@inline function push!(s::IntSet, n::Integer)
|
||||
0 < n <= typemax(Int) || _throw_intset_bounds_err()
|
||||
_setint!(s, n, true)
|
||||
end
|
||||
push!(s::IntSet, ns::Integer...) = (for n in ns; push!(s, n); end; s)
|
||||
|
||||
@inline function pop!(s::IntSet)
|
||||
pop!(s, last(s))
|
||||
end
|
||||
@inline function pop!(s::IntSet, n::Integer)
|
||||
n in s ? (_delete!(s, n); n) : _throw_keyerror(n)
|
||||
end
|
||||
@inline function pop!(s::IntSet, n::Integer, default)
|
||||
n in s ? (_delete!(s, n); n) : default
|
||||
end
|
||||
@inline _delete!(s::IntSet, n::Integer) = _setint!(s, n, false)
|
||||
@inline delete!(s::IntSet, n::Integer) = n < 0 ? s : _delete!(s, n)
|
||||
shift!(s::IntSet) = pop!(s, first(s))
|
||||
|
||||
empty!(s::IntSet) = (fill!(s.bits, false); s)
|
||||
isempty(s::IntSet) = !any(s.bits)
|
||||
|
||||
# Mathematical set functions: union!, intersect!, setdiff!, symdiff!
|
||||
|
||||
union(s::IntSet) = copy(s)
|
||||
union(s1::IntSet, s2::IntSet) = union!(copy(s1), s2)
|
||||
union(s1::IntSet, ss::IntSet...) = union(s1, union(ss...))
|
||||
union(s::IntSet, ns) = union!(copy(s), ns)
|
||||
union!(s::IntSet, ns) = (for n in ns; push!(s, n); end; s)
|
||||
function union!(s1::IntSet, s2::IntSet)
|
||||
_matched_map!(|, s1.bits, s2.bits)
|
||||
s1
|
||||
end
|
||||
|
||||
intersect(s1::IntSet) = copy(s1)
|
||||
intersect(s1::IntSet, ss::IntSet...) = intersect(s1, intersect(ss...))
|
||||
function intersect(s1::IntSet, ns)
|
||||
s = IntSet()
|
||||
for n in ns
|
||||
n in s1 && push!(s, n)
|
||||
end
|
||||
s
|
||||
end
|
||||
intersect(s1::IntSet, s2::IntSet) =
|
||||
(length(s1.bits) >= length(s2.bits) ? intersect!(copy(s1), s2) : intersect!(copy(s2), s1))
|
||||
"""
|
||||
intersect!(s1::IntSet, s2::IntSet)
|
||||
|
||||
Intersects sets `s1` and `s2` and overwrites the set `s1` with the result. If needed, `s1`
|
||||
will be expanded to the size of `s2`.
|
||||
"""
|
||||
function intersect!(s1::IntSet, s2::IntSet)
|
||||
_matched_map!(&, s1.bits, s2.bits)
|
||||
s1
|
||||
end
|
||||
|
||||
setdiff(s::IntSet, ns) = setdiff!(copy(s), ns)
|
||||
setdiff!(s::IntSet, ns) = (for n in ns; _delete!(s, n); end; s)
|
||||
function setdiff!(s1::IntSet, s2::IntSet)
|
||||
_matched_map!(>, s1.bits, s2.bits)
|
||||
s1
|
||||
end
|
||||
|
||||
symdiff(s::IntSet, ns) = symdiff!(copy(s), ns)
|
||||
"""
|
||||
symdiff!(s, itr)
|
||||
|
||||
For each element in `itr`, destructively toggle its inclusion in set `s`.
|
||||
"""
|
||||
symdiff!(s::IntSet, ns) = (for n in ns; symdiff!(s, n); end; s)
|
||||
"""
|
||||
symdiff!(s, n)
|
||||
|
||||
The set `s` is destructively modified to toggle the inclusion of integer `n`.
|
||||
"""
|
||||
function symdiff!(s::IntSet, n::Integer)
|
||||
0 < n < typemax(Int) || _throw_intset_bounds_err()
|
||||
val = !(n in s)
|
||||
_setint!(s, n, val)
|
||||
s
|
||||
end
|
||||
function symdiff!(s1::IntSet, s2::IntSet)
|
||||
_matched_map!(xor, s1.bits, s2.bits)
|
||||
s1
|
||||
end
|
||||
|
||||
@inline function in(n::Integer, s::IntSet)
|
||||
if 1 <= n <= length(s.bits)
|
||||
@inbounds b = s.bits[n]
|
||||
else
|
||||
b = false
|
||||
end
|
||||
b
|
||||
end
|
||||
|
||||
# Use the next-set index as the state to prevent looking it up again in done
|
||||
start(s::IntSet) = next(s, 0)[2]
|
||||
function next(s::IntSet, i)
|
||||
nextidx = i == typemax(Int) ? 0 : findnext(s.bits, i+1)
|
||||
(i, nextidx)
|
||||
end
|
||||
done(s::IntSet, i) = i <= 0
|
||||
|
||||
|
||||
@noinline _throw_intset_notempty_error() = throw(ArgumentError("collection must be non-empty"))
|
||||
function last(s::IntSet)
|
||||
idx = findprev(s.bits, length(s.bits))
|
||||
idx == 0 ? _throw_intset_notempty_error() : idx
|
||||
end
|
||||
|
||||
length(s::IntSet) = sum(s.bits)
|
||||
|
||||
function show(io::IO, s::IntSet)
|
||||
print(io, "IntSet([")
|
||||
first = true
|
||||
for n in s
|
||||
!first && print(io, ", ")
|
||||
print(io, n)
|
||||
first = false
|
||||
end
|
||||
print(io, "])")
|
||||
end
|
||||
|
||||
function ==(s1::IntSet, s2::IntSet)
|
||||
l1 = length(s1.bits)
|
||||
l2 = length(s2.bits)
|
||||
# If the lengths are the same, simply punt to bitarray comparison
|
||||
l1 == l2 && return s1.bits == s2.bits
|
||||
|
||||
# Swap so s1 is always longer
|
||||
if l1 < l2
|
||||
s2, s1 = s1, s2
|
||||
l2, l1 = l1, l2
|
||||
end
|
||||
# Iteratively check the chunks of the bitarrays
|
||||
c1 = s1.bits.chunks
|
||||
c2 = s2.bits.chunks
|
||||
@inbounds for i in 1:length(c2)
|
||||
c1[i] == c2[i] || return false
|
||||
end
|
||||
# Ensure remaining chunks are zero
|
||||
@inbounds for i in length(c2)+1:length(c1)
|
||||
c1[i] == UInt64(0) || return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
issubset(a::IntSet, b::IntSet) = isequal(a, intersect(a,b))
|
||||
<(a::IntSet, b::IntSet) = (a<=b) && !isequal(a,b)
|
||||
<=(a::IntSet, b::IntSet) = issubset(a, b)
|
||||
|
||||
const hashis_seed = UInt === UInt64 ? 0x88989f1fc7dea67d : 0xc7dea67d
|
||||
function hash(s::IntSet, h::UInt)
|
||||
h ⊻= hashis_seed
|
||||
bc = s.bits.chunks
|
||||
i = length(bc)
|
||||
while i > 0 && bc[i] == UInt64(0)
|
||||
# Skip trailing empty bytes to prevent extra space from changing the hash
|
||||
i -= 1
|
||||
end
|
||||
while i > 0
|
||||
h = hash(bc[i], h)
|
||||
i -= 1
|
||||
end
|
||||
h
|
||||
end
|
||||
Reference in New Issue
Block a user