Skip to content

Commit 40f3a5c

Browse files
committed
add experimental mutablentuple type, improve isperm
1 parent 72c052f commit 40f3a5c

File tree

1 file changed

+55
-8
lines changed

1 file changed

+55
-8
lines changed

src/TupleTools.jl

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ Base.@pure Base.:+(::StaticLength{N₁}, ::StaticLength{N₂}) where {N₁,N₂}
2727
Base.@pure Base.:-(::StaticLength{N₁}, ::StaticLength{N₂}) where {N₁,N₂} = StaticLength(max(0,N₁-N₂))
2828

2929
@inline Base.ntuple(f, ::StaticLength{N}) where {N} = ntuple(f, Val{N}())
30+
31+
mutable struct MutableNTuple{N,T}
32+
data::NTuple{N,T}
33+
function MutableNTuple(data::NTuple{N,T}) where {N,T}
34+
@assert isbitstype(T)
35+
return new{N,T}(data)
36+
end
37+
end
38+
39+
Base.@propagate_inbounds function Base.getindex(t::MutableNTuple{N,T}, i::Int) where {N,T}
40+
@boundscheck checkbounds(Base.OneTo(N),i)
41+
GC.@preserve t unsafe_load(Base.unsafe_convert(Ptr{T}, pointer_from_objref(t)), i)
42+
end
43+
44+
Base.@propagate_inbounds function Base.setindex!(t::MutableNTuple{N,T}, val, i::Int) where {N,T}
45+
@boundscheck checkbounds(Base.OneTo(N),i)
46+
GC.@preserve t unsafe_store!(Base.unsafe_convert(Ptr{T}, pointer_from_objref(t)), convert(T, val), i)
47+
return t
48+
end
49+
50+
@inline Base.Tuple(t::MutableNTuple) = t.data
51+
3052
@inline argtail2(a, b, c...) = c
3153

3254
"""
@@ -130,7 +152,7 @@ Returns the sum of the element of a tuple, or `0` for an empty tuple.
130152
"""
131153
sum(t::Tuple{}) = 0
132154
sum(t::Tuple{Any}) = t[1]
133-
sum(t::Tuple) = t[1]+sum(tail(t))
155+
sum(t::Tuple) = t[1] + sum(tail(t))
134156

135157
"""
136158
cumsum(t::Tuple)
@@ -151,7 +173,7 @@ Returns the product of the elements of a tuple, or `1` for an empty tuple.
151173
"""
152174
prod(t::Tuple{}) = 1
153175
prod(t::Tuple{Any}) = t[1]
154-
prod(t::Tuple) = t[1]*prod(tail(t))
176+
prod(t::Tuple) = t[1] * prod(tail(t))
155177

156178
"""
157179
cumprod(t::Tuple)
@@ -284,16 +306,41 @@ _permute(t::NTuple{N,Any}, p) where {N} = ntuple(n->t[p[n]], StaticLength(N))
284306
285307
A non-allocating alternative to Base.isperm(p) that is much faster for small permutations.
286308
"""
287-
function isperm(p)
288-
N = length(p)
289-
@inbounds for i = 1:N
290-
1 <= p[i] <= N || return false
291-
for j = i+1:N
292-
p[i] == p[j] && return false
309+
function isperm(p::NTuple{N,Integer}) where N
310+
used = MutableNTuple(ntuple(n->false, Val(N)))
311+
@inbounds for i in p
312+
if 0 < i <= N && used[i] == false
313+
used[i] = true
314+
else
315+
return false
293316
end
294317
end
295318
return true
296319
end
320+
isperm(p::Tuple{}) = true
321+
isperm(p::Tuple{Int}) = p[1] == 1
322+
isperm(p::Tuple{Int,Int}) = ((p[1] == 1) & (p[2] == 2)) | ((p[1] == 2) & (p[2] == 1))
323+
function isperm(p::Tuple{Int,Int,Int})
324+
return !(p[1] < 1 || p[1] > 3 || p[2] < 1 || p[2] > 3 || p[3] < 1 || p[3] > 3 ||
325+
p[1] == p[2] || p[1] == p[3] || p[2] == p[3])
326+
end
327+
function isperm(p::Tuple{Int,Int,Int,Int})
328+
return !(p[1] < 1 || p[1] > 4 || p[2] < 1 || p[2] > 4 ||
329+
p[3] < 1 || p[3] > 4 || p[4] < 1 || p[4] > 4 ||
330+
p[1] == p[2] || p[1] == p[3] || p[1] == p[4] ||
331+
p[2] == p[3] || p[2] == p[4] || p[3] == p[4])
332+
end
333+
334+
# function isperm(p)
335+
# N = length(p)
336+
# @inbounds for i = 1:N
337+
# 1 <= p[i] <= N || return false
338+
# for j = i+1:N
339+
# p[i] == p[j] && return false
340+
# end
341+
# end
342+
# return true
343+
# end
297344

298345
"""
299346
invperm(p::NTuple{N,Int}) -> ::NTuple{N,Int}

0 commit comments

Comments
 (0)