diff --git a/Project.toml b/Project.toml index 96ae2400a..b10bf9e03 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Compat" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.12.0" +version = "4.13.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/README.md b/README.md index 59b485359..1d645983d 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ changes in `julia`. ## Supported features +* `allequal(f, itr)` and `allunique(f, itr)` methods. ([#47679]) (since Compat 4.13.0) + * `Iterators.cycle(itr, n)` is the lazy version of `repeat(vector, n)`. ([#47354]) (since Compat 4.13.0) * `@compat public foo, bar` marks `foo` and `bar` as public in Julia 1.11+ and is a no-op in Julia 1.10 and earlier. ([#50105]) (since Compat 3.47.0, 4.10.0) @@ -181,3 +183,4 @@ Note that you should specify the correct minimum version for `Compat` in the [#47354]: https://github.com/JuliaLang/julia/issues/47354 [#48038]: https://github.com/JuliaLang/julia/issues/48038 [#50105]: https://github.com/JuliaLang/julia/issues/50105 +[#47679]: https://github.com/JuliaLang/julia/pull/47679 diff --git a/src/Compat.jl b/src/Compat.jl index 079c250ac..2b1eae369 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -330,6 +330,8 @@ if VERSION < v"1.8.0-DEV.1494" # 98e60ffb11ee431e462b092b48a31a1204bd263d allequal(itr) = isempty(itr) ? true : all(isequal(first(itr)), itr) allequal(c::Union{AbstractSet,AbstractDict}) = length(c) <= 1 allequal(r::AbstractRange) = iszero(step(r)) || length(r) <= 1 +else + import Base: allequal # extended below end # https://github.com/JuliaLang/julia/commit/bdf9ead91e5a8dfd91643a17c1626032faada329 @@ -770,6 +772,27 @@ if VERSION < v"1.7.0-DEV.1187" export redirect_stdio end +# https://github.com/JuliaLang/julia/pull/47679 +if VERSION < v"1.11.0-DEV.1562" + Base.allunique(f, xs) = allunique(Base.Generator(f, xs)) + function Base.allunique(f::F, t::Tuple) where {F} + length(t) < 2 && return true + length(t) < 32 || return Base._hashed_allunique(Base.Generator(f, t)) + return allunique(map(f, t)) + end + + # allequal is either imported or defined above + allequal(f, xs) = allequal(Base.Generator(f, xs)) + function allequal(f, xs::Tuple) + length(xs) <= 1 && return true + f1 = f(xs[1]) + for x in Base.tail(xs) + isequal(f1, f(x)) || return false + end + return true + end +end + # https://github.com/JuliaLang/julia/pull/45052 if VERSION < v"1.9.0-DEV.461" Base.VersionNumber(v::VersionNumber) = v diff --git a/test/runtests.jl b/test/runtests.jl index b2c259513..35631190e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -729,6 +729,34 @@ end @test_throws LoadError @eval @compat publac @bar, foo end +# https://github.com/JuliaLang/julia/pull/47679 +@testset "allunique(f, xs)" begin + @test allunique(sin, 1:3) + @test !allunique(sin, [1,2,3,1]) + @test allunique(sin, (1, 2, pi, im)) # eltype Any + @test allunique(abs2, 1:100) + @test !allunique(abs, -10:10) + @test allunique(abs2, Vector{Any}(1:100)) + # These cases don't call the function at all: + @test allunique(error, []) + @test_skip allunique(error, [1]) # depends on updated code in Base to work +end +@testset "allequal(f, xs)" begin + @test allequal(abs2, [3, -3]) + @test allequal(x -> 1, rand(3)) + @test !allequal(x -> rand(), [1,1,1]) + # tuples + @test allequal(abs2, (3, -3)) + @test allequal(x -> 1, Tuple(rand(3))) + @test !allequal(x -> rand(), (1,1,1)) + # These cases don't call the function at all: + @test allequal(error, []) + @test allequal(error, ()) + @test allequal(error, (x for x in 1:3 if false)) + @test_skip allequal(error, [1]) # fixed not by new code but by upgrades to old code + @test allequal(error, (1,)) +end + # https://github.com/JuliaLang/julia/pull/45052 @testset "VersionNumber no-op constructor" begin v = VersionNumber("1.2.3")