-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sort for NTuples #54494
Add sort for NTuples #54494
Changes from 3 commits
d4e955c
dae5920
88ef163
60dcc0e
cfe4fc7
2a84ece
92e4311
c7acc41
24d0944
49e3ec7
5001cf9
9f2c4eb
b89f6ca
4859770
92b5828
9fbb636
6b61f96
27b3ce4
b15776f
a584a99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ module Sort | |
|
||
using Base.Order | ||
|
||
using Base: copymutable, midpoint, require_one_based_indexing, uinttype, | ||
using Base: copymutable, midpoint, require_one_based_indexing, uinttype, tail, | ||
sub_with_overflow, add_with_overflow, OneTo, BitSigned, BitIntegerType, top_set_bit | ||
|
||
import Base: | ||
|
@@ -1475,21 +1475,16 @@ InitialOptimizations(next) = SubArrayOptimization( | |
Small{10}( | ||
IEEEFloatOptimization( | ||
next))))) | ||
""" | ||
DEFAULT_STABLE | ||
|
||
The default sorting algorithm. | ||
|
||
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare | ||
equal). It makes an effort to be fast for most inputs. | ||
|
||
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See extended help | ||
for the current dispatch system. | ||
""" | ||
struct DefaultStable <: Algorithm end | ||
|
||
# Extended Help | ||
`DefaultStable` is an algorithm which indicates that a fast, general purpose sorting | ||
algorithm should be used, but does not specify exactly which algorithm. | ||
|
||
`DEFAULT_STABLE` is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid | ||
of Radix, Insertion, Counting, Quick sorts. | ||
Currently, when sorting short NTuples, this is an unrolled mergesort, and otherwise it is | ||
composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid of Radix, Insertion, | ||
Counting, Quick sorts. | ||
|
||
We begin with MissingOptimization because it has no runtime cost when it is not | ||
triggered and can enable other optimizations to be applied later. For example, | ||
|
@@ -1549,7 +1544,39 @@ stage. | |
Finally, if the input has length less than 80, we dispatch to [`InsertionSort`](@ref) and | ||
otherwise we dispatch to [`ScratchQuickSort`](@ref). | ||
""" | ||
const DEFAULT_STABLE = InitialOptimizations( | ||
struct DefaultStable <: Algorithm end | ||
|
||
""" | ||
DEFAULT_STABLE | ||
|
||
The default sorting algorithm. | ||
|
||
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare | ||
equal). It makes an effort to be fast for most inputs. | ||
|
||
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See the extended help | ||
of `Base.Sort.DefaultStable` for the current dispatch system. | ||
""" | ||
const DEFAULT_STABLE = DefaultStable() | ||
|
||
""" | ||
DefaultUnstable <: Algorithm | ||
|
||
Like [`DefaultStable`](@ref), but does not guarantee stability. | ||
""" | ||
struct DefaultUnstable <: Algorithm end | ||
|
||
""" | ||
DEFAULT_UNSTABLE | ||
|
||
An efficient sorting algorithm which may or may not be stable. | ||
|
||
The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently | ||
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future. | ||
""" | ||
const DEFAULT_UNSTABLE = DefaultUnstable() | ||
|
||
const _DEFAULT_ALGORITHMS_FOR_VECTORS = InitialOptimizations( | ||
IsUIntMappable( | ||
Small{40}( | ||
CheckSorted( | ||
|
@@ -1560,15 +1587,10 @@ const DEFAULT_STABLE = InitialOptimizations( | |
ScratchQuickSort())))))), | ||
StableCheckSorted( | ||
ScratchQuickSort()))) | ||
""" | ||
DEFAULT_UNSTABLE | ||
|
||
An efficient sorting algorithm. | ||
_sort!(v::AbstractVector, ::Union{DefaultStable, DefaultUnstable}, o::Ordering, kw) = | ||
_sort!(v, _DEFAULT_ALGORITHMS_FOR_VECTORS, o, kw) | ||
|
||
The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently | ||
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future. | ||
""" | ||
const DEFAULT_UNSTABLE = DEFAULT_STABLE | ||
const SMALL_THRESHOLD = 20 | ||
|
||
function Base.show(io::IO, alg::Algorithm) | ||
|
@@ -1598,6 +1620,7 @@ defalg(v::AbstractArray) = DEFAULT_STABLE | |
defalg(v::AbstractArray{<:Union{Number, Missing}}) = DEFAULT_UNSTABLE | ||
defalg(v::AbstractArray{Missing}) = DEFAULT_UNSTABLE # for method disambiguation | ||
defalg(v::AbstractArray{Union{}}) = DEFAULT_UNSTABLE # for method disambiguation | ||
defalg(v::NTuple) = DEFAULT_STABLE | ||
|
||
""" | ||
sort!(v; alg::Base.Sort.Algorithm=Base.Sort.defalg(v), lt=isless, by=identity, rev::Bool=false, order::Base.Order.Ordering=Base.Order.Forward) | ||
|
@@ -1736,6 +1759,37 @@ julia> v | |
""" | ||
sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...) | ||
|
||
function sort(x::NTuple{N,T}; | ||
alg::Algorithm=defalg(x), | ||
lt=isless, | ||
by=identity, | ||
rev::Union{Bool,Nothing}=nothing, | ||
order::Ordering=Forward, | ||
scratch::Union{Vector{T}, Nothing}=nothing) where {N,T} | ||
_sort(x, alg, ord(lt,by,rev,order), (;scratch)) | ||
end | ||
# Folks who want to hack internals can define a new _sort(x::NTuple, ::TheirAlg, o::Ordering) | ||
# or _sort(x::NTuple{N, TheirType}, ::DefaultStable, o::Ordering) where N | ||
function _sort(x::NTuple, a::Union{DefaultStable, DefaultUnstable}, o::Ordering, kw) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "hack internals" sounds like it shouldn't be public? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lilith mentioned earlier that a motivation for the design was allowing people to dispatch on the eltype and algorithm. I guess they changed their mind given the comment, but I still think it'd be nice if things like this were made to be dispatchable API when possible. It's a very annoying downside of kwargs in public APIs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
if length(x) > 9 | ||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
v = copymutable(x) | ||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_sort!(v, a, o, kw) | ||
typeof(x)(v) | ||
else | ||
_mergesort(x, o) | ||
end | ||
end | ||
_mergesort(x::Union{NTuple{0}, NTuple{1}}, o::Ordering) = x | ||
function _mergesort(x::NTuple, o::Ordering) | ||
a, b = Base.IteratorsMD.split(x, Val(length(x)>>1)) | ||
merge(_mergesort(a, o), _mergesort(b, o), o) | ||
end | ||
merge(x::NTuple, y::NTuple{0}, o::Ordering) = x | ||
merge(x::NTuple{0}, y::NTuple, o::Ordering) = y | ||
merge(x::NTuple{0}, y::NTuple{0}, o::Ordering) = x # Method ambiguity | ||
merge(x::NTuple, y::NTuple, o::Ordering) = | ||
(lt(o, y[1], x[1]) ? (y[1], merge(x, tail(y), o)...) : (x[1], merge(tail(x), y, o)...)) | ||
|
||
## partialsortperm: the permutation to sort the first k elements of an array ## | ||
|
||
""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a compat notice indicating what versions of Julia support
NTuple
sorting?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, though it should live in
?sort
, not?Base.Sort.DEFAULT_STABLE