diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index a09aa2f..d6f622d 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -22,12 +22,3 @@ jobs: tests: uses: "SciML/.github/.github/workflows/grouped-tests.yml@v1" secrets: "inherit" - tests-32bit: - name: "Core (julia 1, ubuntu-latest, x86)" - uses: "SciML/.github/.github/workflows/tests.yml@v1" - with: - julia-version: "1" - julia-arch: "x86" - group: "Core" - coverage: false - secrets: "inherit" diff --git a/Project.toml b/Project.toml index 503e897..acc1fb4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FindFirstFunctions" uuid = "64ca27bc-2ba2-4a57-88aa-44e436879224" -version = "3.0.3" +version = "3.1.0" authors = ["Chris Elrod and contributors"] [deps] @@ -9,7 +9,7 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" [compat] PrecompileTools = "1.0.1" SafeTestsets = "0.1" -SciMLTesting = "1" +SciMLTesting = "2.2" StableRNGs = "1" Test = "1.10" julia = "1.10" diff --git a/src/equality.jl b/src/equality.jl index 89099dc..a178a6a 100644 --- a/src/equality.jl +++ b/src/equality.jl @@ -36,7 +36,10 @@ Find the index of the first occurrence of `var` in the sorted vector `DenseVector{Int64}` via a branchless binary bisection down to a small basecase, followed by the same SIMD equality scan that backs [`findfirstequal`](@ref) — faster than plain `findfirst(==(var), vars)` -or `searchsortedfirst` + post-check for typical Int64 vectors. +or `searchsortedfirst` + post-check for typical Int64 vectors. Every +other element-type and array-storage combination (including native `Int` +on 32-bit platforms, where `Int` is not `Int64`) falls back to a generic +`searchsortedfirst` + equality post-check. The strategy-framework equivalent is [`findequal(BisectThenSIMD(), vars, var)`](@ref findequal); that wrapper @@ -45,6 +48,10 @@ which is type-stable and composes with the rest of the strategy dispatch. Prefer `findequal` for new code; `findfirstsortedequal` remains as the dedicated `Union{Int64, Nothing}`-returning name. """ +function findfirstsortedequal(var, vars) + i = searchsortedfirst(vars, var) + return (i <= lastindex(vars) && isequal(@inbounds(vars[i]), var)) ? i : nothing +end function findfirstsortedequal( var::Int64, vars::DenseVector{Int64}, diff --git a/test/core_tests.jl b/test/core_tests.jl index 702a2b1..3366964 100644 --- a/test/core_tests.jl +++ b/test/core_tests.jl @@ -1377,3 +1377,24 @@ end end end end + +@safetestset "findfirstsortedequal generic fallback" begin + using FindFirstFunctions, StableRNGs + F = FindFirstFunctions + + # The `(Int64, DenseVector{Int64})` method is the SIMD fast path; every + # other type (e.g. `Int32`, which is the native `Int` on 32-bit platforms) + # takes the generic searchsortedfirst fallback. Exercise it explicitly here + # so both paths are covered regardless of the host word size. + rng = StableRNG(2029) + for T in (Int32, Int16, Float32), _ in 1:500 + n = rand(rng, 0:64) + v = sort!(rand(rng, T(-40):T(40), n)) + for i in eachindex(v) + @test F.findfirstsortedequal(v[i], v) == searchsortedfirst(v, v[i]) + end + x = rand(rng, T(-50):T(50)) + ref = insorted(x, v) ? searchsortedfirst(v, x) : nothing + @test F.findfirstsortedequal(x, v) == ref + end +end diff --git a/test/test_groups.toml b/test/test_groups.toml index 238e907..09a4f24 100644 --- a/test/test_groups.toml +++ b/test/test_groups.toml @@ -6,5 +6,15 @@ versions = ["1", "lts", "pre"] os = ["ubuntu-latest", "macos-latest", "windows-latest"] +# 32-bit lane: a matrix-only alias that dispatches the Core body (GROUP=Core) on +# a single x86 Julia, so the WORD_SIZE != 64 scalar fallbacks in src/simd_ir.jl +# are exercised in CI. The `arch = "x86"` cell needs SciML/.github v1's i386-libs +# step (setup-julia) and the alias skip in SciMLTesting >= 2.2 (folder discovery). +["Core 32-bit"] +group = "Core" +versions = ["1"] +os = ["ubuntu-latest"] +arch = "x86" + [QA] versions = ["lts", "1"]