Skip to content

Commit 6bd7486

Browse files
ChrisRackauckas-ClaudeChrisRackauckasclaude
authored
Add generic findfirstsortedequal fallback (fixes 32-bit) and drop the broken 32-bit CI job (#97)
Follow-up to #95. Two things: 1. Fix a correctness gap #95 shipped. Unlike `findfirstequal`, `findfirstsortedequal` had ONLY the `(Int64, DenseVector{Int64})` method and no generic fallback. On 32-bit platforms native `Int` is `Int32`, so `findfirstsortedequal(::Int32, ::Vector{Int32})` throws MethodError — 8385 such errors in the suite, and a bare `Pkg.test()` / any `Int`-vector caller on 32-bit is broken. Add a generic `searchsortedfirst` + equality post-check fallback (mirroring `findfirstequal`), so it works for any sorted vector on any platform. Add a test covering the fallback on Int32/Int16/Float32. 2. Remove the `tests-32bit` job #95 added to Tests.yml. Running 32-bit Julia on the 64-bit `ubuntu-latest` runner fails at `setup-julia` (the i686 binary can't exec without the 32-bit loader, which is not installed before Julia is invoked: `spawn .../x86/bin/julia ENOENT`), so that job is red regardless of this fix. A proper 32-bit CI lane needs runner/reusable-workflow changes and is deferred; Tests.yml goes back to a thin grouped-tests caller. Minor bump 3.0.3 -> 3.1.0 (new public behavior: `findfirstsortedequal` now accepts any sorted vector). Verified locally: full Core suite passes on 32-bit i686 Julia 1.11 (0 errors) and on x64 (171915 tests); GROUP=All passes. Claude-Session: https://claude.ai/code/session_01EcQkauMQ4KSytnTpJpXUZu Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 012b92c commit 6bd7486

4 files changed

Lines changed: 30 additions & 11 deletions

File tree

.github/workflows/Tests.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,3 @@ jobs:
2222
tests:
2323
uses: "SciML/.github/.github/workflows/grouped-tests.yml@v1"
2424
secrets: "inherit"
25-
tests-32bit:
26-
name: "Core (julia 1, ubuntu-latest, x86)"
27-
uses: "SciML/.github/.github/workflows/tests.yml@v1"
28-
with:
29-
julia-version: "1"
30-
julia-arch: "x86"
31-
group: "Core"
32-
coverage: false
33-
secrets: "inherit"

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "FindFirstFunctions"
22
uuid = "64ca27bc-2ba2-4a57-88aa-44e436879224"
3-
version = "3.0.3"
3+
version = "3.1.0"
44
authors = ["Chris Elrod <elrodc@gmail.com> and contributors"]
55

66
[deps]

src/equality.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ Find the index of the first occurrence of `var` in the sorted vector
3636
`DenseVector{Int64}` via a branchless binary bisection down to a small
3737
basecase, followed by the same SIMD equality scan that backs
3838
[`findfirstequal`](@ref) — faster than plain `findfirst(==(var), vars)`
39-
or `searchsortedfirst` + post-check for typical Int64 vectors.
39+
or `searchsortedfirst` + post-check for typical Int64 vectors. Every
40+
other element-type and array-storage combination (including native `Int`
41+
on 32-bit platforms, where `Int` is not `Int64`) falls back to a generic
42+
`searchsortedfirst` + equality post-check.
4043
4144
The strategy-framework equivalent is
4245
[`findequal(BisectThenSIMD(), vars, var)`](@ref findequal); that wrapper
@@ -45,6 +48,10 @@ which is type-stable and composes with the rest of the strategy
4548
dispatch. Prefer `findequal` for new code; `findfirstsortedequal` remains
4649
as the dedicated `Union{Int64, Nothing}`-returning name.
4750
"""
51+
function findfirstsortedequal(var, vars)
52+
i = searchsortedfirst(vars, var)
53+
return (i <= lastindex(vars) && isequal(@inbounds(vars[i]), var)) ? i : nothing
54+
end
4855
function findfirstsortedequal(
4956
var::Int64,
5057
vars::DenseVector{Int64},

test/core_tests.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,3 +1377,24 @@ end
13771377
end
13781378
end
13791379
end
1380+
1381+
@safetestset "findfirstsortedequal generic fallback" begin
1382+
using FindFirstFunctions, StableRNGs
1383+
F = FindFirstFunctions
1384+
1385+
# The `(Int64, DenseVector{Int64})` method is the SIMD fast path; every
1386+
# other type (e.g. `Int32`, which is the native `Int` on 32-bit platforms)
1387+
# takes the generic searchsortedfirst fallback. Exercise it explicitly here
1388+
# so both paths are covered regardless of the host word size.
1389+
rng = StableRNG(2029)
1390+
for T in (Int32, Int16, Float32), _ in 1:500
1391+
n = rand(rng, 0:64)
1392+
v = sort!(rand(rng, T(-40):T(40), n))
1393+
for i in eachindex(v)
1394+
@test F.findfirstsortedequal(v[i], v) == searchsortedfirst(v, v[i])
1395+
end
1396+
x = rand(rng, T(-50):T(50))
1397+
ref = insorted(x, v) ? searchsortedfirst(v, x) : nothing
1398+
@test F.findfirstsortedequal(x, v) == ref
1399+
end
1400+
end

0 commit comments

Comments
 (0)