diff --git a/Project.toml b/Project.toml index 340e6788d..845596f96 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Compat" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.8.0" +version = "4.9.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/README.md b/README.md index ec4545f77..8ffb9d174 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ changes in `julia`. ## Supported features +* `sort` for `NTuple` and other iterables. ([#46104]) (since Compat 4.9.0) + * `redirect_stdio`, for simple stream redirection. ([#37978]) (since Compat 4.8.0) * `trunc`, `floor`, `ceil`, and `round` to `Bool`. ([#25085]) (since Compat 4.7.0) @@ -168,4 +170,5 @@ Note that you should specify the correct minimum version for `Compat` in the [#43334]: https://github.com/JuliaLang/julia/issues/43334 [#43354]: https://github.com/JuliaLang/julia/issues/43354 [#43852]: https://github.com/JuliaLang/julia/issues/43852 +[#46104]: https://github.com/JuliaLang/julia/issues/46104 [#48038]: https://github.com/JuliaLang/julia/issues/48038 diff --git a/src/Compat.jl b/src/Compat.jl index b20a8ec4b..8bc244917 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -643,11 +643,10 @@ end # https://github.com/JuliaLang/julia/pull/25085 if VERSION < v"1.8.0-beta2.17" || v"1.9.0-" <= VERSION < v"1.9.0-DEV.94" - import Base: trunc, floor, ceil, round - trunc(::Type{Bool}, x::AbstractFloat) = (-1 < x < 2) ? 1 <= x : throw(InexactError(:trunc, Bool, x)) - floor(::Type{Bool}, x::AbstractFloat) = (0 <= x < 2) ? 1 <= x : throw(InexactError(:floor, Bool, x)) - ceil(::Type{Bool}, x::AbstractFloat) = (-1 < x <= 1) ? 0 < x : throw(InexactError(:ceil, Bool, x)) - round(::Type{Bool}, x::AbstractFloat) = (-0.5 <= x < 1.5) ? 0.5 < x : throw(InexactError(:round, Bool, x)) + Base.trunc(::Type{Bool}, x::AbstractFloat) = (-1 < x < 2) ? 1 <= x : throw(InexactError(:trunc, Bool, x)) + Base.floor(::Type{Bool}, x::AbstractFloat) = (0 <= x < 2) ? 1 <= x : throw(InexactError(:floor, Bool, x)) + Base.ceil(::Type{Bool}, x::AbstractFloat) = (-1 < x <= 1) ? 0 < x : throw(InexactError(:ceil, Bool, x)) + Base.round(::Type{Bool}, x::AbstractFloat) = (-0.5 <= x < 1.5) ? 0.5 < x : throw(InexactError(:round, Bool, x)) end # https://github.com/JuliaLang/julia/pull/37978 @@ -706,6 +705,42 @@ if VERSION < v"1.7.0-DEV.1187" export redirect_stdio end +# https://github.com/JuliaLang/julia/pull/46104 +if VERSION < v"1.10.0-DEV.1404" + using Base: Ordering, Forward, ord, lt, tail, copymutable, DEFAULT_STABLE, IteratorSize, HasShape, IsInfinite + function Base.sort(v; kws...) + size = IteratorSize(v) + size == HasShape{0}() && throw(ArgumentError("$v cannot be sorted")) + size == IsInfinite() && throw(ArgumentError("infinite iterator $v cannot be sorted")) + sort!(copymutable(v); kws...) + end + Base.sort(::AbstractString; kws...) = + throw(ArgumentError("sort(::AbstractString) is not supported")) + Base.sort(::Tuple; kws...) = + throw(ArgumentError("sort(::Tuple) is only supported for NTuples")) + + function Base.sort(x::NTuple{N}; lt::Function=isless, by::Function=identity, + rev::Union{Bool,Nothing}=nothing, order::Ordering=Forward) where N + o = ord(lt,by,rev,order) + if N > 9 + v = sort!(copymutable(x), DEFAULT_STABLE, o) + tuple((v[i] for i in 1:N)...) + else + _sort(x, o) + end + end + _sort(x::Union{NTuple{0}, NTuple{1}}, o::Ordering) = x + function _sort(x::NTuple, o::Ordering) + a, b = Base.IteratorsMD.split(x, Val(length(x)>>1)) + merge(_sort(a, o), _sort(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)...)) +end + include("deprecated.jl") end # module Compat diff --git a/test/runtests.jl b/test/runtests.jl index b9da5d945..7c74c8976 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -691,3 +691,36 @@ end @test read(path_stdout, String) == content_stdout end end + +# https://github.com/JuliaLang/julia/pull/46104 +@testset "sort(iterable)" begin + function tuple_sort_test(x) + @test issorted(sort(x)) + length(x) > 9 && return # length > 9 uses a vector fallback + @test 0 == @allocated sort(x) + end + @testset "sort(::NTuple)" begin + @test sort((9,8,3,3,6,2,0,8)) == (0,2,3,3,6,8,8,9) + @test sort((9,8,3,3,6,2,0,8), by=x->x÷3) == (2,0,3,3,8,6,8,9) + for i in 1:40 + tuple_sort_test(tuple(rand(i)...)) + end + @test_throws ArgumentError sort((1,2,3.0)) + end + @testset "sort!(iterable)" begin + gen = (x % 7 + 0.1x for x in 1:50) + @test sort(gen) == sort!(collect(gen)) + gen = (x % 7 + 0.1y for x in 1:10, y in 1:5) + @test sort(gen; dims=1) == sort!(collect(gen); dims=1) + @test sort(gen; dims=2) == sort!(collect(gen); dims=2) + + @test_throws ArgumentError("dimension out of range") sort(gen; dims=3) + + @test_throws UndefKeywordError(:dims) sort(gen) + @test_throws UndefKeywordError(:dims) sort(collect(gen)) + @test_throws UndefKeywordError(:dims) sort!(collect(gen)) + + @test_throws ArgumentError sort("string") + @test_throws ArgumentError("1 cannot be sorted") sort(1) + end +end